How to use Logger in program.cs in .NET 6, before builder.Build()

9.8k Views Asked by At

Using the default WebAPI framework VS2022 in .NET 6. I would like to log information using ILogger, but before the call of "var app = builder.Build();".

Is it possible to retrieve the logger newly configured by "buider.Host.ConfigureLogging(logging =>" from the "WebApplication" object, or the WebApplicationBuilder object, or builder.Host object or any other object?

This is the code of program.cs

var builder = WebApplication.CreateBuilder(args);

string insightConnectionString = Environment.GetEnvironmentVariable("APPLICATIONINSIGHTS_CONNECTION_STRING");

builder.Host.ConfigureLogging(logging =>
{
    logging.ClearProviders();
    logging.AddApplicationInsights(insightConnectionString);
    logging.AddConsole();
});

// -----> I want to log information here, before the call of "var app = builder.Build();" <-----

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// -----> And I want to log information here, before the call of "var app = builder.Build();" <-----

var app = builder.Build();

app.Logger.LogInformation("Log some information #1");

//...

app.Logger.LogInformation("Log some information #2");

app.Run();
2

There are 2 best solutions below

2
On

There is actually a better reason to do it like this: FLUSH of logs. When your app stops on error immediately your logs can be lost because they often written in queue first and then at your destination in some other thread. For example ASP apps write console/file logs this way, which different from Console apps - they stop execution on writes/reads. You have to give it some time to roll through this queue because it helps to see why it crashed. It is not guaranteed that queue will be flushed, but in most cases simple wait is enough, especially if your service crashes on restarts.

This way you can also use it in Program.cs

public static class Program
{
    public static async Task Main(string[] args)
    {
        var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");

        var configuration = new ConfigurationBuilder()
            .AddJsonFile("appsettings.json", optional: false)
            .AddJsonFile($"appsettings.{env}.json", optional: true)
            .AddEnvironmentVariables()
            .AddCommandLine(args)
            .Build();
        
        var logFactory = SerilogLogFactory.Create(configuration);
        AppDomain.CurrentDomain.UnhandledException += (sender, e) =>
        {
            using (var log = logFactory.CreateLog("Unhandled"))
            {
                log.WriteError(e.ExceptionObject);
            }
            logFactory.Flush(TimeSpan.FromSeconds(5));
        };

        try
        {
            await Host
                  .CreateDefaultBuilder(args)
                  .ConfigureAppConfiguration(
                      (context, builder) =>
                      {
                          builder.AddConfiguration(configuration, shouldDisposeConfiguration: true);
                      })
                  .ConfigureLogging(x =>
                  {
                      x.ClearProviders();
                      x.AddProvider(logFactory);
                  })
                  .Build()
                  .RunAsync();
        }
        catch (Exception e)
        {
            using var log = logFactory.CreateLog("Startup");
            log.WriteError(e);

            throw;
        }
        finally
        {
            logFactory.Flush(TimeSpan.FromSeconds(5));
        }
    }
}
2
On

You can manually create LoggerFactory and Logger:

using var loggerFactory = LoggerFactory.Create(loggingBuilder => loggingBuilder
    .SetMinimumLevel(LogLevel.Trace)
    .AddConsole());

ILogger logger = loggerFactory.CreateLogger<Program>();
logger.LogInformation("Example log message");