* dotnet format style --severity info Some changes were manually reverted. * dotnet format analyzers --serverity info Some changes have been minimally adapted. * Restore a few unused methods and variables * Silence dotnet format IDE0060 warnings * Silence dotnet format IDE0059 warnings * Address or silence dotnet format IDE1006 warnings * Address dotnet format CA1816 warnings * Address or silence dotnet format CA2211 warnings * Silence CA1806 and CA1834 issues * Fix formatting for switch expressions * Address most dotnet format whitespace warnings * Apply dotnet format whitespace formatting A few of them have been manually reverted and the corresponding warning was silenced * Revert formatting changes for while and for-loops * Format if-blocks correctly * Run dotnet format whitespace after rebase * Run dotnet format style after rebase * Run dotnet format analyzers after rebase * Run dotnet format after rebase and remove unused usings - analyzers - style - whitespace * Add comments to disabled warnings * Remove a few unused parameters * Replace MmeShadowScratch with Array256<uint> * Simplify properties and array initialization, Use const when possible, Remove trailing commas * Run dotnet format after rebase * Address IDE0251 warnings * Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas" This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e. * dotnet format whitespace after rebase * First dotnet format pass * Second dotnet format pass * Fix build issues * Fix StructArrayHelpers.cs * Apply suggestions from code review Co-authored-by: Ac_K <Acoustik666@gmail.com> * Fix return statements * Fix naming rule violations * Update src/Ryujinx.Common/Utilities/StreamUtils.cs Co-authored-by: Ac_K <Acoustik666@gmail.com> * Add trailing commas * Address review feedback * Address review feedback * Rename remaining type parameters to TKey and TValue * Fix manual formatting for logging levels * Fix spacing before comments --------- Co-authored-by: Ac_K <Acoustik666@gmail.com>
238 lines
8.6 KiB
C#
238 lines
8.6 KiB
C#
using Ryujinx.Common.Logging.Targets;
|
|
using Ryujinx.Common.SystemInterop;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Threading;
|
|
|
|
namespace Ryujinx.Common.Logging
|
|
{
|
|
public static class Logger
|
|
{
|
|
private static readonly Stopwatch _time;
|
|
|
|
private static readonly bool[] _enabledClasses;
|
|
|
|
private static readonly List<ILogTarget> _logTargets;
|
|
|
|
private static readonly StdErrAdapter _stdErrAdapter;
|
|
|
|
public static event EventHandler<LogEventArgs> Updated;
|
|
|
|
public readonly struct Log
|
|
{
|
|
internal readonly LogLevel Level;
|
|
|
|
internal Log(LogLevel level)
|
|
{
|
|
Level = level;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void PrintMsg(LogClass logClass, string message)
|
|
{
|
|
if (_enabledClasses[(int)logClass])
|
|
{
|
|
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, "", message)));
|
|
}
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void Print(LogClass logClass, string message, [CallerMemberName] string caller = "")
|
|
{
|
|
if (_enabledClasses[(int)logClass])
|
|
{
|
|
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, message)));
|
|
}
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void Print(LogClass logClass, string message, object data, [CallerMemberName] string caller = "")
|
|
{
|
|
if (_enabledClasses[(int)logClass])
|
|
{
|
|
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, message), data));
|
|
}
|
|
}
|
|
|
|
[StackTraceHidden]
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void PrintStack(LogClass logClass, string message, [CallerMemberName] string caller = "")
|
|
{
|
|
if (_enabledClasses[(int)logClass])
|
|
{
|
|
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, message), new StackTrace(true)));
|
|
}
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void PrintStub(LogClass logClass, string message = "", [CallerMemberName] string caller = "")
|
|
{
|
|
if (_enabledClasses[(int)logClass])
|
|
{
|
|
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, "Stubbed. " + message)));
|
|
}
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void PrintStub(LogClass logClass, object data, [CallerMemberName] string caller = "")
|
|
{
|
|
if (_enabledClasses[(int)logClass])
|
|
{
|
|
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, "Stubbed."), data));
|
|
}
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void PrintStub(LogClass logClass, string message, object data, [CallerMemberName] string caller = "")
|
|
{
|
|
if (_enabledClasses[(int)logClass])
|
|
{
|
|
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, "Stubbed. " + message), data));
|
|
}
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void PrintRawMsg(string message)
|
|
{
|
|
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, message));
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
private static string FormatMessage(LogClass logClass, string caller, string message) => $"{logClass} {caller}: {message}";
|
|
}
|
|
|
|
public static Log? Debug { get; private set; }
|
|
public static Log? Info { get; private set; }
|
|
public static Log? Warning { get; private set; }
|
|
public static Log? Error { get; private set; }
|
|
public static Log? Guest { get; private set; }
|
|
public static Log? AccessLog { get; private set; }
|
|
public static Log? Stub { get; private set; }
|
|
public static Log? Trace { get; private set; }
|
|
public static Log Notice { get; } // Always enabled
|
|
|
|
static Logger()
|
|
{
|
|
_enabledClasses = new bool[Enum.GetNames<LogClass>().Length];
|
|
|
|
for (int index = 0; index < _enabledClasses.Length; index++)
|
|
{
|
|
_enabledClasses[index] = true;
|
|
}
|
|
|
|
_logTargets = new List<ILogTarget>();
|
|
|
|
_time = Stopwatch.StartNew();
|
|
|
|
// Logger should log to console by default
|
|
AddTarget(new AsyncLogTargetWrapper(
|
|
new ConsoleLogTarget("console"),
|
|
1000,
|
|
AsyncLogTargetOverflowAction.Discard));
|
|
|
|
Notice = new Log(LogLevel.Notice);
|
|
|
|
// Enable important log levels before configuration is loaded
|
|
Error = new Log(LogLevel.Error);
|
|
Warning = new Log(LogLevel.Warning);
|
|
Info = new Log(LogLevel.Info);
|
|
Trace = new Log(LogLevel.Trace);
|
|
|
|
_stdErrAdapter = new StdErrAdapter();
|
|
}
|
|
|
|
public static void RestartTime()
|
|
{
|
|
_time.Restart();
|
|
}
|
|
|
|
private static ILogTarget GetTarget(string targetName)
|
|
{
|
|
foreach (var target in _logTargets)
|
|
{
|
|
if (target.Name.Equals(targetName))
|
|
{
|
|
return target;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public static void AddTarget(ILogTarget target)
|
|
{
|
|
_logTargets.Add(target);
|
|
|
|
Updated += target.Log;
|
|
}
|
|
|
|
public static void RemoveTarget(string target)
|
|
{
|
|
ILogTarget logTarget = GetTarget(target);
|
|
|
|
if (logTarget != null)
|
|
{
|
|
Updated -= logTarget.Log;
|
|
|
|
_logTargets.Remove(logTarget);
|
|
|
|
logTarget.Dispose();
|
|
}
|
|
}
|
|
|
|
public static void Shutdown()
|
|
{
|
|
Updated = null;
|
|
|
|
_stdErrAdapter.Dispose();
|
|
|
|
foreach (var target in _logTargets)
|
|
{
|
|
target.Dispose();
|
|
}
|
|
|
|
_logTargets.Clear();
|
|
}
|
|
|
|
public static IReadOnlyCollection<LogLevel> GetEnabledLevels()
|
|
{
|
|
var logs = new[] { Debug, Info, Warning, Error, Guest, AccessLog, Stub, Trace };
|
|
List<LogLevel> levels = new(logs.Length);
|
|
foreach (var log in logs)
|
|
{
|
|
if (log.HasValue)
|
|
{
|
|
levels.Add(log.Value.Level);
|
|
}
|
|
}
|
|
|
|
return levels;
|
|
}
|
|
|
|
public static void SetEnable(LogLevel logLevel, bool enabled)
|
|
{
|
|
switch (logLevel)
|
|
{
|
|
#pragma warning disable IDE0055 // Disable formatting
|
|
case LogLevel.Debug : Debug = enabled ? new Log(LogLevel.Debug) : new Log?(); break;
|
|
case LogLevel.Info : Info = enabled ? new Log(LogLevel.Info) : new Log?(); break;
|
|
case LogLevel.Warning : Warning = enabled ? new Log(LogLevel.Warning) : new Log?(); break;
|
|
case LogLevel.Error : Error = enabled ? new Log(LogLevel.Error) : new Log?(); break;
|
|
case LogLevel.Guest : Guest = enabled ? new Log(LogLevel.Guest) : new Log?(); break;
|
|
case LogLevel.AccessLog : AccessLog = enabled ? new Log(LogLevel.AccessLog) : new Log?(); break;
|
|
case LogLevel.Stub : Stub = enabled ? new Log(LogLevel.Stub) : new Log?(); break;
|
|
case LogLevel.Trace : Trace = enabled ? new Log(LogLevel.Trace) : new Log?(); break;
|
|
default: throw new ArgumentException("Unknown Log Level");
|
|
#pragma warning restore IDE0055
|
|
}
|
|
}
|
|
|
|
public static void SetEnable(LogClass logClass, bool enabled)
|
|
{
|
|
_enabledClasses[(int)logClass] = enabled;
|
|
}
|
|
}
|
|
}
|