有没有一种方法可以将 LogContext 调用“注入”到项目中的所有 Serilog 日志调用中? 我想添加一个 ExecutionContext 属性,它只是在共享类库中生成的十六进制字符串。 我在 Microsoft.Extensions.Logging 中使用 Serilog,也在 Asp.Net Core API 项目中使用 Serilog 请求日志记录。
创建一个实现
ILoggerProvider
接口的类,它将ExecutionContext
属性添加到日志上下文中。
using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Core;
using Serilog.Events;
public class CustomLoggerProvider : ILoggerProvider
{
private readonly ILoggerProvider _innerProvider;
private readonly LogEventLevel _minimumLogLevel;
public CustomLoggerProvider(ILoggerProvider innerProvider, LogEventLevel minimumLogLevel = LogEventLevel.Information)
{
_innerProvider = innerProvider;
_minimumLogLevel = minimumLogLevel;
}
public ILogger CreateLogger(string categoryName)
{
var logger = _innerProvider.CreateLogger(categoryName);
// Add the ExecutionContext property to the log context
var executionContext = SharedClassLibrary.GetExecutionContext();
var logContext = LogContext.PushProperty("ExecutionContext", executionContext);
return new CustomLogger(logger, logContext, _minimumLogLevel);
}
public void Dispose()
{
_innerProvider.Dispose();
}
}
Create a custom
ILogger
implementation that wraps the default ILogger and uses the LogContext to add the ExecutionContext property:
public class CustomLogger : ILogger
{
private readonly ILogger _innerLogger;
private readonly LogContext _logContext;
private readonly LogEventLevel _minimumLogLevel;
public CustomLogger(ILogger innerLogger, LogContext logContext, LogEventLevel minimumLogLevel = LogEventLevel.Information)
{
_innerLogger = innerLogger;
_logContext = logContext;
_minimumLogLevel = minimumLogLevel;
}
public IDisposable BeginScope<TState>(TState state)
{
return _innerLogger.BeginScope(state);
}
public bool IsEnabled(LogLevel logLevel)
{
return _innerLogger.IsEnabled(logLevel) && logLevel >= ConvertLogLevel(_minimumLogLevel);
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
if (!IsEnabled(logLevel))
{
return;
}
// Use the LogContext to add the ExecutionContext property
using (_logContext.PushProperty("ExecutionContext", SharedClassLibrary.GetExecutionContext()))
{
_innerLogger.Log(logLevel, eventId, state, exception, formatter);
}
}
private static LogEventLevel ConvertLogLevel(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(nameof(logLevel), logLevel, "Invalid log level.")
};
}
}
在Startup类的
ConfigureLogging
方法中注册自定义ILoggerProvider:
using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Events;
public class Startup
{
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
{
// Create the default Serilog logger
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.Enrich.FromLogContext()
.WriteTo.Console()
.CreateLogger();
// Register the custom logger provider that adds the ExecutionContext property
loggerFactory.AddProvider(new CustomLoggerProvider(new SerilogLoggerProvider(), LogEvent