2023-06-01 13:47:53 +00:00
|
|
|
using Ryujinx.Common.Logging.Targets;
|
2023-02-25 15:07:23 +00:00
|
|
|
using Ryujinx.Common.SystemInterop;
|
2018-04-24 18:57:39 +00:00
|
|
|
using System;
|
2019-02-11 12:00:32 +00:00
|
|
|
using System.Collections.Generic;
|
2018-04-24 18:57:39 +00:00
|
|
|
using System.Diagnostics;
|
|
|
|
using System.Runtime.CompilerServices;
|
2019-01-11 00:11:46 +00:00
|
|
|
using System.Threading;
|
2018-04-24 18:57:39 +00:00
|
|
|
|
2018-10-17 17:15:50 +00:00
|
|
|
namespace Ryujinx.Common.Logging
|
2018-04-24 18:57:39 +00:00
|
|
|
{
|
2018-10-17 17:15:50 +00:00
|
|
|
public static class Logger
|
2018-04-24 18:57:39 +00:00
|
|
|
{
|
2023-06-28 16:41:38 +00:00
|
|
|
private static readonly Stopwatch _time;
|
2018-04-24 18:57:39 +00:00
|
|
|
|
2023-06-28 16:41:38 +00:00
|
|
|
private static readonly bool[] _enabledClasses;
|
2018-04-24 18:57:39 +00:00
|
|
|
|
2023-06-28 16:41:38 +00:00
|
|
|
private static readonly List<ILogTarget> _logTargets;
|
2018-04-24 18:57:39 +00:00
|
|
|
|
2023-02-25 15:07:23 +00:00
|
|
|
private static readonly StdErrAdapter _stdErrAdapter;
|
|
|
|
|
2019-02-11 12:00:32 +00:00
|
|
|
public static event EventHandler<LogEventArgs> Updated;
|
2019-01-31 02:49:15 +00:00
|
|
|
|
2022-12-05 13:47:39 +00:00
|
|
|
public readonly struct Log
|
2020-08-03 23:32:53 +00:00
|
|
|
{
|
|
|
|
internal readonly LogLevel Level;
|
|
|
|
|
|
|
|
internal Log(LogLevel level)
|
|
|
|
{
|
|
|
|
Level = level;
|
|
|
|
}
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
public void PrintMsg(LogClass logClass, string message)
|
|
|
|
{
|
2023-06-28 16:41:38 +00:00
|
|
|
if (_enabledClasses[(int)logClass])
|
2020-08-03 23:32:53 +00:00
|
|
|
{
|
2023-06-28 16:41:38 +00:00
|
|
|
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, "", message)));
|
2020-08-03 23:32:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
public void Print(LogClass logClass, string message, [CallerMemberName] string caller = "")
|
|
|
|
{
|
2023-06-28 16:41:38 +00:00
|
|
|
if (_enabledClasses[(int)logClass])
|
2020-08-03 23:32:53 +00:00
|
|
|
{
|
2023-06-28 16:41:38 +00:00
|
|
|
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, message)));
|
2020-08-03 23:32:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
public void Print(LogClass logClass, string message, object data, [CallerMemberName] string caller = "")
|
|
|
|
{
|
2023-06-28 16:41:38 +00:00
|
|
|
if (_enabledClasses[(int)logClass])
|
2020-08-03 23:32:53 +00:00
|
|
|
{
|
2023-06-28 16:41:38 +00:00
|
|
|
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, message), data));
|
2020-08-03 23:32:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-01 13:47:53 +00:00
|
|
|
[StackTraceHidden]
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
public void PrintStack(LogClass logClass, string message, [CallerMemberName] string caller = "")
|
|
|
|
{
|
2023-06-28 16:41:38 +00:00
|
|
|
if (_enabledClasses[(int)logClass])
|
2023-06-01 13:47:53 +00:00
|
|
|
{
|
2023-06-28 16:41:38 +00:00
|
|
|
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, message), new StackTrace(true)));
|
2023-06-01 13:47:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-03 23:32:53 +00:00
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
public void PrintStub(LogClass logClass, string message = "", [CallerMemberName] string caller = "")
|
|
|
|
{
|
2023-06-28 16:41:38 +00:00
|
|
|
if (_enabledClasses[(int)logClass])
|
2020-08-03 23:32:53 +00:00
|
|
|
{
|
2023-06-28 16:41:38 +00:00
|
|
|
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, "Stubbed. " + message)));
|
2020-08-03 23:32:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
public void PrintStub(LogClass logClass, object data, [CallerMemberName] string caller = "")
|
|
|
|
{
|
2023-06-28 16:41:38 +00:00
|
|
|
if (_enabledClasses[(int)logClass])
|
2020-08-03 23:32:53 +00:00
|
|
|
{
|
2023-06-28 16:41:38 +00:00
|
|
|
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, "Stubbed."), data));
|
2020-08-03 23:32:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
public void PrintStub(LogClass logClass, string message, object data, [CallerMemberName] string caller = "")
|
|
|
|
{
|
2023-06-28 16:41:38 +00:00
|
|
|
if (_enabledClasses[(int)logClass])
|
2020-08-03 23:32:53 +00:00
|
|
|
{
|
2023-06-28 16:41:38 +00:00
|
|
|
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, "Stubbed. " + message), data));
|
2020-08-03 23:32:53 +00:00
|
|
|
}
|
2023-02-25 15:07:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
public void PrintRawMsg(string message)
|
|
|
|
{
|
2023-06-28 16:41:38 +00:00
|
|
|
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, message));
|
2023-02-25 15:07:23 +00:00
|
|
|
}
|
2020-08-03 23:32:53 +00:00
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2023-06-28 16:41:38 +00:00
|
|
|
private static string FormatMessage(LogClass logClass, string caller, string message) => $"{logClass} {caller}: {message}";
|
2020-08-03 23:32:53 +00:00
|
|
|
}
|
|
|
|
|
2023-06-28 16:41:38 +00:00
|
|
|
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; }
|
2020-08-03 23:32:53 +00:00
|
|
|
public static Log? AccessLog { get; private set; }
|
2023-06-28 16:41:38 +00:00
|
|
|
public static Log? Stub { get; private set; }
|
|
|
|
public static Log? Trace { get; private set; }
|
|
|
|
public static Log Notice { get; } // Always enabled
|
2020-08-03 23:32:53 +00:00
|
|
|
|
2018-10-17 17:15:50 +00:00
|
|
|
static Logger()
|
2018-04-24 18:57:39 +00:00
|
|
|
{
|
2023-06-28 16:41:38 +00:00
|
|
|
_enabledClasses = new bool[Enum.GetNames<LogClass>().Length];
|
2018-04-24 18:57:39 +00:00
|
|
|
|
2023-06-28 16:41:38 +00:00
|
|
|
for (int index = 0; index < _enabledClasses.Length; index++)
|
2018-04-24 18:57:39 +00:00
|
|
|
{
|
2023-06-28 16:41:38 +00:00
|
|
|
_enabledClasses[index] = true;
|
2018-04-24 18:57:39 +00:00
|
|
|
}
|
|
|
|
|
2023-06-28 16:41:38 +00:00
|
|
|
_logTargets = new List<ILogTarget>();
|
2019-02-11 12:00:32 +00:00
|
|
|
|
2023-06-28 16:41:38 +00:00
|
|
|
_time = Stopwatch.StartNew();
|
2019-12-21 19:52:31 +00:00
|
|
|
|
|
|
|
// Logger should log to console by default
|
|
|
|
AddTarget(new AsyncLogTargetWrapper(
|
|
|
|
new ConsoleLogTarget("console"),
|
|
|
|
1000,
|
2020-06-09 23:22:54 +00:00
|
|
|
AsyncLogTargetOverflowAction.Discard));
|
2020-08-03 23:32:53 +00:00
|
|
|
|
|
|
|
Notice = new Log(LogLevel.Notice);
|
2023-06-01 13:47:53 +00:00
|
|
|
|
2020-08-30 16:51:53 +00:00
|
|
|
// Enable important log levels before configuration is loaded
|
|
|
|
Error = new Log(LogLevel.Error);
|
|
|
|
Warning = new Log(LogLevel.Warning);
|
|
|
|
Info = new Log(LogLevel.Info);
|
2022-02-18 00:08:07 +00:00
|
|
|
Trace = new Log(LogLevel.Trace);
|
2023-02-25 15:07:23 +00:00
|
|
|
|
|
|
|
_stdErrAdapter = new StdErrAdapter();
|
2019-01-11 00:11:46 +00:00
|
|
|
}
|
|
|
|
|
2019-09-19 23:59:48 +00:00
|
|
|
public static void RestartTime()
|
|
|
|
{
|
2023-06-28 16:41:38 +00:00
|
|
|
_time.Restart();
|
2019-09-19 23:59:48 +00:00
|
|
|
}
|
|
|
|
|
2019-12-21 19:52:31 +00:00
|
|
|
private static ILogTarget GetTarget(string targetName)
|
|
|
|
{
|
2023-06-28 16:41:38 +00:00
|
|
|
foreach (var target in _logTargets)
|
2019-12-21 19:52:31 +00:00
|
|
|
{
|
|
|
|
if (target.Name.Equals(targetName))
|
|
|
|
{
|
|
|
|
return target;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2019-02-11 12:00:32 +00:00
|
|
|
public static void AddTarget(ILogTarget target)
|
|
|
|
{
|
2023-06-28 16:41:38 +00:00
|
|
|
_logTargets.Add(target);
|
2019-02-11 12:00:32 +00:00
|
|
|
|
|
|
|
Updated += target.Log;
|
|
|
|
}
|
|
|
|
|
2019-12-21 19:52:31 +00:00
|
|
|
public static void RemoveTarget(string target)
|
|
|
|
{
|
|
|
|
ILogTarget logTarget = GetTarget(target);
|
|
|
|
|
|
|
|
if (logTarget != null)
|
|
|
|
{
|
|
|
|
Updated -= logTarget.Log;
|
|
|
|
|
2023-06-28 16:41:38 +00:00
|
|
|
_logTargets.Remove(logTarget);
|
2019-12-21 19:52:31 +00:00
|
|
|
|
|
|
|
logTarget.Dispose();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-11 12:00:32 +00:00
|
|
|
public static void Shutdown()
|
|
|
|
{
|
|
|
|
Updated = null;
|
|
|
|
|
2023-02-25 15:07:23 +00:00
|
|
|
_stdErrAdapter.Dispose();
|
|
|
|
|
2023-06-28 16:41:38 +00:00
|
|
|
foreach (var target in _logTargets)
|
2019-02-11 12:00:32 +00:00
|
|
|
{
|
|
|
|
target.Dispose();
|
|
|
|
}
|
|
|
|
|
2023-06-28 16:41:38 +00:00
|
|
|
_logTargets.Clear();
|
2019-02-11 12:00:32 +00:00
|
|
|
}
|
|
|
|
|
2020-08-03 23:32:53 +00:00
|
|
|
public static IReadOnlyCollection<LogLevel> GetEnabledLevels()
|
2018-04-24 18:57:39 +00:00
|
|
|
{
|
2023-06-28 16:41:38 +00:00
|
|
|
var logs = new[] { Debug, Info, Warning, Error, Guest, AccessLog, Stub, Trace };
|
|
|
|
List<LogLevel> levels = new(logs.Length);
|
2020-08-03 23:32:53 +00:00
|
|
|
foreach (var log in logs)
|
2019-01-11 00:11:46 +00:00
|
|
|
{
|
2020-08-03 23:32:53 +00:00
|
|
|
if (log.HasValue)
|
|
|
|
{
|
|
|
|
levels.Add(log.Value.Level);
|
|
|
|
}
|
2019-01-11 00:11:46 +00:00
|
|
|
}
|
2020-08-03 23:32:53 +00:00
|
|
|
|
|
|
|
return levels;
|
2018-04-24 18:57:39 +00:00
|
|
|
}
|
|
|
|
|
2020-08-03 23:32:53 +00:00
|
|
|
public static void SetEnable(LogLevel logLevel, bool enabled)
|
2018-04-24 18:57:39 +00:00
|
|
|
{
|
2020-08-03 23:32:53 +00:00
|
|
|
switch (logLevel)
|
2018-04-24 18:57:39 +00:00
|
|
|
{
|
2023-06-28 16:41:38 +00:00
|
|
|
#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;
|
2020-08-03 23:32:53 +00:00
|
|
|
default: throw new ArgumentException("Unknown Log Level");
|
2023-06-28 16:41:38 +00:00
|
|
|
#pragma warning restore IDE0055
|
2018-04-24 18:57:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-03 23:32:53 +00:00
|
|
|
public static void SetEnable(LogClass logClass, bool enabled)
|
2018-04-24 18:57:39 +00:00
|
|
|
{
|
2023-06-28 16:41:38 +00:00
|
|
|
_enabledClasses[(int)logClass] = enabled;
|
2018-04-24 18:57:39 +00:00
|
|
|
}
|
|
|
|
}
|
2023-06-28 16:41:38 +00:00
|
|
|
}
|