Search code examples
asp.net-coreserilogasp.net-core-5.0serilog-sinks-file

Cannot catch instantiations errors with Serilog and .Net Core 5


I have a .Net Core 5 app with Serilog. I am testing error logging and I have a class that cannot be instantiated because I commented out some services in the DI registration. This is my Program.cs file:

public static void Main(string[] args)
    {
        Log.Logger = new LoggerConfiguration()
           .Enrich.FromLogContext()
           .WriteTo.File("Logs/Startup.txt", Serilog.Events.LogEventLevel.Verbose)
           .CreateLogger();
        try
        {
            Log.Information("Starting up");
            CreateHostBuilder(args).Build().Run();
        }
        catch (Exception ex)
        {
            Log.Fatal(ex, "Application start-up failed");
            Environment.Exit(1);
        }
    }
public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .UseSerilog((hostingContext, loggerConfiguration) => loggerConfiguration
                    .ReadFrom.Configuration(hostingContext.Configuration))
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });

In the Startup.txt file I am only seeing the Information and not the errors. Ideas?


Solution

  • Your initial logger is using File() but you later call UseSerilog(callback) which will overwrite it with whatever is in the configuration file.

    CreateBootstrapLogger() sorts all of this out by allowing the startup and later application logs to be merged:

    public static int Main(string[] args)
    {
        Log.Logger = new LoggerConfiguration()
           .Enrich.FromLogContext()
           .WriteTo.File("Logs/Log.txt")  // <-- No longer need a separate startup log
           .CreateBootstrapLogger();  // <-- Change this line
    
        try
        {
            Log.Information("Starting up");
            CreateHostBuilder(args).Build().Run();
        }
        catch (Exception ex)
        {
            Log.Fatal(ex, "Application start-up failed");
            return 1;  // <-- Change this line
        }
        finally  // <-- Add this block
        {
            Log.CloseAndFlush();
        }
    
        return 0;  // <-- Add this line
    }
    
    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .UseSerilog((hostingContext, loggerConfiguration) => loggerConfiguration
                .WriteTo.File("Logs/Log.txt") // <-- Add this line
                .ReadFrom.Configuration(hostingContext.Configuration))
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
    

    If you really don't want startup and regular log events in the same sinks, you can initialize a separate logger for start-up instead:

    public static int Main(string[] args)
    {
        using var startup = new LoggerConfiguration()
           .Enrich.FromLogContext()
           .WriteTo.File("Logs/Startup.txt")
           .CreateLogger();
    
        try
        {
            startup.Information("Starting up");
            CreateHostBuilder(args).Build().Run();
        }
        catch (Exception ex)
        {
            startup.Fatal(ex, "Application start-up failed");
            return 1;  // <-- Change this line
        }
    
        return 0;  // <-- Add this line
    }
    
    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .UseSerilog((hostingContext, loggerConfiguration) => loggerConfiguration
                .ReadFrom.Configuration(hostingContext.Configuration))
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
    

    (I still also suggest avoiding Environment.Exit() when possible.)