Compare commits
45 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e742f21154 | ||
|
|
f3d8fdfe04 | ||
|
|
ee2719ec67 | ||
|
|
4d1f63fbc1 | ||
|
|
f045bd7dbc | ||
|
|
b43fd3d24b | ||
|
|
f8e254440b | ||
|
|
a2ed87f7ce | ||
|
|
f1a061edc1 | ||
|
|
e18aa2ef51 | ||
|
|
40e8632a77 | ||
|
|
25898aff51 | ||
|
|
7c1ff06fa5 | ||
|
|
332b6172ae | ||
|
|
2cb5b1a169 | ||
|
|
8969bb00cc | ||
|
|
53596d9b8a | ||
|
|
a7e5672e18 | ||
|
|
03355fe27b | ||
|
|
933fe1f5e9 | ||
|
|
7b5dfa673a | ||
|
|
a3b7eccc3d | ||
|
|
3bfe19dd65 | ||
|
|
f03407e9b7 | ||
|
|
a4608d4a74 | ||
|
|
9bc5bd0308 | ||
|
|
997108f3d0 | ||
|
|
249148a69d | ||
|
|
311650f29a | ||
|
|
9cb981e86d | ||
|
|
1e4bcb07b0 | ||
|
|
18795d104f | ||
|
|
c21f2dae76 | ||
|
|
cc976c86a1 | ||
|
|
7cdc1b35ea | ||
|
|
667aa66b8e | ||
|
|
c2bb8f6398 | ||
|
|
538808ec42 | ||
|
|
3ec20d05d3 | ||
|
|
d0272b5761 | ||
|
|
c78d869938 | ||
|
|
912ce15848 | ||
|
|
fdca37ec62 | ||
|
|
9e9d10a282 | ||
|
|
1e7355fe8f |
14 changed files with 819 additions and 462 deletions
11
.github/dependabot.yml
vendored
Normal file
11
.github/dependabot.yml
vendored
Normal 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
33
Entities/LogEntry.cs
Normal 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
13
Entities/StringPart.cs
Normal 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
14
Enums/CustomLogLevel.cs
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
namespace Xorog.Logger;
|
||||||
|
|
||||||
|
public enum CustomLogLevel
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Fatal,
|
||||||
|
Error,
|
||||||
|
Warn,
|
||||||
|
Info,
|
||||||
|
Debug,
|
||||||
|
Debug2,
|
||||||
|
Trace,
|
||||||
|
Trace2
|
||||||
|
}
|
||||||
|
|
@ -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
7
Global.cs
Normal 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
8
GlobalSuppressions.cs
Normal 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
406
Logger.cs
|
|
@ -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
696
LoggerClient.cs
Normal 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!;
|
||||||
|
}
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,24 +1,16 @@
|
||||||
using Microsoft.Extensions.Logging;
|
namespace Xorog.Logger;
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Xorog.Logger;
|
public sealed class LoggerProvider : ILoggerProvider
|
||||||
public class LoggerProvider : ILoggerProvider
|
|
||||||
{
|
{
|
||||||
private readonly ConcurrentDictionary<string, Logger> _loggers = new(StringComparer.OrdinalIgnoreCase);
|
internal LoggerProvider(LoggerClient logger)
|
||||||
|
=> this._logger = logger;
|
||||||
|
|
||||||
|
|
||||||
|
private LoggerClient _logger { get; set; }
|
||||||
|
|
||||||
public ILogger CreateLogger(string categoryName)
|
public ILogger CreateLogger(string categoryName)
|
||||||
{
|
=> this._logger;
|
||||||
return _loggers.GetOrAdd(categoryName, name => new Logger());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
=> GC.SuppressFinalize(this);
|
||||||
_loggers.Clear();
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
7
Properties/launchSettings.json
Normal file
7
Properties/launchSettings.json
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"profiles": {
|
||||||
|
"Xorog.Logger": {
|
||||||
|
"commandName": "Project"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,3 +1,9 @@
|
||||||
# Xorog.Logger
|
# 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) -->
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>annotations</Nullable>
|
<Nullable>annotations</Nullable>
|
||||||
<Configurations>Debug;Release;x64</Configurations>
|
<Configurations>Debug;Release;x64</Configurations>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>x64</Platforms>
|
||||||
|
<RunAnalyzersDuringBuild>False</RunAnalyzersDuringBuild>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
|
@ -14,10 +15,12 @@
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
<DebugType>embedded</DebugType>
|
<DebugType>embedded</DebugType>
|
||||||
|
<Optimize>True</Optimize>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64|AnyCPU'">
|
||||||
<DebugType>embedded</DebugType>
|
<DebugType>embedded</DebugType>
|
||||||
|
<Optimize>False</Optimize>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
|
@ -26,14 +29,17 @@
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
<DebugType>embedded</DebugType>
|
<DebugType>embedded</DebugType>
|
||||||
|
<Optimize>True</Optimize>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64|x64'">
|
||||||
<DebugType>embedded</DebugType>
|
<DebugType>embedded</DebugType>
|
||||||
|
<Optimize>False</Optimize>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<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>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
Reference in a new issue