External Logging for APIs with Serilog

Introduction

In the dynamic world of application development, robust logging is a key component for understanding and troubleshooting software behavior. Serilog, a popular logging library for .NET, makes this process seamless. In this article, we'll explore how to implement external logging sources using Serilog for both APIs and Windows Services, providing a comprehensive solution for logging information.

Packages Needed

Before diving into implementation, ensure you have the necessary Serilog packages installed.

<PackageReference Include="Serilog.AspNetCore" Version="8.0.0" />
<PackageReference Include="Serilog.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="Serilog.Settings.AppSettings" Version="2.2.2" />
<PackageReference Include="Serilog.Settings.Configuration" Version="8.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />

Configuration of Serilog in API

To configure Serilog in your API, you need to add the following settings to your appsettings.json file.

"LogBaseDirectory": "C:\\WindowsServiceLogs\\",
"Serilog": {
  "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
  "MinimumLevel": "Debug",
  "WriteTo": [
    {
      "Name": "Console"
    },
    {
      "Name": "File",
      "Args": {
        "path": "%APP_BASE_DIRECTORY%/Logs/log-.txt",
        "rollingInterval": "Day"
      }
    }
  ]
}

The %APP_BASE_DIRECTORY% placeholder will be read from app settings and updated at the startup of the service.

API Startup Configuration

In the startup of your API, configure Serilog as follows.

using Serilog;

var host = Host.CreateDefaultBuilder(args)
    .UseWindowsService()
    .UseSerilog((context, services, configuration) => configuration
        .ReadFrom.Configuration(context.Configuration)
        .ReadFrom.Services(services))
    .ConfigureServices(services =>
    {
        IConfigurationRoot configuration = new ConfigurationBuilder()
            .SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
            .AddJsonFile("appsettings.json")
            .Build();

        if (!Directory.Exists(configuration["LogBaseDirectory"]))
        {
            Directory.CreateDirectory(configuration["LogBaseDirectory"]);
        }

        Environment.SetEnvironmentVariable("APP_BASE_DIRECTORY", configuration["LogBaseDirectory"]);

        services.AddHostedService<SimpleWorker>();
    })
    .Build();

await host.RunAsync();

Worker Class

Now, let's create a simple worker class that utilizes Serilog for logging.

public class SimpleWorker : BackgroundService
{
    private readonly ILogger<SimpleWorker> _logger;

    public SimpleWorker(ILogger<SimpleWorker> logger)
    {
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            _logger.LogInformation("Execute SimpleWorker -> [ExecuteAsync]");

            await Task.Delay(1000, stoppingToken);
        }
    }

    public override Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Starting service [StartAsync]");

        return base.StartAsync(cancellationToken);
    }

    public override Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Stopping service [StopAsync]");

        return base.StopAsync(cancellationToken);
    }
}

With Serilog, logging for APIs and Windows Services becomes an effortless endeavor. By configuring Serilog to use external logging sources, you ensure that your application's behavior is well-documented and can be easily analyzed. Embrace the power of Serilog to enhance your logging strategy and make troubleshooting a breeze.