Compare commits

..

45 commits
legacy ... main

Author SHA1 Message Date
Lala Sabathil
e742f21154
Merge pull request #7 from Fortunevale/dependabot/nuget/Microsoft.Extensions.Logging.Abstractions-8.0.1
Bump Microsoft.Extensions.Logging.Abstractions from 8.0.0 to 8.0.1
2024-03-13 15:07:49 +01:00
dependabot[bot]
f3d8fdfe04
Bump Microsoft.Extensions.Logging.Abstractions from 8.0.0 to 8.0.1
Bumps [Microsoft.Extensions.Logging.Abstractions](https://github.com/dotnet/runtime) from 8.0.0 to 8.0.1.
- [Release notes](https://github.com/dotnet/runtime/releases)
- [Commits](https://github.com/dotnet/runtime/compare/v8.0.0...v8.0.1)

---
updated-dependencies:
- dependency-name: Microsoft.Extensions.Logging.Abstractions
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-13 07:21:48 +00:00
Mira
ee2719ec67
chore: Update to net8 2023-11-20 09:14:59 +01:00
Mira
4d1f63fbc1
Merge pull request #6 from Fortunevale/dependabot/nuget/Microsoft.Extensions.Logging.Abstractions-8.0.0
Bump Microsoft.Extensions.Logging.Abstractions from 7.0.1 to 8.0.0
2023-11-20 09:07:26 +01:00
dependabot[bot]
f045bd7dbc
Bump Microsoft.Extensions.Logging.Abstractions from 7.0.1 to 8.0.0
Bumps [Microsoft.Extensions.Logging.Abstractions](https://github.com/dotnet/runtime) from 7.0.1 to 8.0.0.
- [Release notes](https://github.com/dotnet/runtime/releases)
- [Commits](https://github.com/dotnet/runtime/compare/v7.0.1...v8.0.0)

---
updated-dependencies:
- dependency-name: Microsoft.Extensions.Logging.Abstractions
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-20 07:29:50 +00:00
Mira
b43fd3d24b
Merge pull request #5 from Fortunevale/dependabot/nuget/Microsoft.Extensions.Logging.Abstractions-7.0.1
Bump Microsoft.Extensions.Logging.Abstractions from 7.0.0 to 7.0.1
2023-11-20 07:56:28 +01:00
Mira
f8e254440b
fix: RunAnalyzersDuringBuild to False 2023-10-03 13:44:23 +02:00
Mira
a2ed87f7ce
Update LoggerClient.cs 2023-08-23 04:26:20 +02:00
Mira
f1a061edc1
refactor: Apply .editorconfig 2023-08-06 19:14:08 +02:00
Mira
e18aa2ef51
Update LoggerClient.cs 2023-06-18 21:43:23 +02:00
Mira
40e8632a77
Update LoggerClient.cs 2023-06-18 20:43:10 +02:00
dependabot[bot]
25898aff51
Bump Microsoft.Extensions.Logging.Abstractions from 7.0.0 to 7.0.1
Bumps [Microsoft.Extensions.Logging.Abstractions](https://github.com/dotnet/runtime) from 7.0.0 to 7.0.1.
- [Release notes](https://github.com/dotnet/runtime/releases)
- [Commits](https://github.com/dotnet/runtime/compare/v7.0.0...v7.0.1)

---
updated-dependencies:
- dependency-name: Microsoft.Extensions.Logging.Abstractions
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-14 08:03:04 +00:00
Mira
7c1ff06fa5
Seal + Docs 2023-06-08 03:27:52 +02:00
Mira
332b6172ae
Target x64 2023-06-07 20:31:34 +02:00
Mira
2cb5b1a169
Refactor 2023-06-07 00:10:00 +02:00
Mira
8969bb00cc
Update Logger.cs 2023-05-31 17:09:02 +02:00
Mira
53596d9b8a
Update Logger.cs 2023-05-30 22:02:03 +02:00
Mira
a7e5672e18
Update Logger.cs 2023-05-30 21:18:04 +02:00
Mira
03355fe27b
fuck this 2023-05-26 11:09:31 +02:00
Mira
933fe1f5e9
Update Logger.cs 2023-05-26 11:05:17 +02:00
Mira
7b5dfa673a
fix nre 2023-05-26 10:57:47 +02:00
Mira
a3b7eccc3d
chore(deps): Update to .NET 7.0 2023-05-09 15:06:03 +02:00
Lala Sabathil
3bfe19dd65
Merge pull request #4 from Fortunevale/dependabot/nuget/Newtonsoft.Json-13.0.3
Bump Newtonsoft.Json from 13.0.2 to 13.0.3
2023-03-08 09:04:41 +01:00
dependabot[bot]
f03407e9b7
Bump Newtonsoft.Json from 13.0.2 to 13.0.3
Bumps [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json) from 13.0.2 to 13.0.3.
- [Release notes](https://github.com/JamesNK/Newtonsoft.Json/releases)
- [Commits](https://github.com/JamesNK/Newtonsoft.Json/commits)

---
updated-dependencies:
- dependency-name: Newtonsoft.Json
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-08 08:02:09 +00:00
Mira
a4608d4a74
fix: Create destination directory if not exist 2023-01-29 21:51:12 +01:00
Mira
9bc5bd0308
fix: Change colors to make them visible in linux 2023-01-29 21:47:51 +01:00
Mira
997108f3d0
Update README.md 2023-01-29 18:13:47 +01:00
Mira
249148a69d
Merge pull request #3 from Fortunevale/dependabot/nuget/Microsoft.Extensions.Logging.Abstractions-7.0.0
Bump Microsoft.Extensions.Logging.Abstractions from 6.0.2 to 7.0.0
2023-01-29 18:13:21 +01:00
Mira
311650f29a
Update Logger.cs 2022-11-29 09:11:22 +01:00
Mira
9cb981e86d
fix: dont add empty strings to builder 2022-11-29 09:06:58 +01:00
Mira
1e4bcb07b0
fix: '{0}{1}' is now parsed correctly 2022-11-29 09:04:46 +01:00
dependabot[bot]
18795d104f
Bump Microsoft.Extensions.Logging.Abstractions from 6.0.2 to 7.0.0
Bumps [Microsoft.Extensions.Logging.Abstractions](https://github.com/dotnet/runtime) from 6.0.2 to 7.0.0.
- [Release notes](https://github.com/dotnet/runtime/releases)
- [Commits](https://github.com/dotnet/runtime/commits)

---
updated-dependencies:
- dependency-name: Microsoft.Extensions.Logging.Abstractions
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-29 07:15:15 +00:00
Mira
c21f2dae76
fix: No longer the need to rely on string interpolation 2022-11-29 08:11:51 +01:00
Mira
cc976c86a1
Update Logger.cs 2022-10-12 14:44:32 +02:00
Mira
7cdc1b35ea
Merge pull request #2 from Fortunevale/dependabot/nuget/Microsoft.Extensions.Logging.Abstractions-6.0.2
Bump Microsoft.Extensions.Logging.Abstractions from 6.0.1 to 6.0.2
2022-09-14 10:00:06 +02:00
dependabot[bot]
667aa66b8e
Bump Microsoft.Extensions.Logging.Abstractions from 6.0.1 to 6.0.2
Bumps [Microsoft.Extensions.Logging.Abstractions](https://github.com/dotnet/runtime) from 6.0.1 to 6.0.2.
- [Release notes](https://github.com/dotnet/runtime/releases)
- [Commits](https://github.com/dotnet/runtime/compare/v6.0.1...v6.0.2)

---
updated-dependencies:
- dependency-name: Microsoft.Extensions.Logging.Abstractions
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-14 07:42:22 +00:00
Mira
c2bb8f6398
Update Logger.cs 2022-09-04 19:41:45 +02:00
Mira
538808ec42
Update Logger.cs 2022-08-19 20:21:18 +02:00
Mira
3ec20d05d3
Fix msg 2022-07-20 06:50:25 +02:00
Mira
d0272b5761
Merge pull request #1 from Fortunevale/dependabot/nuget/Microsoft.Extensions.Logging.Abstractions-6.0.1
Bump Microsoft.Extensions.Logging.Abstractions from 6.0.0 to 6.0.1
2022-07-12 23:20:40 +02:00
dependabot[bot]
c78d869938
Bump Microsoft.Extensions.Logging.Abstractions from 6.0.0 to 6.0.1
Bumps [Microsoft.Extensions.Logging.Abstractions](https://github.com/dotnet/runtime) from 6.0.0 to 6.0.1.
- [Release notes](https://github.com/dotnet/runtime/releases)
- [Commits](https://github.com/dotnet/runtime/compare/v6.0.0...v6.0.1)

---
updated-dependencies:
- dependency-name: Microsoft.Extensions.Logging.Abstractions
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-12 21:18:57 +00:00
Mira
912ce15848
Create dependabot.yml 2022-07-12 23:18:36 +02:00
Mira
fdca37ec62
Modify LoggerProvider to work with non static 2022-06-13 11:44:01 +02:00
Mira
9e9d10a282
Smart™ 2022-06-13 10:38:08 +02:00
Mira
1e7355fe8f
No more static 2022-06-13 10:27:27 +02:00
14 changed files with 819 additions and 462 deletions

11
.github/dependabot.yml vendored Normal file
View file

@ -0,0 +1,11 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "nuget" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "daily"

33
Entities/LogEntry.cs Normal file
View file

@ -0,0 +1,33 @@
namespace Xorog.Logger;
public class LogEntry
{
internal LogEntry() { }
internal string RawMessage { get; set; }
/// <summary>
/// The time of the event.
/// </summary>
public DateTime TimeOfEvent { get; internal set; }
/// <summary>
/// The severity of the event.
/// </summary>
public CustomLogLevel LogLevel { get; internal set; }
/// <summary>
/// The message describing the event.
/// </summary>
public string Message { get; internal set; }
/// <summary>
/// Any objects involved in creating the event message.
/// </summary>
public object[] Args { get; internal set; } = Array.Empty<object>();
/// <summary>
/// The exception that's been caused.
/// </summary>
public Exception? Exception { get; internal set; }
}

13
Entities/StringPart.cs Normal file
View file

@ -0,0 +1,13 @@
namespace Xorog.Logger;
internal class StringPart : IDisposable
{
internal string String { get; set; }
internal ConsoleColor? Color { get; set; }
public void Dispose()
{
String = "";
Color = null;
}
}

14
Enums/CustomLogLevel.cs Normal file
View file

@ -0,0 +1,14 @@
namespace Xorog.Logger;
public enum CustomLogLevel
{
None,
Fatal,
Error,
Warn,
Info,
Debug,
Debug2,
Trace,
Trace2
}

View file

@ -1,7 +1,6 @@
namespace Xorog.Logger;
namespace Xorog.Logger.EventArgs;
public class LogMessageEventArgs : EventArgs
public class LogMessageEventArgs : System.EventArgs
{
public LoggerObjects.LogEntry LogEntry { get; set; }
public LogEntry LogEntry { get; set; }
}

7
Global.cs Normal file
View file

@ -0,0 +1,7 @@
global using Microsoft.Extensions.Logging;
global using System;
global using System.Collections.Generic;
global using System.IO;
global using System.Linq;
global using System.Text;
global using System.Threading.Tasks;

8
GlobalSuppressions.cs Normal file
View file

@ -0,0 +1,8 @@
// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "<Pending>", Scope = "member", Target = "~P:Xorog.Logger.LoggerProvider._logger")]

406
Logger.cs
View file

@ -1,406 +0,0 @@
using System.Text;
using System.IO;
using static Xorog.Logger.LoggerObjects;
using Microsoft.Extensions.Logging;
namespace Xorog.Logger;
public class Logger : ILogger
{
private static bool loggerStarted = false;
private static LoggerObjects.LogLevel maxLogLevel = LoggerObjects.LogLevel.DEBUG;
private static string FileName = "";
private static FileStream OpenedFile { get; set; }
private readonly static LoggerObjects _loggerObjects = new();
private static Task RunningLogger = null;
public static event EventHandler<LogMessageEventArgs> LogRaised;
/// <summary>
/// Starts the logger with specified settings
/// </summary>
/// <param name="filePath">Where the current logs should be saved to, leave blank if logs shouldnt be saved</param>
/// <param name="level">The loglevel that should be displayed in the console, does not affect whats written to file</param>
/// <param name="cleanUpBefore">Clean up old logs before a datetime</param>
/// <returns>A bool stating if the logger was started</returns>
public static ILogger StartLogger(string filePath = "", LoggerObjects.LogLevel level = LoggerObjects.LogLevel.DEBUG, DateTime cleanUpBefore = new DateTime(), bool ThrowOnFailedDeletion = false)
{
if (loggerStarted)
throw new Exception($"The logger is already started");
if (filePath is not "")
{
FileName = filePath;
OpenedFile = File.Open(FileName, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.Read);
}
loggerStarted = true;
maxLogLevel = level;
if (cleanUpBefore != new DateTime())
{
foreach (var b in Directory.GetFiles(new FileInfo(filePath).Directory.FullName))
{
try
{
FileInfo fi = new(b);
if (fi.CreationTimeUtc < cleanUpBefore)
{
fi.Delete();
LogDebug($"{fi.Name} deleted");
}
}
catch (Exception ex)
{
if (!ThrowOnFailedDeletion)
LogError( $"Couldn't delete log file {b}", ex);
else
throw new Exception($"Failed to delete {b}: {ex}");
}
}
}
RunningLogger = Task.Run(async () =>
{
while (loggerStarted)
{
try
{
while (_loggerObjects.LogsToPost.Count == 0)
{
Thread.Sleep(10);
}
for (int i = 0; i < _loggerObjects.LogsToPost.Count; i++)
{
var currentLog = _loggerObjects.LogsToPost[0];
_loggerObjects.LogsToPost.Remove(currentLog);
if (currentLog is null)
{
continue;
}
string LogLevelText = currentLog.LogLevel.ToString();
if (LogLevelText.Length < 6)
LogLevelText += new string(' ', 6 - LogLevelText.Length);
ConsoleColor LogLevelColor;
ConsoleColor BackgroundColor;
LogLevelColor = currentLog.LogLevel switch
{
LoggerObjects.LogLevel.TRACE => ConsoleColor.Gray,
LoggerObjects.LogLevel.DEBUG2 => ConsoleColor.Gray,
LoggerObjects.LogLevel.DEBUG => ConsoleColor.Gray,
LoggerObjects.LogLevel.INFO => ConsoleColor.Green,
LoggerObjects.LogLevel.WARN => ConsoleColor.Yellow,
LoggerObjects.LogLevel.ERROR => ConsoleColor.Red,
LoggerObjects.LogLevel.FATAL => ConsoleColor.Black,
_ => ConsoleColor.Gray
};
BackgroundColor = currentLog.LogLevel switch
{
LoggerObjects.LogLevel.FATAL => ConsoleColor.DarkRed,
_ => ConsoleColor.Black
};
string LogMessage = currentLog.Message;
foreach (var blacklistobject in _loggerObjects.Blacklist)
LogMessage = LogMessage.Replace(blacklistobject, new String('*', blacklistobject.Length), StringComparison.CurrentCultureIgnoreCase);
if (maxLogLevel >= currentLog.LogLevel)
{
Console.ResetColor(); Console.Write($"[{currentLog.TimeOfEvent:dd.MM.yyyy HH:mm:ss}] ");
Console.ForegroundColor = LogLevelColor; Console.BackgroundColor = BackgroundColor; Console.Write($"[{LogLevelText}]");
Console.ResetColor(); Console.WriteLine($" {LogMessage}");
if (currentLog.Exception is not null)
Console.WriteLine(currentLog.Exception.ToString());
}
_ = Task.Run(() =>
{
LogRaised?.Invoke(null, new LogMessageEventArgs() { LogEntry = currentLog });
});
try
{
if (!_loggerObjects.FileBlackList.Contains(currentLog.LogLevel))
{
Byte[] FileWrite = Encoding.UTF8.GetBytes($"[{currentLog.TimeOfEvent:dd.MM.yyyy HH:mm:ss}] [{LogLevelText}] {LogMessage}\n{(currentLog.Exception is not null ? $"{currentLog.Exception}\n" : "")}");
if (OpenedFile != null)
{
await OpenedFile.WriteAsync(FileWrite.AsMemory(0, FileWrite.Length));
OpenedFile.Flush();
}
}
}
catch (Exception ex)
{
LogFatal($"Couldn't write log to file: {ex}");
}
}
}
catch (Exception ex)
{
LogError("An exception occured while trying to display a log message", ex);
await Task.Delay(1000);
continue;
}
}
});
return new Logger();
}
/// <summary>
/// Stops the logger
/// </summary>
public static void StopLogger()
{
loggerStarted = false;
maxLogLevel = LoggerObjects.LogLevel.DEBUG;
FileName = "";
Thread.Sleep(500);
if (RunningLogger is not null)
RunningLogger.Dispose();
RunningLogger = null;
if (OpenedFile is not null)
OpenedFile.Close();
}
/// <summary>
/// Add blacklisted string to censor automatically
/// </summary>
/// <param name="blacklist"></param>
public static void AddBlacklist(string blacklist)
{
_loggerObjects.Blacklist.Add(blacklist);
}
/// <summary>
/// Add blacklisted log level to not save
/// </summary>
/// <param name="blacklist"></param>
public static void AddLogLevelBlacklist(LoggerObjects.LogLevel level)
{
_loggerObjects.FileBlackList.Add(level);
}
/// <summary>
/// Changes the log level
/// </summary>
/// <param name="level"></param>
public static void ChangeLogLevel(LoggerObjects.LogLevel level)
{
maxLogLevel = level;
}
/// <summary>
/// Log with none log level
/// </summary>
/// <param name="sender"></param>
/// <param name="message"></param>
public static void LogNone(string message, Exception? exception = null)
{
_loggerObjects.LogsToPost.Add(new LoggerObjects.LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = LoggerObjects.LogLevel.NONE,
Message = message,
Exception = exception
});
}
/// <summary>
/// Log with trace log level
/// </summary>
/// <param name="sender"></param>
/// <param name="message"></param>
public static void LogTrace(string message, Exception? exception = null)
{
_loggerObjects.LogsToPost.Add(new LoggerObjects.LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = LoggerObjects.LogLevel.TRACE,
Message = message,
Exception = exception
});
}
/// <summary>
/// Log with debug2 log level
/// </summary>
/// <param name="sender"></param>
/// <param name="message"></param>
public static void LogDebug2(string message, Exception? exception = null)
{
_loggerObjects.LogsToPost.Add(new LoggerObjects.LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = LoggerObjects.LogLevel.DEBUG2,
Message = message,
Exception = exception
});
}
/// <summary>
/// Log with debug log level
/// </summary>
/// <param name="sender"></param>
/// <param name="message"></param>
public static void LogDebug(string message, Exception? exception = null)
{
_loggerObjects.LogsToPost.Add(new LoggerObjects.LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = LoggerObjects.LogLevel.DEBUG,
Message = message,
Exception = exception
});
}
/// <summary>
/// Log with info log level
/// </summary>
/// <param name="sender"></param>
/// <param name="message"></param>
public static void LogInfo(string message, Exception? exception = null)
{
_loggerObjects.LogsToPost.Add(new LoggerObjects.LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = LoggerObjects.LogLevel.INFO,
Message = message,
Exception = exception
});
}
/// <summary>
/// Log with warn log level
/// </summary>
/// <param name="sender"></param>
/// <param name="message"></param>
public static void LogWarn(string message, Exception? exception = null)
{
_loggerObjects.LogsToPost.Add(new LoggerObjects.LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = LoggerObjects.LogLevel.WARN,
Message = message,
Exception = exception
});
}
/// <summary>
/// Log with error log level
/// </summary>
/// <param name="sender"></param>
/// <param name="message"></param>
public static void LogError(string message, Exception? exception = null)
{
_loggerObjects.LogsToPost.Add(new LoggerObjects.LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = LoggerObjects.LogLevel.ERROR,
Message = message,
Exception = exception
});
}
/// <summary>
/// Log with fatal log level
/// </summary>
/// <param name="sender"></param>
/// <param name="message"></param>
public static void LogFatal(string message, Exception? exception = null)
{
_loggerObjects.LogsToPost.Add(new LoggerObjects.LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = LoggerObjects.LogLevel.FATAL,
Message = message,
Exception = exception
});
}
/// <summary>
/// Log with standard Microsoft.Extensions.Logging format
/// </summary>
/// <typeparam name="TState"></typeparam>
/// <param name="logLevel"></param>
/// <param name="eventId"></param>
/// <param name="state"></param>
/// <param name="exception"></param>
/// <param name="formatter"></param>
public void Log<TState>(Microsoft.Extensions.Logging.LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
{
_loggerObjects.LogsToPost.Add(new LoggerObjects.LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = logLevel switch
{
Microsoft.Extensions.Logging.LogLevel.Debug => LoggerObjects.LogLevel.DEBUG2,
Microsoft.Extensions.Logging.LogLevel.Trace => LoggerObjects.LogLevel.TRACE2,
Microsoft.Extensions.Logging.LogLevel.Information => LoggerObjects.LogLevel.INFO,
Microsoft.Extensions.Logging.LogLevel.Warning => LoggerObjects.LogLevel.WARN,
Microsoft.Extensions.Logging.LogLevel.Error => LoggerObjects.LogLevel.ERROR,
Microsoft.Extensions.Logging.LogLevel.Critical => LoggerObjects.LogLevel.FATAL,
Microsoft.Extensions.Logging.LogLevel.None => LoggerObjects.LogLevel.NONE,
_ => throw new NotImplementedException()
},
Message = $"[{eventId.Id,2}] {formatter(state, exception)}",
Exception = exception
});
}
public bool IsEnabled(Microsoft.Extensions.Logging.LogLevel logLevel)
{
return loggerStarted;
}
public IDisposable BeginScope<TState>(TState state)
{
return default!;
}
}

696
LoggerClient.cs Normal file
View file

@ -0,0 +1,696 @@
using Newtonsoft.Json;
using Xorog.Logger.EventArgs;
namespace Xorog.Logger;
public sealed class LoggerClient : ILogger
{
internal LoggerClient() { }
/// <summary>
/// The <see cref="ILoggerProvider"/>.
/// </summary>
public LoggerProvider Provider { get; internal set; }
private bool LoggerStarted = false;
private CustomLogLevel MaxLogLevel = CustomLogLevel.Debug;
private string FileName = "";
private FileStream OpenedFile { get; set; }
internal List<LogEntry> LogsToPost = new();
internal List<string> Blacklist = new();
internal List<CustomLogLevel> FileBlackList = new();
private Task RunningLogger = null;
/// <summary>
/// Fired when a log message has been sent.
/// </summary>
public event EventHandler<LogMessageEventArgs> LogRaised;
/// <summary>
/// Starts the logger with specified settings
/// </summary>
/// <param name="filePath">Where the current logs should be saved to, leave blank if logs shouldnt be saved</param>
/// <param name="level">The loglevel that should be displayed in the console, does not affect whats written to file</param>
/// <param name="cleanUpBefore">Clean up old logs before a datetime</param>
/// <returns>A bool stating if the logger was started</returns>
public static LoggerClient StartLogger(string filePath = "", CustomLogLevel level = CustomLogLevel.Debug, DateTime cleanUpBefore = new DateTime(), bool ThrowOnFailedDeletion = false)
{
DirectoryInfo directoryInfo = new(new FileInfo(filePath).DirectoryName);
if (!directoryInfo.Exists)
directoryInfo.Create();
filePath = filePath.Replace("\\", "/");
var handler = new LoggerClient();
handler.Provider = new(handler);
if (handler.LoggerStarted)
throw new Exception($"The logger is already started");
if (filePath is not "")
{
if (filePath.Contains('/'))
{
var dirPath = filePath[..filePath.LastIndexOf('/')];
if (!Directory.Exists(dirPath))
_ = Directory.CreateDirectory(dirPath);
}
handler.FileName = filePath;
handler.OpenedFile = File.Open(handler.FileName, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.Read);
}
handler.LoggerStarted = true;
handler.MaxLogLevel = level;
if (cleanUpBefore != new DateTime())
{
foreach (var b in Directory.GetFiles(new FileInfo(filePath).Directory.FullName))
{
try
{
FileInfo fi = new(b);
if (fi.CreationTimeUtc < cleanUpBefore)
{
fi.Delete();
handler.LogDebug($"{fi.Name} deleted");
}
}
catch (Exception ex)
{
if (!ThrowOnFailedDeletion)
handler.LogError( $"Couldn't delete log file {b}", ex);
else
throw new Exception($"Failed to delete {b}: {ex}");
}
}
}
handler.RunningLogger = Task.Run(async () =>
{
while (handler.LoggerStarted)
{
try
{
while (handler.LogsToPost.Count == 0)
{
Thread.Sleep(10);
}
for (var i = 0; i < handler.LogsToPost.Count; i++)
{
var currentLog = handler.LogsToPost[0];
_ = handler.LogsToPost.Remove(currentLog);
if (currentLog is null || currentLog.RawMessage is null)
{
continue;
}
var LogLevelText = $"{currentLog.LogLevel,-6}";
ConsoleColor LogLevelColor;
ConsoleColor BackgroundColor;
LogLevelColor = currentLog.LogLevel switch
{
CustomLogLevel.Trace => ConsoleColor.Gray,
CustomLogLevel.Debug2 => ConsoleColor.Gray,
CustomLogLevel.Debug => ConsoleColor.Gray,
CustomLogLevel.Info => ConsoleColor.Cyan,
CustomLogLevel.Warn => ConsoleColor.Yellow,
CustomLogLevel.Error => ConsoleColor.Red,
CustomLogLevel.Fatal => ConsoleColor.Black,
_ => ConsoleColor.Gray
};
BackgroundColor = currentLog.LogLevel switch
{
CustomLogLevel.Fatal => ConsoleColor.DarkRed,
_ => ConsoleColor.Black
};
var leftOver = currentLog.RawMessage;
foreach (var blacklistobject in handler.Blacklist)
leftOver = leftOver.Replace(blacklistobject, new String('*', blacklistobject.Length), StringComparison.CurrentCultureIgnoreCase);
var currentArg = 0;
var inTemplate = false;
var attemptedParsing = false;
List<StringPart> builder = new();
while (leftOver.Length > 0)
{
if (inTemplate)
{
attemptedParsing = true;
if (currentLog.Args?.Length >= currentArg && currentLog.Args?.Length != 0)
{
try
{
var endIndex = leftOver.IndexOf('}');
if (currentArg > currentLog.Args.Length)
continue;
var objectToAdd = currentLog.Args[currentArg];
currentArg++;
if (objectToAdd is null)
continue;
if (objectToAdd.GetType() == typeof(int))
builder.Add(new StringPart { String = objectToAdd.ToString(), Color = ConsoleColor.Magenta });
else if (objectToAdd.GetType() == typeof(long))
builder.Add(new StringPart { String = objectToAdd.ToString(), Color = ConsoleColor.Magenta });
else if (objectToAdd.GetType() == typeof(uint))
builder.Add(new StringPart { String = objectToAdd.ToString(), Color = ConsoleColor.Magenta });
else if (objectToAdd.GetType() == typeof(ulong))
builder.Add(new StringPart { String = objectToAdd.ToString(), Color = ConsoleColor.Magenta });
else
builder.Add(new StringPart { String = objectToAdd.ToString(), Color = ConsoleColor.Cyan });
inTemplate = false;
leftOver = leftOver[(endIndex + 1)..];
attemptedParsing = false;
}
catch (Exception)
{
currentArg++;
continue;
}
continue;
}
}
inTemplate = false;
var placeholderIndex = leftOver.IndexOf('{');
if (placeholderIndex != -1)
inTemplate = true;
if (placeholderIndex == -1 || placeholderIndex > leftOver.Length)
placeholderIndex = leftOver.Length;
if (placeholderIndex == 0 && attemptedParsing)
placeholderIndex = leftOver.Length;
var str = leftOver[..placeholderIndex];
if (!string.IsNullOrEmpty(str))
builder.Add(new StringPart { String = str });
leftOver = leftOver[placeholderIndex..];
attemptedParsing = false;
}
if (handler.MaxLogLevel >= currentLog.LogLevel)
{
Console.ResetColor(); Console.Write($"[{currentLog.TimeOfEvent:dd.MM.yyyy HH:mm:ss:fff}] ");
Console.ForegroundColor = LogLevelColor; Console.BackgroundColor = BackgroundColor; Console.Write($"[{LogLevelText}]"); Console.ResetColor(); Console.Write(" ");
foreach (var part in builder)
{
Console.ForegroundColor = part.Color ?? ConsoleColor.White;
Console.BackgroundColor = ConsoleColor.Black;
Console.Write($"{part.String}");
}
Console.ResetColor();
Console.WriteLine();
if (currentLog.Exception is not null)
try
{
Console.WriteLine(JsonConvert.SerializeObject(currentLog.Exception, Formatting.Indented, new JsonSerializerSettings()
{
NullValueHandling = NullValueHandling.Ignore,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
Error = (serializer, err) => err.ErrorContext.Handled = true
}));
}
catch (Exception)
{
Console.WriteLine(currentLog.Exception);
}
}
currentLog.Message = string.Join("", builder.Select(x => x.String));
for (var i1 = 0; i1 < builder.Count; i1++)
{
builder[i1].Dispose();
}
builder.Clear();
_ = Task.Run(() => handler.LogRaised?.Invoke(null, new LogMessageEventArgs() { LogEntry = currentLog }));
try
{
if (!handler.FileBlackList.Contains(currentLog.LogLevel))
{
var FileWrite = Encoding.UTF8.GetBytes($"[{currentLog.TimeOfEvent:dd.MM.yyyy HH:mm:ss:fff}] [{LogLevelText}] {currentLog.Message}\n{(currentLog.Exception is not null ? $"{currentLog.Exception}\n" : "")}");
if (handler.OpenedFile != null)
{
await handler.OpenedFile.WriteAsync(FileWrite.AsMemory(0, FileWrite.Length));
handler.OpenedFile.Flush();
}
}
}
catch (Exception ex)
{
handler.LogFatal($"Couldn't write log to file: {ex}");
}
}
}
catch (Exception ex)
{
handler.LogError("An exception occurred while trying to display a log message", ex);
await Task.Delay(1000);
continue;
}
}
});
return handler;
}
/// <summary>
/// Stops the logger
/// </summary>
public void StopLogger()
{
LoggerStarted = false;
MaxLogLevel = CustomLogLevel.Debug;
FileName = "";
Thread.Sleep(500);
RunningLogger?.Dispose();
RunningLogger = null;
this.OpenedFile?.Close();
}
/// <summary>
/// Add strings automatically censor on output to console and file.
/// </summary>
/// <param name="blacklist">The strings to censor</param>
public void AddBlacklist(params string[] blacklist)
{
for (var i = 0; i < blacklist.Length; i++)
{
if (!string.IsNullOrWhiteSpace(blacklist[i]))
Blacklist.Add(blacklist[i]);
}
}
/// <summary>
/// Add blacklisted log level to not save
/// </summary>
/// <param name="levels">The log levels not to save to the log file</param>
public void AddLogLevelBlacklist(params CustomLogLevel[] levels)
{
for (var i = 0; i < levels.Length; i++)
{
FileBlackList.Add(levels[i]);
}
}
/// <summary>
/// Changes the log level
/// </summary>
/// <param name="level">The new log level to apply</param>
public void ChangeLogLevel(CustomLogLevel level) => MaxLogLevel = level;
/// <summary>
/// Log with none log level
/// </summary>
/// <param name="message">The message to display</param>
/// <param name="exception">The exception that was caused</param>
/// <param name="args">The objects involved in the event</param>
public void LogNone(string message, Exception? exception = null, params object[] args) => LogsToPost.Add(new LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = CustomLogLevel.None,
RawMessage = message,
Args = args,
Exception = exception
});
/// <summary>
/// Log with none log level
/// </summary>
/// <param name="message">The message to display</param>
/// <param name="exception">The exception that was caused</param>
public void LogNone(string message, Exception? exception = null) => LogsToPost.Add(new LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = CustomLogLevel.None,
RawMessage = message,
Exception = exception
});
/// <summary>
/// Log with none log level
/// </summary>
/// <param name="message">The message to display</param>
/// <param name="args">The objects involved in the event</param>
public void LogNone(string message, params object[] args) => LogsToPost.Add(new LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = CustomLogLevel.None,
RawMessage = message,
Args = args
});
/// <summary>
/// Log with trace log level
/// </summary>
/// <param name="message">The message to display</param>
/// <param name="exception">The exception that was caused</param>
/// <param name="args">The objects involved in the event</param>
public void LogTrace(string message, Exception? exception = null, params object[] args) => LogsToPost.Add(new LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = CustomLogLevel.Trace,
RawMessage = message,
Args = args,
Exception = exception
});
/// <summary>
/// Log with trace log level
/// </summary>
/// <param name="message">The message to display</param>
/// <param name="exception">The exception that was caused</param>
public void LogTrace(string message, Exception? exception = null) => LogsToPost.Add(new LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = CustomLogLevel.Trace,
RawMessage = message,
Exception = exception
});
/// <summary>
/// Log with trace log level
/// </summary>
/// <param name="message">The message to display</param>
/// <param name="args">The objects involved in the event</param>
public void LogTrace(string message, params object[] args) => LogsToPost.Add(new LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = CustomLogLevel.Trace,
RawMessage = message,
Args = args,
});
/// <summary>
/// Log with debug2 log level
/// </summary>
/// <param name="message">The message to display</param>
/// <param name="exception">The exception that was caused</param>
/// <param name="args">The objects involved in the event</param>
public void LogDebug2(string message, Exception? exception = null, params object[] args) => LogsToPost.Add(new LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = CustomLogLevel.Debug2,
RawMessage = message,
Args = args,
Exception = exception
});
/// <summary>
/// Log with debug2 log level
/// </summary>
/// <param name="message">The message to display</param>
/// <param name="exception">The exception that was caused</param>
public void LogDebug2(string message, Exception? exception = null) => LogsToPost.Add(new LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = CustomLogLevel.Debug2,
RawMessage = message,
Exception = exception
});
/// <summary>
/// Log with debug2 log level
/// </summary>
/// <param name="message">The message to display</param>
/// <param name="args">The objects involved in the event</param>
public void LogDebug2(string message, params object[] args) => LogsToPost.Add(new LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = CustomLogLevel.Debug2,
RawMessage = message,
Args = args
});
/// <summary>
/// Log with debug log level
/// </summary>
/// <param name="message">The message to display</param>
/// <param name="exception">The exception that was caused</param>
/// <param name="args">The objects involved in the event</param>
public void LogDebug(string message, Exception? exception = null, params object[] args) => LogsToPost.Add(new LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = CustomLogLevel.Debug,
RawMessage = message,
Args = args,
Exception = exception
});
/// <summary>
/// Log with debug log level
/// </summary>
/// <param name="message">The message to display</param>
/// <param name="exception">The exception that was caused</param>
public void LogDebug(string message, Exception? exception = null) => LogsToPost.Add(new LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = CustomLogLevel.Debug,
RawMessage = message,
Exception = exception
});
/// <summary>
/// Log with debug log level
/// </summary>
/// <param name="message">The message to display</param>
/// <param name="args">The objects involved in the event</param>
public void LogDebug(string message, params object[] args) => LogsToPost.Add(new LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = CustomLogLevel.Debug,
RawMessage = message,
Args = args
});
/// <summary>
/// Log with info log level
/// </summary>
/// <param name="message">The message to display</param>
/// <param name="exception">The exception that was caused</param>
/// <param name="args">The objects involved in the event</param>
public void LogInfo(string message, Exception? exception = null, params object[] args) => LogsToPost.Add(new LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = CustomLogLevel.Info,
RawMessage = message,
Args = args,
Exception = exception
});
/// <summary>
/// Log with info log level
/// </summary>
/// <param name="message">The message to display</param>
/// <param name="exception">The exception that was caused</param>
public void LogInfo(string message, Exception? exception = null) => LogsToPost.Add(new LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = CustomLogLevel.Info,
RawMessage = message,
Exception = exception
});
/// <summary>
/// Log with info log level
/// </summary>
/// <param name="message">The message to display</param>
/// <param name="args">The objects involved in the event</param>
public void LogInfo(string message, params object[] args) => LogsToPost.Add(new LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = CustomLogLevel.Info,
RawMessage = message,
Args = args
});
/// <summary>
/// Log with warn log level
/// </summary>
/// <param name="message">The message to display</param>
/// <param name="exception">The exception that was caused</param>
/// <param name="args">The objects involved in the event</param>
public void LogWarn(string message, Exception? exception = null, params object[] args) => LogsToPost.Add(new LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = CustomLogLevel.Warn,
RawMessage = message,
Args = args,
Exception = exception
});
/// <summary>
/// Log with warn log level
/// </summary>
/// <param name="message">The message to display</param>
/// <param name="exception">The exception that was caused</param>
public void LogWarn(string message, Exception? exception = null) => LogsToPost.Add(new LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = CustomLogLevel.Warn,
RawMessage = message,
Exception = exception
});
/// <summary>
/// Log with warn log level
/// </summary>
/// <param name="message">The message to display</param>
/// <param name="args">The objects involved in the event</param>
public void LogWarn(string message, params object[] args) => LogsToPost.Add(new LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = CustomLogLevel.Warn,
RawMessage = message,
Args = args
});
/// <summary>
/// Log with error log level
/// </summary>
/// <param name="message">The message to display</param>
/// <param name="exception">The exception that was caused</param>
/// <param name="args">The objects involved in the event</param>
public void LogError(string message, Exception? exception = null, params object[] args) => LogsToPost.Add(new LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = CustomLogLevel.Error,
RawMessage = message,
Args = args,
Exception = exception
});
/// <summary>
/// Log with error log level
/// </summary>
/// <param name="message">The message to display</param>
/// <param name="exception">The exception that was caused</param>
public void LogError(string message, Exception? exception = null) => LogsToPost.Add(new LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = CustomLogLevel.Error,
RawMessage = message,
Exception = exception
});
/// <summary>
/// Log with error log level
/// </summary>
/// <param name="message">The message to display</param>
/// <param name="args">The objects involved in the event</param>
public void LogError(string message, params object[] args) => LogsToPost.Add(new LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = CustomLogLevel.Error,
RawMessage = message,
Args = args
});
/// <summary>
/// Log with fatal log level
/// </summary>
/// <param name="message">The message to display</param>
/// <param name="exception">The exception that was caused</param>
/// <param name="args">The objects involved in the event</param>
public void LogFatal(string message, Exception? exception = null, params object[] args) => LogsToPost.Add(new LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = CustomLogLevel.Fatal,
RawMessage = message,
Args = args,
Exception = exception
});
/// <summary>
/// Log with fatal log level
/// </summary>
/// <param name="message">The message to display</param>
/// <param name="exception">The exception that was caused</param>
public void LogFatal(string message, Exception? exception = null) => LogsToPost.Add(new LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = CustomLogLevel.Fatal,
RawMessage = message,
Exception = exception
});
/// <summary>
/// Log with fatal log level
/// </summary>
/// <param name="message">The message to display</param>
/// <param name="args">The objects involved in the event</param>
public void LogFatal(string message, params object[] args) => LogsToPost.Add(new LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = CustomLogLevel.Fatal,
RawMessage = message,
Args = args
});
/// <summary>
/// Log with standard Microsoft.Extensions.Logging format
/// </summary>
/// <typeparam name="TState"></typeparam>
/// <param name="logLevel"></param>
/// <param name="eventId"></param>
/// <param name="state"></param>
/// <param name="exception"></param>
/// <param name="formatter"></param>
public void Log<TState>(Microsoft.Extensions.Logging.LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter) => LogsToPost.Add(new LogEntry
{
TimeOfEvent = DateTime.Now,
LogLevel = logLevel switch
{
Microsoft.Extensions.Logging.LogLevel.Debug => CustomLogLevel.Debug2,
Microsoft.Extensions.Logging.LogLevel.Trace => CustomLogLevel.Trace2,
Microsoft.Extensions.Logging.LogLevel.Information => CustomLogLevel.Info,
Microsoft.Extensions.Logging.LogLevel.Warning => CustomLogLevel.Warn,
Microsoft.Extensions.Logging.LogLevel.Error => CustomLogLevel.Error,
Microsoft.Extensions.Logging.LogLevel.Critical => CustomLogLevel.Fatal,
Microsoft.Extensions.Logging.LogLevel.None => CustomLogLevel.None,
_ => CustomLogLevel.None,
},
RawMessage = $"[{eventId.Id}] {formatter(state, exception)}",
Exception = exception
});
public bool IsEnabled(Microsoft.Extensions.Logging.LogLevel logLevel)
=> LoggerStarted;
public IDisposable BeginScope<TState>(TState state)
=> default!;
}

View file

@ -1,29 +0,0 @@
namespace Xorog.Logger;
public class LoggerObjects
{
internal List<LogEntry> LogsToPost = new();
internal List<string> Blacklist = new();
internal List<LogLevel> FileBlackList = new();
public class LogEntry
{
public DateTime TimeOfEvent { get; set; }
public LogLevel LogLevel { get; set; }
public string Message { get; set; }
public Exception? Exception { get; set; }
}
public enum LogLevel
{
NONE,
FATAL,
ERROR,
WARN,
INFO,
DEBUG,
DEBUG2,
TRACE,
TRACE2
}
}

View file

@ -1,24 +1,16 @@
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Xorog.Logger;
namespace Xorog.Logger;
public class LoggerProvider : ILoggerProvider
public sealed class LoggerProvider : ILoggerProvider
{
private readonly ConcurrentDictionary<string, Logger> _loggers = new(StringComparer.OrdinalIgnoreCase);
internal LoggerProvider(LoggerClient logger)
=> this._logger = logger;
public ILogger CreateLogger(string categoryName)
{
return _loggers.GetOrAdd(categoryName, name => new Logger());
}
public void Dispose()
{
_loggers.Clear();
GC.SuppressFinalize(this);
}
private LoggerClient _logger { get; set; }
public ILogger CreateLogger(string categoryName)
=> this._logger;
public void Dispose()
=> GC.SuppressFinalize(this);
}

View file

@ -0,0 +1,7 @@
{
"profiles": {
"Xorog.Logger": {
"commandName": "Project"
}
}
}

View file

@ -1,3 +1,9 @@
# Xorog.Logger
This legacy branch is meant to prevent having to update way too many applications because of a few breaking changes to main.
The logger used in projects of Fortunevale.
## Used in
- [BeatRecorder](https://github.com/TheXorog/BeatRecorder)
<!-- - [Project Ichigo](https://github.com/Fortunevale/ProjectIchigo) -->

View file

@ -1,11 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>annotations</Nullable>
<Configurations>Debug;Release;x64</Configurations>
<Platforms>AnyCPU;x64</Platforms>
<Platforms>x64</Platforms>
<RunAnalyzersDuringBuild>False</RunAnalyzersDuringBuild>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
@ -14,10 +15,12 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DebugType>embedded</DebugType>
<Optimize>True</Optimize>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64|AnyCPU'">
<DebugType>embedded</DebugType>
<Optimize>False</Optimize>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -26,14 +29,17 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<DebugType>embedded</DebugType>
<Optimize>True</Optimize>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64|x64'">
<DebugType>embedded</DebugType>
<Optimize>False</Optimize>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
</Project>