mirror of
https://github.com/ryujinx-mirror/ryujinx.git
synced 2024-12-22 14:26:17 +00:00
6c90d50c8e
* Redact usernames from logs * Changed internal vars to private and applied naming rules * Use Directory.GetParent() instead of DirectoryInfo * Update src/Ryujinx.Common/Logging/Logger.cs --------- Co-authored-by: Ac_K <Acoustik666@gmail.com>
247 lines
9.0 KiB
C#
247 lines
9.0 KiB
C#
using Ryujinx.Common.Logging.Targets;
|
|
using Ryujinx.Common.SystemInterop;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
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
|
|
{
|
|
private static readonly string _homeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
|
|
private static readonly string _homeDirRedacted = Path.Combine(Directory.GetParent(_homeDir).FullName, "[redacted]");
|
|
|
|
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)
|
|
{
|
|
message = message.Replace(_homeDir, _homeDirRedacted);
|
|
|
|
return $"{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;
|
|
}
|
|
}
|
|
}
|