using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace PCL.Core.Logging; /// /// Microsoft.Extensions.Logging.ILogger 适配器 /// 将现有的 Logger 包装为标准的 ILogger 接口实现 /// public class LoggerAdapter(Logger logger, string categoryName) : ILogger { private readonly Logger _innerLogger = logger ?? throw new ArgumentNullException(nameof(logger)); private readonly string _categoryName = categoryName ?? throw new ArgumentNullException(nameof(categoryName)); private static readonly AsyncLocal> _ScopeStack = new(); IDisposable ILogger.BeginScope(TState state) { _ScopeStack.Value ??= new Stack(); _ScopeStack.Value.Push(state); return new ScopeDisposable(state); } #pragma warning disable CS9113 // 参数未读。 private class ScopeDisposable(object state) : IDisposable { private bool _disposed; public void Dispose() { if (_disposed) return; if (_ScopeStack.Value is { Count: > 0 }) { #if DEBUG var popped = _ScopeStack.Value.Pop(); if (!ReferenceEquals(popped, state)) { throw new InvalidOperationException("Scope disposal order mismatch."); } #else _ = _ScopeStack.Value.Pop(); #endif } _disposed = true; } } public bool IsEnabled(Microsoft.Extensions.Logging.LogLevel level) => true; public void Log(Microsoft.Extensions.Logging.LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) { if (!IsEnabled(logLevel)) return; ArgumentNullException.ThrowIfNull(formatter); var originalMessage = formatter(state, exception); var sb = new StringBuilder(); // 类别名称 if (!string.IsNullOrEmpty(_categoryName)) { sb.Append('[').Append(_categoryName).Append("] "); } // 事件 ID if (eventId.Id != 0 || !string.IsNullOrEmpty(eventId.Name)) { sb.Append("[EventId:"); if (!string.IsNullOrEmpty(eventId.Name)) { sb.Append(eventId.Id).Append(':').Append(eventId.Name); } else { sb.Append(eventId.Id); } sb.Append("] "); } // 上下文信息 var scopeContext = _BuildScopeContext(); if (!string.IsNullOrEmpty(scopeContext)) { sb.Append('[').Append(_categoryName).Append("] "); } sb.Append(originalMessage); var finalMessage = sb.ToString(); // 日志级别 switch (logLevel) { case Microsoft.Extensions.Logging.LogLevel.Trace: _innerLogger.Trace(finalMessage); break; case Microsoft.Extensions.Logging.LogLevel.Debug: _innerLogger.Debug(finalMessage); break; case Microsoft.Extensions.Logging.LogLevel.Information: _innerLogger.Info(finalMessage); break; case Microsoft.Extensions.Logging.LogLevel.Warning: _innerLogger.Warn(finalMessage); break; case Microsoft.Extensions.Logging.LogLevel.Error: _innerLogger.Error(finalMessage); break; case Microsoft.Extensions.Logging.LogLevel.Critical: _innerLogger.Fatal(finalMessage); break; } if (exception is not null) { var exceptionMessage = $"Exception: {exception}"; _innerLogger.Log($"[{_categoryName}] {exceptionMessage}"); } } private string _BuildScopeContext() { var stack = _ScopeStack.Value; if (stack is null || stack.Count == 0) return string.Empty; var scopes = stack.AsEnumerable().Reverse(); return string.Join(" => ", scopes.Select(s => s.ToString())); } }