Search code examples
c#asp.net-coreasp.net-web-api.net-6.0serilog

Serilog file paths with Versioning


I'm fairly new to Versioning my API. I am using ASP.NET 6.0 and Serilog to write to a log file.

Now that I've implemented versioning I want to have v1.0 of the app write to "Logs/V1.0/logfile.json" and v2.0 write to "Logs/v2.0/logfile.json".

I can get the version number "1.0" or "2.0" inside my controllers no problem.

[ApiController]
[Route("/v{version:apiVersion}/[controller]")]
[ApiVersion("2.0")]
public class MainController : Controller

    [HttpGet]
    public void MyMethod(ApiVersion version)
    {
        _logger.LogInformation("APIVersion: {ApiVersion}", version);
    }
}

I can see Serilog will save this "ApiVersion" variable in the log's Properties.

"Properties":{
   "ApiVersion":"2.0",
   "RequestPath":"/v2.0/Main/MyMethod",
   ...

So how do I put all this together to get Serilog to save the logs in different File locations?

I think it may have something to do with the "Log.Logger = new LoggerConfiguration()" in Program.cs ? I read about various options like .WriteTo.Map or Write.To.Conditional ?

Everything seems to be to do with writing logs of different levels (Informational, Warning, Alert) to different locations though. I also have no idea what best practice for this set up would be.

Any help appreciated!


Solution

  • You can use Serilog.Sinks.Map.

    Below is a working demo, You can refer to it.

    Install Serilog.AspNetCore, Serilog.Sinks.Map and Microsoft.AspNetCore.Mvc.Versioning NuGet Package.

    Add Serilog in appsetting.json file:

    "Serilog": {
        "Using": [ "Serilog.Sinks.File" ],
        "MinimumLevel": {
          "Default": "Debug",
          "Override": {
            "Microsoft": "Error",
            "System": "Debug"
          }
        },
        "Enrich": [ "FromLogContext", "WithMachineName", "WithProcessId", "WithThreadId" ]
    }
    

    In Program.cs:

    var logger = new LoggerConfiguration().WriteTo.Map(
                        "ApiVersion",
                        "(None)",
                        (ApiV, wt) =>
                            wt.File($"Your Path\\Logs\\{ApiV}\\logfile.json")
                        )
      .ReadFrom.Configuration(builder.Configuration)
      .Enrich.FromLogContext()
      .CreateLogger();
    builder.Logging.ClearProviders();
    builder.Logging.AddSerilog(logger);
    
    builder.Services.AddApiVersioning();
    //...
    

    Controller:

    [Route("/v{version:apiVersion}/[controller]")]
    [ApiVersion("2.0")]
    [ApiController]
    public class MainController : ControllerBase
    {
        private readonly ILogger<MainController> _logger;
        public MainController(ILogger<MainController> logger)
        {
            _logger = logger;
        }
    
        [HttpGet]
        public void MyMethod(ApiVersion version)
        {
            _logger.LogInformation("APIVersion: {ApiVersion}", "V"+version);
        }
    }
    

    Test Result:

    enter image description here

    enter image description here

    Update:

    Please confirm whether your basePath ends with \\, if not, then you need to manually add the \\ symbol:

    var basePath = "C:\\...Path\\ProjectName";
    
    var logger = new LoggerConfiguration().WriteTo.Map(
                        "ApiVersion",
                        "(None)",
                        (ApiV, wt) =>
                            wt.File($"{basePath}\\Logs\\{ApiV}\\logfile.json")
                        )
      .ReadFrom.Configuration(builder.Configuration)
      .Enrich.FromLogContext()
      .CreateLogger();