9

I am using generic host pattern in my project. I need a logger to file specially a rolling file like Serilog. How can I add it to certain logger configuration to the host builder.

In generic host we can add log configuration such as debugger and console. But I want to use a logger to file with specific options. I don't know how to do so.

Which way is the best practice for?

Hassan Ahmadi
  • 626
  • 5
  • 14
  • 4
    Have a look at [this](https://github.com/serilog/serilog-sinks-rollingfile) and [this](https://ondrejbalas.com/using-serilog-with-asp-net-core-2-0/) – Pavel Anikhouski Jul 17 '19 at 08:01

3 Answers3

9

Thanks to both answers, I need to use both Serilog.Extensions.Hosting and Serilog.Sinks.RollingFile. Then it needs to create a logger object so it can be added to host builder, As shown below :

var logger = new LoggerConfiguration().WriteTo.RollingFile(
                outputTemplate: outputTemplate,
                restrictedToMinimumLevel: LogEventLevel.Information,
                pathFormat: Path.Combine(loggingDirectory, "systemlog-{Date}.text")
            .CreateLogger();

Note that pathFormat argument are useful and important.It consists of path and format which is described adequately in Serilog.Sinks.RollingFile( Filename format specifiers). Here i use {Date} format after path which means : It creates a file per day. Filenames use the yyyyMMdd format.

After creating logger with such a config it needs to be added into HostBuilder like this:

var host = new HostBuilder()
            .ConfigureLogging((context, builder) =>
            {
                builder.AddConsole();
                builder.AddSerilog(logger);
                //....<- some other option here
            })
            .Build();
Hassan Ahmadi
  • 626
  • 5
  • 14
4

You'll need Serilog.Extensions.Hosting.

public static IHost BuildHost(string[] args) =>
    new HostBuilder()
        .UseSerilog() // <- Add this line
        .Build();
Nicholas Blumhardt
  • 30,271
  • 4
  • 90
  • 101
4

Here's another example, I'm hoping this provides a complete example for anyone in need:

  • .NET 7 Console App
  • Microsoft Generic Host with top-level statements
  • Uses a Bootstrap Logger for capturing startup exceptions
  • Loads the Logger from IConfiguration

Program.cs

using ConsoleUI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Core;
using Serilog.Events;

Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Override("Default", LogEventLevel.Debug)
            .Enrich.FromLogContext()
            .WriteTo.Console()
            .CreateBootstrapLogger();

try
{
    HostApplicationBuilder builder = Host.CreateApplicationBuilder();
    
    builder.Services.AddLogging(config =>
    {
        config.ClearProviders();

        Logger logger = new LoggerConfiguration()
            .ReadFrom.Configuration(builder.Configuration)
            .CreateLogger();

        config.AddSerilog(logger);
    });

    builder.Services.AddHostedService<App>();
    IHost app = builder.Build();
    app.Run();
}
catch (Exception ex)
{
    Log.Fatal(ex, "Host terminated unexpectedly");
}
finally
{
    Log.CloseAndFlush();
}

appsettings.json

{
  "Serilog": {
    "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
    "MinimumLevel": {
      "Default": "Information",
      "Override": {
        "System": "Information",
        "Microsoft": "Information",
        "Microsoft.AspNetCore": "Information",
        "Microsoft.EntityFrameworkCore": "Information",
        "Azure": "Information"
      }
    },
    "WriteTo": [
      {
        "Name": "Console",
        "Args": {
          "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz}|{Level:u3}|{SourceContext}|{Message:lj}{NewLine}{Exception}"
        }
      },
      {
        "Name": "File",
        "Args": {
          "path": "logs/ConsoleUI-.log",
          "rollingInterval": "Day",
          "retainedFileCountLimit": 15,
          "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz}|{Level:u3}|{SourceContext}|{Message:lj}{NewLine}{Exception}"
        }
      }
    ],
    "Enrich": [ "FromLogContext", "WithMachineName" ],
    "Properties": {
      "Application": "ConsoleUI"
    }
  }
}

App.cs

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace ConsoleUI;

public class App : IHostedService
{
    private readonly IHostApplicationLifetime _hostApplicationLifetime;
    private readonly IConfiguration _config;
    private readonly ILogger<App> _logger;

    public App(IHostApplicationLifetime hostApplicationLifetime,
               IConfiguration configuration,
               ILogger<App> logger)
    {
        _hostApplicationLifetime = hostApplicationLifetime;
        _config = configuration;
        _logger = logger;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _hostApplicationLifetime.ApplicationStarted.Register(async () =>
        {
            try
            {
                await Task.Yield(); // https://github.com/dotnet/runtime/issues/36063
                await Task.Delay(1000); // Additional delay for Microsoft.Hosting.Lifetime messages
                await ExecuteAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Unhandled exception!");
            }
            finally
            {
                _hostApplicationLifetime.StopApplication();
            }
        });

        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        return Task.CompletedTask;
    }

    public async Task ExecuteAsync()
    {
        _logger.LogTrace("Hello, Trace!");
        _logger.LogDebug("Hello, Debug!");
        _logger.LogInformation("Hello, World!");
        _logger.LogWarning("Hello, Warning!");
        _logger.LogError("Hello, Error!");
        _logger.LogCritical("Hello, Critical!");

        await Task.Delay(1);
    }
}

Nuget Packages enter image description here

Output enter image description here

Brian
  • 315
  • 5
  • 10