Search code examples
asp.net-corelogging

ASP.net Core: How to inject header values into custom logger?


If the request HTTP header has a value like CorrelationId, how can my custom Logger get this value so that all log entries will have the CorrelationId?

public ILogger CreateLogger(string categoryName) cannot be change to inject any parameters and has to implement ILoggerProvider


Solution

  • You could register IHttpContextAccessor in ConfigureService and pass the instance of it to custom logger.

    Then you could get the header value by using

        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;
            }
        }