using System; using System.Collections.Generic; using System.Text; using Dalamud.Plugin.Services; using Microsoft.Extensions.Logging; using Serilog.Events; namespace Questionable; internal 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 IExternalScopeProvider? _scopeProvider; private readonly IPluginLog _pluginLog; public DalamudLogger(string? name, IExternalScopeProvider? scopeProvider, IPluginLog pluginLog) { _name = name; _scopeProvider = scopeProvider; _pluginLog = pluginLog; } public IDisposable BeginScope(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(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func 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> enumerable) { { foreach (KeyValuePair 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 _categoryNameFormatter; private IExternalScopeProvider? _scopeProvider; public DalamudLoggerProvider(IPluginLog pluginLog, Func? categoryNameFormatter = null) { _pluginLog = pluginLog; _categoryNameFormatter = categoryNameFormatter ?? ((Func)((string t) => t)); } public ILogger CreateLogger(string categoryName) { return new DalamudLogger(_categoryNameFormatter(categoryName), _scopeProvider, _pluginLog); } public void SetScopeProvider(IExternalScopeProvider scopeProvider) { _scopeProvider = scopeProvider; } public void Dispose() { } }