mirror of
https://github.com/par274/sharpemu.git
synced 2026-08-08 10:45:52 +08:00
initial commit
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
// Copyright (C) 2026 SharpEmu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
using System.IO;
|
||||
|
||||
namespace SharpEmu.Logging;
|
||||
|
||||
public sealed class ConsoleLogSink : ISharpEmuLogSink
|
||||
{
|
||||
private readonly object _sync = new();
|
||||
|
||||
public ConsoleLogSink(bool useColors = true, bool includeTimestamp = false)
|
||||
{
|
||||
UseColors = useColors;
|
||||
IncludeTimestamp = includeTimestamp;
|
||||
}
|
||||
|
||||
public bool UseColors { get; set; }
|
||||
|
||||
public bool IncludeTimestamp { get; set; }
|
||||
|
||||
public void Write(in LogEntry entry)
|
||||
{
|
||||
lock (_sync)
|
||||
{
|
||||
var writer = entry.Level >= LogLevel.Error ? Console.Error : Console.Out;
|
||||
if (IncludeTimestamp)
|
||||
{
|
||||
writer.Write('[');
|
||||
writer.Write(entry.Timestamp.ToString("HH:mm:ss.fff"));
|
||||
writer.Write(']');
|
||||
}
|
||||
|
||||
var levelLabel = ToLevelLabel(entry.Level);
|
||||
WriteLevelSegment(writer, levelLabel, entry.Level);
|
||||
writer.Write('[');
|
||||
writer.Write(entry.Category);
|
||||
writer.Write(']');
|
||||
writer.Write(' ');
|
||||
writer.Write(entry.SourceFileName);
|
||||
if (entry.SourceLine > 0)
|
||||
{
|
||||
writer.Write(':');
|
||||
writer.Write(entry.SourceLine);
|
||||
}
|
||||
|
||||
writer.Write(' ');
|
||||
WriteMessageSegment(writer, entry.Message);
|
||||
writer.WriteLine();
|
||||
if (entry.Exception is not null)
|
||||
{
|
||||
writer.WriteLine(entry.Exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string ToLevelLabel(LogLevel level)
|
||||
{
|
||||
return level switch
|
||||
{
|
||||
LogLevel.Trace => "TRACE",
|
||||
LogLevel.Debug => "DEBUG",
|
||||
LogLevel.Info => "INFO",
|
||||
LogLevel.Warning => "WARNING",
|
||||
LogLevel.Error => "ERROR",
|
||||
LogLevel.Critical => "CRITICAL",
|
||||
_ => "LOG",
|
||||
};
|
||||
}
|
||||
|
||||
private void WriteLevelSegment(TextWriter writer, string label, LogLevel level)
|
||||
{
|
||||
if (!UseColors)
|
||||
{
|
||||
writer.Write('[');
|
||||
writer.Write(label);
|
||||
writer.Write(']');
|
||||
return;
|
||||
}
|
||||
|
||||
var originalColor = Console.ForegroundColor;
|
||||
Console.ForegroundColor = GetLevelColor(level);
|
||||
writer.Write('[');
|
||||
writer.Write(label);
|
||||
writer.Write(']');
|
||||
Console.ForegroundColor = originalColor;
|
||||
}
|
||||
|
||||
private static ConsoleColor GetLevelColor(LogLevel level)
|
||||
{
|
||||
return level switch
|
||||
{
|
||||
LogLevel.Trace => ConsoleColor.DarkGray,
|
||||
LogLevel.Debug => ConsoleColor.Gray,
|
||||
LogLevel.Info => ConsoleColor.Blue,
|
||||
LogLevel.Warning => ConsoleColor.Yellow,
|
||||
LogLevel.Error => ConsoleColor.Red,
|
||||
LogLevel.Critical => ConsoleColor.DarkRed,
|
||||
_ => ConsoleColor.White,
|
||||
};
|
||||
}
|
||||
|
||||
private void WriteMessageSegment(TextWriter writer, string message)
|
||||
{
|
||||
if (!UseColors || !TryGetMessageColor(message, out var messageColor))
|
||||
{
|
||||
writer.Write(message);
|
||||
return;
|
||||
}
|
||||
|
||||
var originalColor = Console.ForegroundColor;
|
||||
Console.ForegroundColor = messageColor;
|
||||
writer.Write(message);
|
||||
Console.ForegroundColor = originalColor;
|
||||
}
|
||||
|
||||
private static bool TryGetMessageColor(string message, out ConsoleColor color)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(message))
|
||||
{
|
||||
color = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ContainsIgnoreCase(message, "unresolved import") ||
|
||||
ContainsIgnoreCase(message, "unresolved symbol") ||
|
||||
ContainsIgnoreCase(message, "hot_unresolved_imports=") ||
|
||||
ContainsIgnoreCase(message, "unresolved_imports_hit="))
|
||||
{
|
||||
color = ConsoleColor.Red;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ContainsIgnoreCase(message, "syscall") ||
|
||||
ContainsIgnoreCase(message, "UnhandledSyscall"))
|
||||
{
|
||||
color = ConsoleColor.DarkYellow;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ContainsIgnoreCase(message, "Import trace") ||
|
||||
ContainsIgnoreCase(message, "import_stub_return") ||
|
||||
ContainsIgnoreCase(message, "last_import=") ||
|
||||
ContainsIgnoreCase(message, "hot_imports=") ||
|
||||
ContainsIgnoreCase(message, "resolved import"))
|
||||
{
|
||||
color = ConsoleColor.Blue;
|
||||
return true;
|
||||
}
|
||||
|
||||
color = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool ContainsIgnoreCase(string text, string value)
|
||||
{
|
||||
return text.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user