Why should we write logs from the startup of an application?

Usually, we write logs from various application events and user interactions. These are to record what activities the user performs, what data the app deals with, etc. When something goes wrong with our application in production, the logs help us to investigate what went wrong. However, in some cases, writing logs during the application startup will come to our rescue. For instance, if our application fails during startup, the logs that it writes during startup will help us troubleshoot the issue.

In this article, we are going to learn how to write logs from the Program and Startup classes.

To download the source code for this article, you can visit our GitHub repository.

So let’s get started.

How to Write Logs From the Program Class?

Let’s say we are creating web applications using the latest ASP.NET Core web app templates such as .NET 6 or .NET 7.  We start by building a web application object using the WebApplicationBuilder class. Then, we add all the required services and build the web application object. This provides a streamlined way of building a web application without the use of a Startup class.

Once we build a web application this way, it will have a default logger service attached to it. We can access the logger service using the WebApplication.Logger property from the Program class. After accessing the logger service, we can use its methods to write logs from the Program class:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

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

var app = builder.Build();

app.Logger.LogInformation("This is an informational log from Program.cs");

Here, we create a new instance of the WebApplicationBuilder class using WebApplication.CreateBuilder() method.

Next, we add all the required services to the builder instance. After that, we build the web application by calling the Build() method.

Finally, once we build the web application, we can access the logger service using the WebApplication.Logger instance to write logs.

On running the application, we see that it writes this log from the Program class when the application is starting up:

info: LoggingFromProgram[0]
      This is an informational log from Program.cs

About Minimal API

If we are creating API endpoints using minimal APIs, we will not be creating controller classes for defining action methods. Instead, we’ll be defining API endpoints and mapping them to a request delegate or a method from within the Program class.

Now if we want to write logs from the request delegate, we can access the logger service of the app and write logs, just like we’ve done for logging in the Program class example.

Remember that in this case, we are writing logs from within the API endpoint, but just that we are binding the logger from the Program class directly.

However, if we are organizing our mapping method into a separate service, then we can just inject the logger service into the method using dependency injection (DI).

How to Write Logs From the Main() Method?

If we are creating ASP.NET Core applications using an older template such as .NET 5 or earlier that comes with separate Program and  Startup classes, things are a bit different. Here we will have the Main() method in the Program class that first builds a host and then specifies the startup type.

Of course, we will have a separate Startup class as well that adds and configures all the services. In this case, it is possible to write logs either in the Main() method or in the Startup class.

For writing logs in the Main() method,  we can get an instance of ILogger from DI after initializing the host:

public static void Main(string[] args)
{
    var host = CreateHostBuilder(args).Build();

    var logger = host.Services.GetRequiredService<ILogger<Program>>();
    logger.LogInformation("This is an informational log from Main()");

    host.Run();
}

Here, we use the Services.GetRequiredService() method to get the logger service instance from the service container at runtime and use it to write logs.

On running the application, we can see that the Main() method generates this log during the application startup:

info: LoggingFromStartup.Program[0]
      This is an informational log from Main()

This way we can write logs from the Main() method of an application that uses .NET 5 or earlier.

How to Add Logging in the Startup Class?

While using .NET 5 or earlier versions, it is possible to access the logger service from the Startup class as well. However, remember that we can access the logger service only after the DI container is set up. That means it is not possible to inject the logger into the Startup class’s constructor or the ConfigureServices() method. The DI container will be ready only after the ConfigureServices() method completes its execution. What this implies is that the logger service will be ready for use only in the Configure() method.

Let’s inject the logger service into the Configure() method of the Startup class:

public void Configure(IApplicationBuilder app, 
    IWebHostEnvironment env, 
    ILogger<Startup> logger)
{
    logger.LogInformation("This is an informational log from Startup.cs");

    // code removed for brevity

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

Here, we inject the ILogger service into the Configure() method and use it to write the logs.

When we run the application, we can see that this time it writes some additional logs which come from the Startup class:

info: LoggingFromStartup.Program[0]
      This is an informational log from Main()
info: LoggingFromStartup.Startup[0]
      This is an informational log from Startup.cs

This way, we can write logs from the Configure() method of the  Startup class.

Conclusion

In this article, we learned how to write logs from the startup of .NET applications. For newer versions such as .NET 6, .NET 7, etc., we learned how to write logs from the  Program class as it does not come with a Startup class. For older versions such as .NET 5 and earlier, we learned how to write logs from both the Main() method and the Startup class.