Search code examples
c#.netloggingserilog

Different log file for different levels in Serilog


I am using serilog and I need to save different log levels to different files ( for example debug-20200708.log for debug level, info-20200798.log for debug level and ...)

I used below code but it does not work correctly.

var baseLogger = new Serilog.LoggerConfiguration()
    .WriteTo.Logger(l => l
        .Filter.ByIncludingOnly(e => e.Level == LogEventLevel.Fatal))
        .WriteTo.File(
            path: GetLogPath(LogEventLevel.Fatal),
            formatter: formatter)

    .WriteTo.Logger(l => l
        .Filter.ByIncludingOnly(e => e.Level == LogEventLevel.Error))
        .WriteTo.File(
            path: GetLogPath(LogEventLevel.Error),
            formatter: formatter)

    .WriteTo.Logger(l => l
        .Filter.ByIncludingOnly(e => e.Level == LogEventLevel.Warning))
        .WriteTo.File(
            path: GetLogPath(LogEventLevel.Warning),
            formatter: formatter)

    .WriteTo.Logger(l => l
        .Filter.ByIncludingOnly(e => e.Level == LogEventLevel.Information))
        .WriteTo.File(
            path: GetLogPath(LogEventLevel.Information),
            formatter: formatter)

    .WriteTo.Logger(l => l
        .Filter.ByIncludingOnly(e => e.Level == LogEventLevel.Debug))
        .WriteTo.File(
            path: GetLogPath(LogEventLevel.Debug),
            formatter: formatter)

    .WriteTo.Logger(l => l
        .Filter.ByIncludingOnly(e => e.Level == LogEventLevel.Verbose))
        .WriteTo.File(
            path: GetLogPath(LogEventLevel.Verbose),
            formatter: formatter)
    .Enrich.FromLogContext();

_logger = baseLogger.CreateLogger();

Solution

  • The main reason it doesn't work is because you're not using the .WriteTo of the filter, and instead you're using the .WriteTo of the main pipeline (which doesn't have filters applied).

    E.g. Instead of:

    .WriteTo.Logger(l => l
        .Filter.ByIncludingOnly(e => e.Level == LogEventLevel.Fatal))
    .WriteTo.File(
        path: GetLogPath(LogEventLevel.Fatal),
        formatter: formatter)
    

    You need (notice the difference in parentheses):

    .WriteTo.Logger(l => l
        .Filter.ByIncludingOnly(e => e.Level == LogEventLevel.Fatal)
        .WriteTo.File(
            path: GetLogPath(LogEventLevel.Fatal),
            formatter: formatter))
    

    This applies for each of the .WriteTo calls you have as they all have the same issue.

    Once you fix that, you'll see that the logs are written to the corresponding files now, except for Verbose and Debug (files are empty). The reason for that is because Serilog's default MinimumLevel is Information so anything lower than that is ignored. To resolve that you need to set the MinimumLevel to Verbose in the logging pipeline configuration:

    var baseLogger = new Serilog.LoggerConfiguration()
        .MinimumLevel.Verbose()
        .WriteTo.Logger(l => l
        // ...
    

    ps: There's also a different approach to doing what you're doing using the Serilog.Sinks.Map sink which you can see an example here.