'Serilog in Blazor server .Net6 to split error messages to a different file

In serilog, I need to split the information in two files. i.e one file should contain the Information and the other should contain the error. with the below code and configuration, the information and the errors both displays in both files, instead of filtering out.

Note: I am trying this in .Net6 in Serverside Blazor. Please help us. Thanks in Advance

    "Serilog": {
    "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File", "Serilog.Expressions" ],
    "MinimumLevel": {
      "Default": "Information",
      "Override": {
        "Microsoft": "Warning",
        "System": "Warning"
      }
    },
    "Enrich": [
      "FromLogContext",
      "WithMachineName"
    ],
    "WriteTo": [
      {
        "Name": "Console"
      },
      {
        "Name": "File",
        "Args": {
          "path": "Logs/ex_.log",
          "outputTemplate": "{Timestamp:o} [{Level:u3}] ({SourceContext}) {Message:lj}{NewLine}{Exception}",
          "rollingInterval": "Day",
          "retainedFileCountLimit": 7
        }
      },
      {
        "Name": "Logger",
        "Args": {
          "configureLogger": {
            "Filter": [
              {
                "Name": "ByExcluding",
                "Args": {
                  "expression": "(@Level = 'Information' )"
                }
              }
            ],
            "WriteTo": [
              {
                "Name": "File",
                "Args": {
                  "path": "Logs/ERROR_.log",
                  "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level:u3}] {Message:lj}{NewLine}{Exception}",
                  "rollingInterval": "Day",
                  "retainedFileCountLimit": 7
                }
              }
            ]
          }
        }
      }
    ]
  }

 Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.CreateBootstrapLogger();

WebApplicationBuilder builder;
try
{
    Log.Information("Application starting .....");
    builder = WebApplication.CreateBuilder(args);

    builder.Host.UseSerilog((ctx, lc) => lc
    .WriteTo.Console()
    .ReadFrom.Configuration(ctx.Configuration));

    // Add services to the container.
    builder.Services.AddRazorPages();
    builder.Services.AddServerSideBlazor();
    builder.Services.AddTelerikBlazor();
    builder.Services.AddSingleton<WeatherForecastService>();

    var app = builder.Build();

    // Configure the HTTP request pipeline.
    if (!app.Environment.IsDevelopment())
    {
        app.UseExceptionHandler("/Error");
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseSerilogRequestLogging();

    app.UseRouting();
    app.MapBlazorHub();
    app.MapFallbackToPage("/_Host");

    app.Run();
}
catch (Exception ex)
{
    Log.Fatal("Application even failed to start....");
}


Solution 1:[1]

You need to make sure the following NuGet packages are installed. You can find this working example code on GitHub here

  1. Serilog,
  2. Serilog.AspNetCore
  3. Serilog.Settings.Configuration
  4. Serilog.Sinks.File, Serilog.Sinks.* (whatever sink type you are using, relevant package)
  5. Serilog.Expressions,
  6. Serilog.Enrichers.*(this package is an optional choice) if you want to use enrichers.

I am using Blazor Serverside with .Net6 example here.

Program.cs 
   

  
    using Serilog;
    
    var builder = WebApplication.CreateBuilder(args);
    
    var configuration = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile("appsettings.json")
        .Build();
    
    
    Log.Logger = new LoggerConfiguration()
        .ReadFrom.Configuration(configuration)    
        .WriteTo.Console()
        .WriteTo.Logger(lc => lc
                        .Filter.ByIncludingOnly(" @l = 'Debug' or @l = 'Information' or @l = 'Warning'")
                        .WriteTo.File("Logs/Log-Information-{Date}.log", rollingInterval: RollingInterval.Day))
        .WriteTo.Logger(lc => lc
                        .Filter.ByIncludingOnly(" @l = 'Error' or @l = 'Fatal'")
                        .WriteTo.File("Logs/Log-Error-{Date}.log", rollingInterval: RollingInterval.Day))
        .CreateLogger();
    
    Log.Information("Starting up");
    
    
    Serilog.Log.Information("Starting application");
    Serilog.Log.Error("Error");
    Serilog.Log.Fatal("Fatal");
    Serilog.Log.Debug("Debug");
    
    // Add services to the container.
    builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
       .AddNegotiate();
    
    builder.Services.AddAuthorization(options =>
    {
        // By default, all incoming requests will be authorized according to the default policy.
        options.FallbackPolicy = options.DefaultPolicy;
    });
    
    builder.Services.AddRazorPages();
    builder.Services.AddServerSideBlazor();
    builder.Services.AddSingleton<WeatherForecastService>();
    
    var app = builder.Build();

Appsettings.json file:

      "Serilog": {
        "MinimumLevel": {
          "Default": "Information",
          "Microsoft.AspNetCore": "Warning",
          "Microsoft.EntityFrameworkCore": "Warning",
          "Microsoft.Extensions.DependencyInjection": "Warning",
        },
        "WriteTo": [
          {
            "Name": "Console",
            "Args": {
              "outputTemplate": "{Timestamp:HH:mm:ss} [{Level}] {SourceContext}{NewLine}{Message}{NewLine}{Exception}"
            }        
          },
          {
            "Name": "File",
            "Args": {
              "Path": "./logs/log.txt",
              "IncludeScopes": true,
              "TimestampFormat": "yyyy-MM-dd HH:mm:ss",
              "RollingInterval": "Day"
            }        
          },
          {
            "Name": "Seq",
            "Args": { "serverUrl":  "http://localhost:5341"}
          }
        ]
      }

The above code snippet will generate two different log files under the "./Logs/" path, per the below screenshot.

enter image description here

Inside the files:

enter image description here

enter image description here

Note: I have added "@using Serilog" into _Imports.razor as well.

My project package references:

<ItemGroup>
  <PackageReference Include="Microsoft.AspNetCore.Authentication.Negotiate" Version="6.0.5" />
  <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.5" />
  <PackageReference Include="Serilog" Version="2.11.0" />
  <PackageReference Include="Serilog.AspNetCore" Version="5.0.0" />
  <PackageReference Include="Serilog.Expressions" Version="3.3.0" />
  <PackageReference Include="Serilog.Sinks.Seq" Version="5.1.1" />    
  <PackageReference Include="Serilog.Enrichers.AspNetCore.HttpContext" Version="1.0.1" />
  <PackageReference Include="Serilog.Enrichers.AssemblyName" Version="1.0.9" />
  <PackageReference Include="Serilog.Enrichers.Context" Version="4.2.0" />
  <PackageReference Include="Serilog.Enrichers.Environment" Version="2.2.0" />
  <PackageReference Include="Serilog.Enrichers.Memory" Version="1.0.4" />
  <PackageReference Include="Serilog.Enrichers.Process" Version="2.0.2" />
  <PackageReference Include="Serilog.Enrichers.Thread" Version="3.1.0" />
  <PackageReference Include="Serilog.Settings.Configuration" Version="3.3.0" />
  <PackageReference Include="Serilog.Sinks.MSSqlServer" Version="5.7.0" />
   </ItemGroup>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1