Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Always log context data using serilog

I am using Serilog for logging. For every log i want to log context information like username and some other context information. So i created wrapper with static method as below

public static class MyLogger
{    
    public static void Error(Exception ex, string messageTemplate, params object[] propertyvalues)
    {
        var properties = new List<object>(propertyvalues);
        if (HttpContext.Current != null && HttpContext.Current.User != null && HttpContext.Current.User.Identity != null)
        {
            var contextInfo = new
            {                    
                UserName = HttpContext.Current.User.Identity.Name
            };
            messageTemplate += "{@ContextInfo}";
            properties.Add(contextInfo);
        }

        //serilog log
        Log.Error(ex, messageTemplate, properties.ToArray());
    }
}

Then log the error as

      MyLogger.Error(exception,"{@SomeMetadata}",metadata);

this is working, but is there any better way to include context information with serilog

Update1

So i created an enricher based on suggestion

public class HttpContextEnricher: ILogEventEnricher
{
    LogEventProperty _cachedProperty;

    public const string EnvironmentUserNamePropertyName = "UserName";

    public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
    {
        _cachedProperty = _cachedProperty ?? propertyFactory.CreateProperty(EnvironmentUserNamePropertyName, GetUserName());
        logEvent.AddPropertyIfAbsent(_cachedProperty);
    }

    private string GetUserName()
    {
        if (HttpContext.Current != null && HttpContext.Current.User != null && HttpContext.Current.User.Identity != null)
        {
            return HttpContext.Current.User.Identity.Name;
        }

        return string.Empty;
    }
}

However how do i invoke it? Which With method i should be using?

  Log.Logger = new LoggerConfiguration()
            .Enrich.With???????
            .ReadFrom.AppSettings()
            .CreateLogger();

Update 2
I have created extension method and then use it during logging configuration

public static class HttpContextLoggerConfigurationExtensions
{
    public static LoggerConfiguration WithUserName(
        this LoggerEnrichmentConfiguration enrichmentConfiguration)
    {
        if (enrichmentConfiguration == null) throw new ArgumentNullException(nameof(enrichmentConfiguration));
        return enrichmentConfiguration.With<HttpContextEnricher>();
    }
}

and then configured the logger in global.asax in Application_Start event

 Log.Logger = new LoggerConfiguration()
            .Enrich.WithUserName()
            .ReadFrom.AppSettings()
            .CreateLogger();

I have noticed everytime i log something, enricher is getting invoked and it returns UserName but it does not log UserName in the log. I see my message in the log but not the UserName property. I am using Windows EventLog Sink

I am logging information as

       Log.Information("Some message");

and Error as

       Log.Error(exception, "ErrorID={ErrorID}",someid);

What am i missing?

like image 528
LP13 Avatar asked Feb 21 '17 21:02

LP13


People also ask

What is Serilog log context?

Serilog. Context. LogContext can be used to dynamically add and remove properties from the ambient "execution context"; for example, all messages written during a transaction might carry the id of that transaction, and so-on.

What is structured logging in Serilog?

Structured logging is a modern approach where logging events are treated as structured data rather than text, for example: { “payload”: { “order”: { “id”: 10 }, “message”: “OrderId: 10 placed successfully” }

Is Serilog thread safe?

Yes, ILogger s in Serilog are always safe to use concurrently from multiple threads.


1 Answers

There's a few different ways to do that with Serilog. You could use an Enricher that you configure at the start of your application (when you configure logging), and it gets called automatically as you log messages and you can add the additional properties you want to the Log context.

Another way would be to hook into an event called by your web app framework at the beginning of each request, and then add properties to the Log context.

One other way, would be to add contextual properties at the moment where the logger instance is resolved by your DI container (if you're using one).


  • Enricher Samples

https://github.com/serilog-web/owin/blob/master/src/SerilogWeb.Owin/Owin/RequestContextMiddleware.cs

https://github.com/serilog-web/classic/blob/master/src/SerilogWeb.Classic/Classic/Enrichers/HttpRequestClientHostIPEnricher.cs


  • Context PushProperty example

https://web.archive.org/web/20171207095449/http://mylifeforthecode.com/enriching-serilog-output-with-httpcontext-information-in-asp-net-core/


  • Autofac Serilog Integration

https://github.com/nblumhardt/autofac-serilog-integration

like image 200
C. Augusto Proiete Avatar answered Oct 17 '22 03:10

C. Augusto Proiete