Search code examples
.net-coreserilog

Serilog does not write to a file using LoggerFactory in .NET 5 Console App, produces no errors or output


I'm trying to use Serilog's AddFile by way of LoggerFactory but I can't get it to do anything.

This is my appsettings.json, unchanged from the getting started guide.

Here is what I have:

IConfiguration Configuration = new ConfigurationBuilder()
    //.SetBasePath(Path.Combine(Directory.GetCurrentDirectory(), "Logs"))
    .AddJsonFile(Path.Combine(Directory.GetCurrentDirectory(), "Properties", "appsettings.json"), optional: false, reloadOnChange: false)
    //.AddEnvironmentVariables()
    //.AddCommandLine(args)
    .Build();

ILoggerFactory loggerFactory = LoggerFactory.Create(builder => {
    builder
        .AddConfiguration(Configuration.GetSection("Logging"))
        .AddConsole()
        .AddDebug()
        .AddFile("log.txt"); //Configuration.GetSection("Logging"));
});

ILogger<Program> logger = loggerFactory.CreateLogger<Program>();

logger.LogTrace("Trace");
logger.LogInformation("Information");
logger.LogDebug("Debug");
logger.LogError("Error");
logger.LogCritical("Critical");

I see output in the console. I receive no errors. Even with the suggested addition of:

Serilog.Debugging.SelfLog.Enable(msg => Debug.WriteLine(msg));

From: https://github.com/serilog/serilog/wiki/Debugging-and-Diagnostics


Solution

  • The Serilog extension you're using (Serilog.Extensions.Logging.File) internally writes to the file asynchronously on a separate thread, and your application is terminating before Serilog had the chance to flush the logs to the file on disk (which could take about ~2 seconds).

    Normally you'd use an application host that takes care of disposing the logger (and other services) before the application terminates, forcing a flush which would write to disk, but in your case with a simple Console app, nobody is disposing the log so there's no final flush happening before the app terminates.

    Serilog has a Log.CloseAndFlush method that is normally used in cases like this and you're expected to call it before your app terminates, however Log.CloseAndFlush doesn't work with Serilog.Extensions.Logging.File (at least with the latest version as of this writing) because it doesn't assign the logger it creates to Log.Logger which is what CloseAndFlush tries to dispose.

    Thus, in your case, without a host and without the ability to use CloseAndFlush, you'd need to prevent your application from terminating for a few seconds, for example, by blocking the main thread with a Thread.Sleep or wait for user input with a Console.ReadLine, or similar...

    // ...
    logger.LogError("Error");
    logger.LogCritical("Critical");
    
    // Just for the sake of proving that the file is being written (not production code)
    System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5)); // <<<<<
    

    Related issue: Means to troubleshoot/debug logging? #48