将 Serilog LogContext 添加到每个日志调用

问题描述 投票:0回答:1

有没有一种方法可以将 LogContext 调用“注入”到项目中的所有 Serilog 日志调用中? 我想添加一个 ExecutionContext 属性,它只是在共享类库中生成的十六进制字符串。 我在 Microsoft.Extensions.Logging 中使用 Serilog,也在 Asp.Net Core API 项目中使用 Serilog 请求日志记录。

.net-6.0 serilog
1个回答
0
投票

创建一个实现

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

© www.soinside.com 2019 - 2024. All rights reserved.