Sigurd Garshol
Sigurd Garshol

Reputation: 1544

Adding extra properties to ILogger<T> structured logging

Using ILogger<T>, is there a way to add log properties in addition to the ones covered by the message template?

For example:

_logger.LogInformation("Order {OrderNumber} was registered.", orderNumber);
// Appending extra information to this log entry would be neat:
// OrderOriginSystem = InStoreSupport
// Supervisor = Duncan P.
// StoreLocationCode = ca-north-12

I know Serilog allows various approaches for appending additional properties to log statements, and these seem to play nice with ILogger<T>, e.g.:

using (LogContext.PushProperty("OrderOriginSystem ", orderOriginSystem))
using (LogContext.PushProperty("Supervisor", supervisor))
using (LogContext.PushProperty("StoreLocationCode", slc))
{
    _logger.LogInformation("Order {OrderNumber} was registered.", orderNumber);
}

But I'd like to avoid having to commit to Serilog directly in my code, and hope to instead rely on ILogger<T> throughout.

Is there some trick I've missed?

Upvotes: 1

Views: 694

Answers (2)

Qiang Fu
Qiang Fu

Reputation: 8411

Maybe you could try implement customLogger to enrich with property depending on the T:

    public class MyLogger<T> : ILogger<T>
    {
        private readonly Serilog.ILogger _logger;

        public MyLogger()
        {
            var loggerConfiguration = new LoggerConfiguration();
            //check the type of T
            if (typeof(T) == typeof(WeatherForecastController))
            {
                loggerConfiguration
                    .WriteTo.Console()
                    .Enrich.WithProperty("OrderOriginSystem ", "InStoreSupport");
            }
            _logger = loggerConfiguration.CreateLogger();
        }

        public IDisposable? BeginScope<TState>(TState state) where TState : notnull
        {
            throw new NotImplementedException();
        }

        public bool IsEnabled(LogLevel logLevel) => _logger.IsEnabled((LogEventLevel)logLevel);

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

            _logger.Write((LogEventLevel)logLevel, exception, formatter(state, exception));
        }
    }

Then in program.cs (will not need configure serilog in program.cs)

builder.Services.AddSingleton(typeof(ILogger<>), typeof(MyLogger<>));

Upvotes: 0

Yehor Androsov
Yehor Androsov

Reputation: 6162

ILogger's equivalent of Serilog's PushProperty is BeginScope.

Here is a great article about it

using (logger.BeginScope(new Dictionary<string, object>{
    ["CustomerId"] = 12345,
    ["OrderId"] = 54
}))
{
    logger.LogInformation("Processing credit card payment");
}

Upvotes: 2

Related Questions