26
votes

I am using Serilog for logging and cant' figure out how to separate log events to different files. For example, I want to log errors to error_log-ddmmyyyy.txt and warnings to warn_log-ddmmyyyy.txt.

Here goes my logger configuration:

Log.Logger = new LoggerConfiguration()
            .WriteTo.Logger(lc =>
                lc.Filter.ByIncludingOnly(Matching.WithProperty("Level", "Warning"))
                    .WriteTo.RollingFile(
                        Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"Logs\warn_log-{Date}.txt"),
                        outputTemplate: OutputTemplate))
            .WriteTo.Logger(lc =>
                lc.Filter.ByIncludingOnly(Matching.WithProperty("Level", "Error"))
                    .WriteTo.RollingFile(
                        Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"Logs\error_log-{Date}.txt"),
                        outputTemplate: OutputTemplate))
            .CreateLogger();

It only works when I specify {Level} property exatcly in log message.

I was trying to use:

Matching.WithProperty<LogEventLevel>("Level", l => l == LogEventLevel.Warning)

but it didn't work too.

5
@Kiquenet, it's WCF application. - Anton Kiprianov
How do you log errors and log warnings in your code using Serilog ? - Kiquenet
@Kiquenet, examples are below: Error message with exception details: Log.Logger.Error(ex, "Here goes error message with {Data}", someData) Warning message: Log.Logger.Warning("Here goes warning message with {Data}", someData) - Anton Kiprianov

5 Answers

44
votes

I use the following configuration and it works for me:

            Log.Logger = new LoggerConfiguration()
                    .MinimumLevel.Debug()
                    .WriteTo.LiterateConsole()
                    .WriteTo.Logger(l => l.Filter.ByIncludingOnly(e => e.Level == LogEventLevel.Information).WriteTo.RollingFile(@"Logs\Info-{Date}.log"))
                    .WriteTo.Logger(l => l.Filter.ByIncludingOnly(e => e.Level == LogEventLevel.Debug      ).WriteTo.RollingFile(@"Logs\Debug-{Date}.log"))
                    .WriteTo.Logger(l => l.Filter.ByIncludingOnly(e => e.Level == LogEventLevel.Warning    ).WriteTo.RollingFile(@"Logs\Warning-{Date}.log"))
                    .WriteTo.Logger(l => l.Filter.ByIncludingOnly(e => e.Level == LogEventLevel.Error      ).WriteTo.RollingFile(@"Logs\Error-{Date}.log"))
                    .WriteTo.Logger(l => l.Filter.ByIncludingOnly(e => e.Level == LogEventLevel.Fatal      ).WriteTo.RollingFile(@"Logs\Fatal-{Date}.log"))
                    .WriteTo.RollingFile(@"Logs\Verbose-{Date}.log")
                    .CreateLogger();
20
votes

I think you need:

.ByIncludingOnly(evt => evt.Level == LogEventLevel.Warning)

Edit:

In many cases it's now more succinct to use Serilog.Sinks.Map. With it, the example can be written as:

Log.Logger = new LoggerConfiuration()
    .WriteTo.Map(
        evt => evt.Level,
        (level, wt) => wt.RollingFile("Logs\\" + level + "-{Date}.log"))
    .CreateLogger();
2
votes

Usually for my use-cases I need multiple logs that will contain a minimum level for each. This way I can later investigate the logs more efficiently.

For more recent versions of Serilog I would suggest to use this:

Log.Logger = new LoggerConfiuration()
    .MinimumLevel.Debug()
    .WriteTo.File(path: "debug.log", rollingInterval: RollingInterval.Day)
    .WriteTo.File(path: "info.log", restrictedToMinimumLevel: LogEventLevel.Information, rollingInterval: RollingInterval.Day)
    .WriteTo.File(path: "error.log",restrictedToMinimumLevel: LogEventLevel.Error, rollingInterval: RollingInterval.Day)
    .WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Warning)
    .CreateLogger();
0
votes
var dateTimeNowString = $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}";
Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Debug()
    .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
    .WriteTo.Logger(
        x => x.Filter.ByIncludingOnly(e => e.Level == LogEventLevel.Error)
            .WriteTo.File($"Logs/{dateTimeNowString}-Error.log")
    )
    .WriteTo.Logger(
        x => x.Filter.ByIncludingOnly(e => e.Level == LogEventLevel.Warning)
            .WriteTo.File($"Logs/{dateTimeNowString}-Warning.log")
    )
    .WriteTo.File($"Logs/{dateTimeNowString}-All.log")
    .WriteTo.Console()
    .CreateLogger();

These are my nuget packages:

    <PackageReference Include="Serilog.AspNetCore" Version="2.1.1" />
    <PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
    <PackageReference Include="Serilog.Sinks.File" Version="4.0.0" />
0
votes

Another variant is to have ERROR and FATAL in one file (instead of errors in one file and fatal in another). Seems to many files for me having them separate. Just to keep in mind "or" operator can be used.

Log.Logger = new LoggerConfiguration()
    .WriteTo.File("logs\\all.log", rollingInterval: RollingInterval.Day)
    .WriteTo.Logger(
        x => x.Filter.ByIncludingOnly(y => y.Level == Serilog.Events.LogEventLevel.Error || y.Level == Serilog.Events.LogEventLevel.Fatal)
        .WriteTo.File("logs\\error.log", rollingInterval: RollingInterval.Day))
    .CreateLogger();