34

I am logging events of all types to single Json file irrespective of LogLevel. Now I have a requirement to log some custom performance counters to a seperate Json file. How can this be done in Serilog. Should I create different Logger Instance and use that where ever I am going to Log the performance counters? Want to use this with LibLog

Shetty
  • 1,792
  • 4
  • 22
  • 38

4 Answers4

33

You can do this by first making sure the performance counter events are tagged with either a particular property value (OpenMappedContext() in LibLog) or from a particular type/namespace.

var log = LogProvider.For<MyApp.Performance.SomeCounter>()
log.Info(...);

When configuring Serilog, a sub-logger with filter applied can send just the required events to the second file.

Log.Logger = new LoggerConfiguration()
    .WriteTo.Logger(lc => lc
        .Filter.ByExcluding(Matching.FromSource("MyApp.Performance"))
        .WriteTo.File("first.json", new JsonFormatter()))
    .WriteTo.Logger(lc => lc
        .Filter.ByIncludingOnly(Matching.FromSource("MyApp.Performance"))
        .WriteTo.File("second.json", new JsonFormatter()))
    .CreateLogger();
Nicholas Blumhardt
  • 30,271
  • 4
  • 90
  • 101
  • Read your write up : Serilog 2.0 adventures with sub-loggers. Not sure If I missed something, but, If I do this, the logs from ""MyApp.Performance" will go to outer logger as well right? I do not want these specific logs to be written to the main log file. – Shetty Jul 23 '16 at 20:23
  • Adding two sub-logging pipelines with inverse filters should do it. Updating answer.. – Nicholas Blumhardt Jul 23 '16 at 23:40
  • That worked for me. Edited answer to remove JsonFormatter. – Shetty Jul 24 '16 at 15:59
  • Do you have json example of this? – shiva Apr 12 '18 at 09:22
12

We can set it up in the configuration files too. Given below is a sample in the appsettings.json to split the log the rolling files based on levels

{
 
  "Serilog": {
    "MinimumLevel": {
      "Default": "Debug",
      "Override": {
        "Default": "Information",
        "Microsoft": "Warning",
        "Microsoft.Hosting.Lifetime": "Information"
      }
    },
    "WriteTo": [
      {
        "Name": "Logger",
        "Args": {
          "configureLogger": {
            "Filter": [
              {
                "Name": "ByIncludingOnly",
                "Args": {
                  "expression": "(@Level = 'Error' or @Level = 'Fatal' or @Level = 'Warning')"
                }
              }
            ],
            "WriteTo": [
              {
                "Name": "File",
                "Args": {
                  "path": "Logs/ex_.log",
                  "outputTemplate": "{Timestamp:o} [{Level:u3}] ({SourceContext}) {Message}{NewLine}{Exception}",
                  "rollingInterval": "Day",
                  "retainedFileCountLimit": 7
                }
              }
            ]
          }
        }
      },
      {
        "Name": "Logger",
        "Args": {
          "configureLogger": {
            "Filter": [
              {
                "Name": "ByIncludingOnly",
                "Args": {
                  "expression": "(@Level = 'Information' or @Level = 'Debug')"
                }
              }
            ],
            "WriteTo": [
              {
                "Name": "File",
                "Args": {
                  "path": "Logs/cp_.log",
                  "outputTemplate": "{Timestamp:o} [{Level:u3}] ({SourceContext}) {Message}{NewLine}{Exception}",
                  "rollingInterval": "Day",
                  "retainedFileCountLimit": 7
                }
              }
            ]
          }
        }
      }
    ],
    "Enrich": [
      "FromLogContext",
      "WithMachineName"
    ],
    "Properties": {
      "Application": "MultipleLogFilesSample"
    }
  }
}

Then, you will only need to modify the CreateHostBuilder method in Program.cs file to read it from the configuration file

public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            })
            .UseSerilog((hostingContext, loggerConfig) =>
                loggerConfig.ReadFrom.Configuration(hostingContext.Configuration)
            );

For more details, refer the post here

Amal Dev
  • 1,938
  • 1
  • 14
  • 26
3

If you want to have an independent logging pipeline, just make another instance. This is robbed and adapted from https://github.com/serilog/serilog/wiki/Lifecycle-of-Loggers:

using (var performanceCounters = new LoggerConfiguration()
        .WriteTo.File(@"myapp\log.txt")
        .CreateLogger())
{
    performanceCounters.Information("Performance is really good today ;-)");

    // Your app runs, then disposal of `performanceCounters` flushes any buffers
}
Stefan Bormann
  • 643
  • 7
  • 25
1

I'm using the following code to log different levels to different files.

var conn = configuration.GetSection("ConnectionStrings:SqlConn").Value;

var serilogLogger = new LoggerConfiguration()
            .MinimumLevel.Information()
            .WriteTo.Console()
            .WriteTo.MSSqlServer(conn, new MSSqlServerSinkOptions { TableName = "ErrorLogs", AutoCreateSqlTable = true }, restrictedToMinimumLevel: Serilog.Events.LogEventLevel.Warning)
            .WriteTo.MSSqlServer(conn, new MSSqlServerSinkOptions { TableName = "InfoLogs", AutoCreateSqlTable = true }, restrictedToMinimumLevel: Serilog.Events.LogEventLevel.Information)
            .CreateLogger();