fix: No longer the need to rely on string interpolation

This commit is contained in:
Mira 2022-11-29 08:11:51 +01:00
parent cc976c86a1
commit c21f2dae76
Signed by untrusted user who does not match committer: Xorog
GPG key ID: 983798ED9C3E7C36
4 changed files with 401 additions and 149 deletions

View file

@ -2,8 +2,11 @@
public class LogEntry public class LogEntry
{ {
internal string RawMessage { get; set; }
public DateTime TimeOfEvent { get; set; } public DateTime TimeOfEvent { get; set; }
public LogLevel LogLevel { get; set; } public LogLevel LogLevel { get; set; }
public string Message { get; set; } public string Message { get; set; }
public object[] Args { get; set; }
public Exception? Exception { get; set; } public Exception? Exception { get; set; }
} }

13
Entities/StringPart.cs Normal file
View file

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

529
Logger.cs
View file

@ -1,4 +1,6 @@
namespace Xorog.Logger; using Newtonsoft.Json;
namespace Xorog.Logger;
#pragma warning disable IDE1006 // Naming Styles #pragma warning disable IDE1006 // Naming Styles
@ -92,10 +94,7 @@ public class Logger : ILogger
continue; continue;
} }
string LogLevelText = currentLog.LogLevel.ToString(); string LogLevelText = $"{currentLog.LogLevel,-6}";
if (LogLevelText.Length < 6)
LogLevelText += new string(' ', 6 - LogLevelText.Length);
ConsoleColor LogLevelColor; ConsoleColor LogLevelColor;
ConsoleColor BackgroundColor; ConsoleColor BackgroundColor;
@ -118,19 +117,86 @@ public class Logger : ILogger
_ => ConsoleColor.Black _ => ConsoleColor.Black
}; };
string LogMessage = currentLog.Message; string leftOver = currentLog.RawMessage;
foreach (var blacklistobject in handler.Blacklist) foreach (var blacklistobject in handler.Blacklist)
LogMessage = LogMessage.Replace(blacklistobject, new String('*', blacklistobject.Length), StringComparison.CurrentCultureIgnoreCase); leftOver = leftOver.Replace(blacklistobject, new String('*', blacklistobject.Length), StringComparison.CurrentCultureIgnoreCase);
int currentArg = 0;
bool inTemplate = false;
List<StringPart> builder = new();
while (leftOver.Length > 0)
{
if (inTemplate && currentLog.Args?.Length >= currentArg)
{
int endIndex = leftOver.IndexOf('}');
object objectToAdd = currentLog.Args[currentArg];
currentArg++;
if (objectToAdd.GetType() == typeof(int))
builder.Add(new StringPart { String = objectToAdd.ToString(), Color = ConsoleColor.Cyan });
else if (objectToAdd.GetType() == typeof(long))
builder.Add(new StringPart { String = objectToAdd.ToString(), Color = ConsoleColor.Cyan });
else if (objectToAdd.GetType() == typeof(uint))
builder.Add(new StringPart { String = objectToAdd.ToString(), Color = ConsoleColor.Cyan });
else if (objectToAdd.GetType() == typeof(ulong))
builder.Add(new StringPart { String = objectToAdd.ToString(), Color = ConsoleColor.Cyan });
else
builder.Add(new StringPart { String = objectToAdd.ToString(), Color = ConsoleColor.DarkGray });
inTemplate = false;
leftOver = leftOver[(endIndex + 1)..];
continue;
}
inTemplate = false;
int placeholderIndex = leftOver.IndexOf('{');
if (placeholderIndex != -1 && currentLog.Args?.Length >= currentArg)
inTemplate = true;
if (placeholderIndex is -1 or 0 || placeholderIndex > leftOver.Length)
placeholderIndex = leftOver.Length;
builder.Add(new StringPart { String = leftOver[..placeholderIndex] });
leftOver = leftOver[placeholderIndex..];
}
if (handler.maxLogLevel >= currentLog.LogLevel) if (handler.maxLogLevel >= currentLog.LogLevel)
{ {
Console.ResetColor(); Console.Write($"[{currentLog.TimeOfEvent:dd.MM.yyyy HH:mm:ss:fff}] "); Console.ResetColor(); Console.Write($"[{currentLog.TimeOfEvent:dd.MM.yyyy HH:mm:ss:fff}] ");
Console.ForegroundColor = LogLevelColor; Console.BackgroundColor = BackgroundColor; Console.Write($"[{LogLevelText}]"); Console.ForegroundColor = LogLevelColor; Console.BackgroundColor = BackgroundColor; Console.Write($"[{LogLevelText}]"); Console.ResetColor(); Console.Write(" ");
Console.ResetColor(); Console.WriteLine($" {LogMessage}");
foreach (StringPart 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) if (currentLog.Exception is not null)
Console.WriteLine(currentLog.Exception); try
{
Console.WriteLine(JsonConvert.SerializeObject(currentLog.Exception, Formatting.Indented, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore }));
}
catch (Exception)
{
Console.WriteLine(currentLog.Exception);
}
}
currentLog.Message = string.Join("", builder.Select(x => x.String));
for (int i1 = 0; i1 < builder.Count; i1++)
{
builder[i1].Dispose();
} }
_ = Task.Run(() => _ = Task.Run(() =>
@ -142,7 +208,7 @@ public class Logger : ILogger
{ {
if (!handler.FileBlackList.Contains(currentLog.LogLevel)) if (!handler.FileBlackList.Contains(currentLog.LogLevel))
{ {
Byte[] FileWrite = Encoding.UTF8.GetBytes($"[{currentLog.TimeOfEvent:dd.MM.yyyy HH:mm:ss:fff}] [{LogLevelText}] {LogMessage}\n{(currentLog.Exception is not null ? $"{currentLog.Exception}\n" : "")}"); Byte[] 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) if (handler.OpenedFile != null)
{ {
await handler.OpenedFile.WriteAsync(FileWrite.AsMemory(0, FileWrite.Length)); await handler.OpenedFile.WriteAsync(FileWrite.AsMemory(0, FileWrite.Length));
@ -168,8 +234,6 @@ public class Logger : ILogger
return handler; return handler;
} }
/// <summary> /// <summary>
/// Stops the logger /// Stops the logger
/// </summary> /// </summary>
@ -188,181 +252,363 @@ public class Logger : ILogger
OpenedFile?.Close(); OpenedFile?.Close();
} }
/// <summary> /// <summary>
/// Add blacklisted string to censor automatically /// Add strings automatically censor on output to console and file.
/// </summary> /// </summary>
/// <param name="blacklist"></param> /// <param name="blacklist">The strings to censor</param>
public void AddBlacklist(string blacklist) public void AddBlacklist(params string[] blacklist)
{ {
Blacklist.Add(blacklist); for (int i = 0; i < blacklist.Length; i++)
{
Blacklist.Add(blacklist[i]);
}
} }
/// <summary> /// <summary>
/// Add blacklisted log level to not save /// Add blacklisted log level to not save
/// </summary> /// </summary>
/// <param name="blacklist"></param> /// <param name="levels">The log levels not to save to the log file</param>
public void AddLogLevelBlacklist(LogLevel level) public void AddLogLevelBlacklist(params LogLevel[] levels)
{ {
FileBlackList.Add(level); for (int i = 0; i < levels.Length; i++)
{
FileBlackList.Add(levels[i]);
}
} }
/// <summary> /// <summary>
/// Changes the log level /// Changes the log level
/// </summary> /// </summary>
/// <param name="level"></param> /// <param name="level">The new log level to apply</param>
public void ChangeLogLevel(LogLevel level) public void ChangeLogLevel(LogLevel level) => maxLogLevel = level;
{
maxLogLevel = level;
}
/// <summary> /// <summary>
/// Log with none log level /// Log with none log level
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="message">The message to display</param>
/// <param name="message"></param> /// <param name="exception">The exception that was caused</param>
public void LogNone(string message, Exception? exception = null) /// <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
{ {
LogsToPost.Add(new LogEntry TimeOfEvent = DateTime.Now,
{ LogLevel = LogLevel.NONE,
TimeOfEvent = DateTime.Now, RawMessage = message,
LogLevel = LogLevel.NONE, Args = args,
Message = message, Exception = exception
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 = LogLevel.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 = LogLevel.NONE,
RawMessage = message,
Args = args
});
/// <summary> /// <summary>
/// Log with trace log level /// Log with trace log level
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="message">The message to display</param>
/// <param name="message"></param> /// <param name="exception">The exception that was caused</param>
public void LogTrace(string message, Exception? exception = null) /// <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
{ {
LogsToPost.Add(new LogEntry TimeOfEvent = DateTime.Now,
{ LogLevel = LogLevel.TRACE,
TimeOfEvent = DateTime.Now, RawMessage = message,
LogLevel = LogLevel.TRACE, Args = args,
Message = message, Exception = exception
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 = LogLevel.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 = LogLevel.TRACE,
RawMessage = message,
Args = args,
});
/// <summary> /// <summary>
/// Log with debug2 log level /// Log with debug2 log level
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="message">The message to display</param>
/// <param name="message"></param> /// <param name="exception">The exception that was caused</param>
public void LogDebug2(string message, Exception? exception = null) /// <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
{ {
LogsToPost.Add(new LogEntry TimeOfEvent = DateTime.Now,
{ LogLevel = LogLevel.DEBUG2,
TimeOfEvent = DateTime.Now, RawMessage = message,
LogLevel = LogLevel.DEBUG2, Args = args,
Message = message, Exception = exception
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 = LogLevel.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 = LogLevel.DEBUG2,
RawMessage = message,
Args = args
});
/// <summary> /// <summary>
/// Log with debug log level /// Log with debug log level
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="message">The message to display</param>
/// <param name="message"></param> /// <param name="exception">The exception that was caused</param>
public void LogDebug(string message, Exception? exception = null) /// <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
{ {
LogsToPost.Add(new LogEntry TimeOfEvent = DateTime.Now,
{ LogLevel = LogLevel.DEBUG,
TimeOfEvent = DateTime.Now, RawMessage = message,
LogLevel = LogLevel.DEBUG, Args = args,
Message = message, Exception = exception
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 = LogLevel.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 = LogLevel.DEBUG,
RawMessage = message,
Args = args
});
/// <summary> /// <summary>
/// Log with info log level /// Log with info log level
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="message">The message to display</param>
/// <param name="message"></param> /// <param name="exception">The exception that was caused</param>
public void LogInfo(string message, Exception? exception = null) /// <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
{ {
LogsToPost.Add(new LogEntry TimeOfEvent = DateTime.Now,
{ LogLevel = LogLevel.INFO,
TimeOfEvent = DateTime.Now, RawMessage = message,
LogLevel = LogLevel.INFO, Args = args,
Message = message, Exception = exception
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 = LogLevel.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 = LogLevel.INFO,
RawMessage = message,
Args = args
});
/// <summary> /// <summary>
/// Log with warn log level /// Log with warn log level
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="message">The message to display</param>
/// <param name="message"></param> /// <param name="exception">The exception that was caused</param>
public void LogWarn(string message, Exception? exception = null) /// <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
{ {
LogsToPost.Add(new LogEntry TimeOfEvent = DateTime.Now,
{ LogLevel = LogLevel.WARN,
TimeOfEvent = DateTime.Now, RawMessage = message,
LogLevel = LogLevel.WARN, Args = args,
Message = message, Exception = exception
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 = LogLevel.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 = LogLevel.WARN,
RawMessage = message,
Args = args
});
/// <summary> /// <summary>
/// Log with error log level /// Log with error log level
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="message">The message to display</param>
/// <param name="message"></param> /// <param name="exception">The exception that was caused</param>
public void LogError(string message, Exception? exception = null) /// <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
{ {
LogsToPost.Add(new LogEntry TimeOfEvent = DateTime.Now,
{ LogLevel = LogLevel.ERROR,
TimeOfEvent = DateTime.Now, RawMessage = message,
LogLevel = LogLevel.ERROR, Args = args,
Message = message, Exception = exception
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 = LogLevel.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 = LogLevel.ERROR,
RawMessage = message,
Args = args
});
/// <summary> /// <summary>
/// Log with fatal log level /// Log with fatal log level
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="message">The message to display</param>
/// <param name="message"></param> /// <param name="exception">The exception that was caused</param>
public void LogFatal(string message, Exception? exception = null) /// <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
{ {
LogsToPost.Add(new LogEntry TimeOfEvent = DateTime.Now,
{ LogLevel = LogLevel.FATAL,
TimeOfEvent = DateTime.Now, RawMessage = message,
LogLevel = LogLevel.FATAL, Args = args,
Message = message, Exception = exception
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 = LogLevel.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 = LogLevel.FATAL,
RawMessage = message,
Args = args
});
/// <summary> /// <summary>
/// Log with standard Microsoft.Extensions.Logging format /// Log with standard Microsoft.Extensions.Logging format
@ -373,38 +619,27 @@ public class Logger : ILogger
/// <param name="state"></param> /// <param name="state"></param>
/// <param name="exception"></param> /// <param name="exception"></param>
/// <param name="formatter"></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) public void Log<TState>(Microsoft.Extensions.Logging.LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter) => LogsToPost.Add(new LogEntry
{ {
LogsToPost.Add(new LogEntry TimeOfEvent = DateTime.Now,
LogLevel = logLevel switch
{ {
TimeOfEvent = DateTime.Now, Microsoft.Extensions.Logging.LogLevel.Debug => LogLevel.DEBUG2,
LogLevel = logLevel switch Microsoft.Extensions.Logging.LogLevel.Trace => LogLevel.TRACE2,
{ Microsoft.Extensions.Logging.LogLevel.Information => LogLevel.INFO,
Microsoft.Extensions.Logging.LogLevel.Debug => LogLevel.DEBUG2, Microsoft.Extensions.Logging.LogLevel.Warning => LogLevel.WARN,
Microsoft.Extensions.Logging.LogLevel.Trace => LogLevel.TRACE2, Microsoft.Extensions.Logging.LogLevel.Error => LogLevel.ERROR,
Microsoft.Extensions.Logging.LogLevel.Information => LogLevel.INFO, Microsoft.Extensions.Logging.LogLevel.Critical => LogLevel.FATAL,
Microsoft.Extensions.Logging.LogLevel.Warning => LogLevel.WARN, Microsoft.Extensions.Logging.LogLevel.None => LogLevel.NONE,
Microsoft.Extensions.Logging.LogLevel.Error => LogLevel.ERROR, _ => LogLevel.NONE,
Microsoft.Extensions.Logging.LogLevel.Critical => LogLevel.FATAL, },
Microsoft.Extensions.Logging.LogLevel.None => LogLevel.NONE, RawMessage = $"[{eventId.Id}] {formatter(state, exception)}",
_ => throw new NotImplementedException() Exception = exception
}, });
Message = $"[{eventId.Id,2}] {formatter(state, exception)}",
Exception = exception
});
}
public bool IsEnabled(Microsoft.Extensions.Logging.LogLevel logLevel) public bool IsEnabled(Microsoft.Extensions.Logging.LogLevel logLevel)
{ => loggerStarted;
return loggerStarted;
}
public IDisposable BeginScope<TState>(TState state) public IDisposable BeginScope<TState>(TState state)
{ => default!;
return default!;
}
} }

View file

@ -34,6 +34,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.2" /> <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.2" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
</ItemGroup> </ItemGroup>
</Project> </Project>