Technique Logger le démarrage d'une application ASP.NET

Julien Chomarat Photo de Julien Chomarat

Julien Chomarat

Logger le démarrage d'une application ASP.NET

Dans cet article nous allons voir comment modifier le template de base d'une application aspnet pour logger les erreurs au démarrage.

Problème

Ci-dessous, vous avez le template proposé dans le Program.cs avec ses grandes étapes commentées.

// Création du WebApplicationBuilder
var builder = WebApplication.CreateBuilder(args);

// Enregistrement des services
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// Création de l'application
var app = builder.Build();

// Enregistrement des middleware et des endpoints
app.UseHttpsRedirection();

app.MapGet("/weatherforecast", () => { /* Code endpoint*/ })
    .WithName("GetWeatherForecast")
    .WithOpenApi();

// Démarrage de l'application
app.Run();

Comme vous pouvez le voir, le démarrage d'une application aspnet fait beaucoup de choses et peut donc planter à tout moment.

Si votre application démarre, tout va bien, vous avez un logger qui a été configuré automatiquement en fonction des informations dans votre appsettings.json et vous aurez des logs qui s'afficheront dans votre console.

En revanche, si elle ne démarre pas, vous n'aurez rien car le logger par défaut n'est pas encore disponible à ce moment.

Solution

Nous allons donc modifier ce template pas à pas pour rendre le démarrage un peu plus bavard.

// Les usings nécessaires pour récupérer les informations de base
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;

// On crée ici notre logger factory, avec une configuration simple
// Attention: le using ici est très important, il permet de faire un flush des logs
//            lors du Dispose
using var factory = LoggerFactory.Create(builder =>
              builder.AddSimpleConsole(options =>
              {
                  options.IncludeScopes = false;
                  options.SingleLine = true;
                  options.TimestampFormat = "HH:mm:ss ";
              }));
// On crée notre logger pour le démarrage
var logger = factory.CreateLogger<Program>();

try
{
    var builder = WebApplication.CreateBuilder(args);

    // Dans les lignes qui suivent, on affiche ici toutes les informations de base
    // de notre application et de l'environnement d'éxecution
    logger.LogInformation("-------------------------------------------------");
    logger.LogInformation("Starting... {Name}", Assembly.GetEntryAssembly()!.GetName().Name);
    logger.LogInformation("FrameworkName: {FrameworkName}",
        Assembly.GetEntryAssembly()!.GetCustomAttribute<TargetFrameworkAttribute>()?.FrameworkName);
    logger.LogInformation("OSDescription: {OSDescription}", RuntimeInformation.OSDescription);
    logger.LogInformation("OSArchitecture: {OSArchitecture}", RuntimeInformation.OSArchitecture);
    logger.LogInformation("ProcessArchitecture {ProcessArchitecture}", RuntimeInformation.ProcessArchitecture);
    logger.LogInformation("ProcessId: {ProcessId}", Environment.ProcessId);
    logger.LogInformation("Urls: {Urls}", builder.WebHost.GetSetting(WebHostDefaults.ServerUrlsKey)?.Replace(";", " "));
    logger.LogInformation("-------------------------------------------------");

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

    var app = builder.Build();

    app.UseHttpsRedirection();

    app.MapGet("/weatherforecast", () => { /* Code endpoint*/ })
        .WithName("GetWeatherForecast")
        .WithOpenApi();

    app.Run();
}
// Si le démarrage se passe mal alors on catch l'Exception et on la log
catch (Exception ex)
{
    logger.LogCritical(ex, "Application failed to start");
    throw;
}

Maintenant quand vous lancerez votre application vous aurez ces informations de disponibles

15:22:01 info: Program[0] -------------------------------------------------
15:22:01 info: Program[0] Starting... WebApplication1
15:22:01 info: Program[0] FrameworkName: .NETCoreApp,Version=v8.0
15:22:01 info: Program[0] OSDescription: Microsoft Windows 10.0.26100
15:22:01 info: Program[0] OSArchitecture: X64
15:22:01 info: Program[0] ProcessArchitecture X64
15:22:01 info: Program[0] ProcessId: 12572
15:22:01 info: Program[0] Urls: http://localhost:5234
15:22:01 info: Program[0] -------------------------------------------------

Par exemple, si votre application se bloque mais ne plante pas, vous connaissez le PID à inspecter.

Vous ne connaissez pas le PORT utilisé, vous avez aussi cette information.

Si votre application renvoie une Exception et s'arrête immédatiement vous aurez ce type de logs

15:41:44 info: Program[0] -------------------------------------------------
15:41:44 info: Program[0] Starting... WebApplication1
15:41:44 info: Program[0] FrameworkName: .NETCoreApp,Version=v8.0
15:41:44 info: Program[0] OSDescription: Microsoft Windows 10.0.26100
15:41:44 info: Program[0] OSArchitecture: X64
15:41:44 info: Program[0] ProcessArchitecture X64
15:41:44 info: Program[0] ProcessId: 29464
15:41:44 info: Program[0] Urls: http://localhost:5234
15:41:44 info: Program[0] -------------------------------------------------
15:41:44 crit: Program[0] Application failed to start
System.Exception: La configuration est manquante    at Program.<Main>$(String[] args)
in C:\dev\WebApplication1\WebApplication1\Program.cs:line 33

Vous disposez du Message et de la StackTrace afin de remonter à l'erreur d'origine.

Conclusion

Vous avez maintenant ce qu'il faut pour comprendre pourquoi votre application refuse de se lancer.

Ce qui est important ici est que ce Logger pour le démarrage est configuré manuellement ET en dur afin d'éviter les problèmes avec des dépendances externes (ex : un fichier de config ou un service distant).

Ce Logger est utilisé uniquement pendant le démarrage, ce n'est pas celui configuré et utilisé par l'application.

Je l'ai configuré ici pour envoyer les messages dans la console mais vous pouvez adapter ça à vos besoins. Au risque de me répéter, pensez à rester sur quelque chose de basique qui fonctionnera toujours.

Tags : C# Observability