How to use Logger in program.cs in .NET 6, before builder.Build() [duplicate]
Asked Answered
D

2

7

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();
Disgust answered 23/8, 2022 at 23:58 Comment(1)
E
7

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");
Ekaterinodar answered 24/8, 2022 at 1:58 Comment(2)
Thanks Chen. I just updated my question : Instead to create a logger from loggerFactory, 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 ?Disgust
There is no way to get the logger that would be created from the configuration at this point in the pipeline?Lofty
G
0

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));
        }
    }
}
Governor answered 24/8, 2022 at 0:15 Comment(2)
That's because you aren't using var host = ...Build() to dispose the host. Logs will be flushed when the service container is disposed.Judoka
Nope, most log factories/sinks doesn't even have Dispose pattern (NLog/Serilog have static class for this kind of problems and you lose exceptions if you not calling it).Governor

© 2022 - 2024 — McMap. All rights reserved.