ASP.net Core:如何将标头值注入自定义记录器?

时间:2019-08-13 23:48:29

标签: asp.net-core logging

如果请求HTTP标头具有类似CorrelationId的值,我的自定义Logger如何获得该值,以便所有日志条目都具有CorrelationId?

公共ILogger CreateLogger(字符串类别名称) 不能更改以注入任何参数,而必须实现 ILoggerProvider

2 个答案:

答案 0 :(得分:1)

您可以在ConfigureService中注册IHttpContextAccessor并将其实例传递给自定义记录器。

然后您可以使用

获取标头值
var header = _accessor.HttpContext.Request.Headers["CorrelationId"].ToString()

1.startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}

public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory, IServiceProvider serviceProvider)
{
    loggerFactory.AddCustomLogger(serviceProvider.GetService<IHttpContextAccessor>());

}

2.CustomLogger.cs:

public class CustomLogProvider : ILoggerProvider
{

    private readonly Func<string, LogLevel, bool> _filter;
    private readonly IHttpContextAccessor _accessor;//DI

    public CustomLogProvider(Func<string, LogLevel, bool> filter, IHttpContextAccessor accessor)
    {
        _filter = filter;
        _accessor = accessor;
    }

    public ILogger CreateLogger(string categoryName)
    {
        return new CustomLogger(categoryName, _filter, _accessor);
    }

    public void Dispose()
    {
    }
}

public class CustomLogger : ILogger
{
    private string _categoryName;
    private Func<string, LogLevel, bool> _filter;
    private readonly IHttpContextAccessor _accessor;

    public CustomLogger(string categoryName, Func<string, LogLevel, bool> filter, IHttpContextAccessor accessor)
    {
        _categoryName = categoryName;
        _filter = filter;
        _accessor = accessor;
    }

    public IDisposable BeginScope<TState>(TState state)
    {
        return null;
    }

    public bool IsEnabled(LogLevel logLevel)
    {
        return (_filter == null || _filter(_categoryName, logLevel));
    }

    public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
    {
        if (!IsEnabled(logLevel))
        {
            return;
        }

        if (formatter == null)
        {
            throw new ArgumentNullException(nameof(formatter));
        }

        var message = formatter(state, exception);

        if (string.IsNullOrEmpty(message))
        {
            return;
        }

        message = $"{ logLevel }: {message}";

        if (exception != null)
        {
            message += Environment.NewLine + Environment.NewLine + exception.ToString();
        }
        if (_accessor.HttpContext != null) // you should check HttpContext 
        {
            var headers = _accessor.HttpContext.Request.Headers["CorrelationId"].ToString();
            if(headers != "")
            {
                message += Environment.NewLine + headers + Environment.NewLine + _accessor.HttpContext.Request.Path;
                Console.ForegroundColor = ConsoleColor.DarkGreen;
                Console.WriteLine(message);
            }

        }
        // your implementation

    }

}
public static class CustomLoggerExtensions
{
    public static ILoggerFactory AddCustomLogger(this ILoggerFactory factory, IHttpContextAccessor accessor,
                                          Func<string, LogLevel, bool> filter = null)
    {
        factory.AddProvider(new CustomLogProvider(filter, accessor));
        return factory;
    }
}

答案 1 :(得分:0)

我最后使用的解决方案是实现一个具有相关ID的基类。 创建了一个客户Controller工厂类,以从标头中获取相关性ID并将其设置在基类上。 然后,记录器可以使用基类中的值。

示例代码位于此处。 https://github.com/xavierjohn/AspCoreApplicationPart/blob/PlusConfigureCreatedController/AspCoreApplicationPart/MyCustomControllerFactory.cs