serilog-contrib / serilog-enrichers-globallogcontext

A Serilog Enricher for adding properties to all log events in your app
https://www.nuget.org/packages/Serilog.Enrichers.GlobalLogContext/
Apache License 2.0
27 stars 1 forks source link

Allow separate contexts for different loggers #2

Open augustoproiete opened 3 years ago

augustoproiete commented 3 years ago

Based on comment from @cassandra-d on StackOverflow:

Good answer and good work with nuget. A little bit unfortunate that that enricher works only globally and you can't set properties per logger instance to use it for distributed logging.


Given that enrichers are not sink-specific, I'm thinking that we would need to introduce something like "named contexts", and instruct the user to use sub-loggers to configure the enricher separately. It would look similar to the below (pseudo-code):

var consoleContext = GlobalLogContext.Create("Console");
var fileContext = GlobalLogContext.Create("File");

Log.Logger = new LoggerConfiguration()
    .WriteTo.Logger(lc => lc
        .WriteTo.Console()
        .Enrich.FromGlobalContext(consoleContext)
    )
    .WriteTo.Logger(lc => lc
        .WriteTo.File("log.txt")
        .Enrich.FromGlobalContext(fileContext)
    )
    .CreateLogger();
Cassandra-d commented 3 years ago

Thank you for creating the issue and paying attention to my comment. Just a little explanation what I was looking for and what was my task. Tho it might be not the same as the intention of this issue.

I'm writing a distributed tracing system and for that I needed to pass a correlation id into logs. And I would like to do something like this logger.PushProperty(TraceId, userContext.TraceId), taking into account that I have a specific instance of a logger. I'm entrusting IoC container to make a unit of work and to ensure that the logger will be a single instance throughout a request.

There is an option to use scopes, but I would want to refrain from controlling lifetime of anything by myself if possible.

augustoproiete commented 3 years ago

@Cassandra-d Gotcha.

The enricher in this repo (Serilog.Enrichers.GlobalLogContext) is global across all threads (and by extension across all requests) and shared across all sinks configured in the pipeline.

What I thought you asked, was to be able to have separate contexts per sink - but still global throughout the app, just like it is now, which is what I tried to described above re: name contexts, etc.

So it seems what you're looking for is the default LogContext that comes with Serilog out-of-the-box, which is unique per thread (and by extension per request, as each request gets its own thread).

You can add properties to the log context directly via the LogContext class:

using Serilog;
using Serilog.Context;

Log.Logger = new LoggerConfiguration()
    .Enrich.FromLogContext() // <<<<<<<<
    .WriteTo.SinkName(...)
    .CreateLogger();

LogContext.PushProperty("TraceId", traceId); // <<<<<<<<

Log.Information("...");

Alternatively, you can create a context logger via Log.ForContext and include the property you want (you'll get the same result).

using Serilog;

Log.Logger = new LoggerConfiguration()
    .Enrich.FromLogContext() // <<<<<<<<
    .WriteTo.SinkName(...)
    .CreateLogger();

var contextLogger = Log.ForContext("TraceId", traceId); // <<<<<<<<

contextLogger.Information("...");

Links that might be useful: