qstbak/LLib/LLib.Logging/DalamudLoggerProvider.cs
2026-08-17 20:29:32 +10:00

160 lines
3.9 KiB
C#

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using Dalamud.Plugin.Services;
using Microsoft.Extensions.Logging;
using Serilog.Events;
namespace LLib.Logging;
public sealed class DalamudLoggerProvider : ILoggerProvider, IDisposable, ISupportExternalScope
{
private sealed class DalamudLogger : ILogger
{
private sealed class NullScope : IDisposable
{
public static NullScope Instance { get; } = new NullScope();
private NullScope()
{
}
public void Dispose()
{
}
}
private readonly string? _name;
private readonly DalamudLoggerProvider _provider;
private readonly IPluginLog _pluginLog;
private IExternalScopeProvider? ScopeProvider => _provider._scopeProvider;
public DalamudLogger(string? name, DalamudLoggerProvider provider, IPluginLog pluginLog)
{
_name = name;
_provider = provider;
_pluginLog = pluginLog;
}
public IDisposable BeginScope<TState>(TState state) where TState : notnull
{
return ScopeProvider?.Push(state) ?? NullScope.Instance;
}
public bool IsEnabled(LogLevel logLevel)
{
if (logLevel == LogLevel.None)
{
return false;
}
return ToSerilogLevel(logLevel) >= _pluginLog.MinimumLogLevel;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
{
if (!IsEnabled(logLevel))
{
return;
}
ArgumentNullException.ThrowIfNull(formatter, "formatter");
LogEventLevel level = ToSerilogLevel(logLevel);
StringBuilder stringBuilder = new StringBuilder();
ScopeProvider?.ForEachScope(delegate(object? scope, StringBuilder builder)
{
if (scope is IEnumerable<KeyValuePair<string, object>> enumerable)
{
{
foreach (KeyValuePair<string, object> item in enumerable)
{
builder.Append('<').Append(item.Key).Append('=')
.Append(item.Value)
.Append("> ");
}
return;
}
}
if (scope != null)
{
builder.Append('<').Append(scope).Append("> ");
}
}, stringBuilder);
if (!string.IsNullOrEmpty(_name))
{
stringBuilder.Append(_name).Append(": ");
}
stringBuilder.Append(formatter(state, null));
_pluginLog.Write(level, exception, stringBuilder.ToString());
}
private static LogEventLevel ToSerilogLevel(LogLevel logLevel)
{
return logLevel switch
{
LogLevel.Trace => LogEventLevel.Verbose,
LogLevel.Debug => LogEventLevel.Debug,
LogLevel.Information => LogEventLevel.Information,
LogLevel.Warning => LogEventLevel.Warning,
LogLevel.Error => LogEventLevel.Error,
LogLevel.Critical => LogEventLevel.Fatal,
_ => throw new ArgumentOutOfRangeException("logLevel", logLevel, null),
};
}
}
private readonly IPluginLog _pluginLog;
private readonly Func<string, string?> _categoryNameFormatter;
private IExternalScopeProvider? _scopeProvider;
public DalamudLoggerProvider(IPluginLog pluginLog, Func<string, string?>? categoryNameFormatter = null)
{
ArgumentNullException.ThrowIfNull(pluginLog, "pluginLog");
_pluginLog = pluginLog;
_categoryNameFormatter = categoryNameFormatter ?? ((Func<string, string>)((string t) => t));
}
public ILogger CreateLogger(string categoryName)
{
string name = _categoryNameFormatter(categoryName);
if (LooksObfuscated(name))
{
name = null;
}
return new DalamudLogger(name, this, _pluginLog);
}
private static bool LooksObfuscated(string? name)
{
if (string.IsNullOrEmpty(name))
{
return false;
}
foreach (char c in name)
{
if (char.IsControl(c))
{
return true;
}
UnicodeCategory unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c);
if (((uint)(unicodeCategory - 15) <= 2u || unicodeCategory == UnicodeCategory.OtherNotAssigned) ? true : false)
{
return true;
}
}
return false;
}
public void SetScopeProvider(IExternalScopeProvider scopeProvider)
{
_scopeProvider = scopeProvider;
}
public void Dispose()
{
}
}