Cycle d'initialisation et gestion du logger statique Serilog sous ASP.NET Core

La phase de pré-démarrage d’une application ASP.NET Core nécessite un composant de traçage capable d’absorber les exceptions survenant avant la finalisation du conteneur de dépendances. Serilog met en œuvre ce scénario via une instance de travail éphémère :

// Capture des erreurs critiques durant la construction du builder web
var stageOneConfig = new LoggerConfiguration()
    .WriteTo.Console()
    .CreateBootstrapLogger();
Log.Logger = stageOneConfig;

L’extension UseSerilog(), fournie par le package Serilog.AspNetCore, prend ensuite le relais pour brancher le système sur le moteur de configuration de l’application. Son overload expose le booléen preserveStaticLogger, initialisé à false par convention.

Lorsqu’il demeure non spécifié, le runtime identifie si la référence courante implémente ReloadableLogger. Ce modèle permet de basculer vers une nouvelle configuration sans bloquer le thread hôte :

if (Log.Logger is ReloadableLogger currentProvider)
{
    currentProvider.Refresh(configBuilder =>
    {
        configBuilder.WriteTo.Providers(serviceProviderCollection);
        configureDelegate(applicationContext, serviceContainer, configBuilder);
        return configBuilder;
    });
}

Le traitement aboutit à la création d’un objet RegisteredLogger, qui devient la nouvelle cible assignée à la propriété statique Log.Logger. En parallèle, le framework Microsoft doit être relié à cette même instance afin de maintenir la cohérence du pipeline global.

L’injection de ILoggerFactory s’effectue via le wrapper dédié :

var factoryPipeline = new SerilogLoggerFactory(
    resolvedLogger: microsoftTarget, 
    disposeOnShutdown: false, 
    extraProviders: configuredProviders
);
services.AddSingleton<ILoggerFactory>(factoryPipeline);

À l’intérieur de SerilogLoggerFactory, chaque demande de logger par nom de catégorie instancie un SerilogLogger. Le constructeur affecte null au champ privé _logger. Durant l’exécution réelle (BeginScope ou vérification du niveau de criticité), la logique intervient avec Serilog.Log.Logger comme fallback. Cela assure que tout consommateur utilisant l’interface Microsoft.Extensions.Logging.ILogger redirige son flux vers le logger Serilog pleinement chargé.

Pour conserver deux chaînes distinctes, il suffit de passer true à preserveStaticLogger :

ILogger concreteLogger = serviceProvider.GetRequiredService<RegisteredLogger>().Logger;
ILogger bridgeInstance = preserveStaticLogger ? concreteLogger : null;

if (!preserveStaticLogger)
    Log.Logger = concreteLogger;

var isolatedFactory = new SerilogLoggerFactory(bridgeInstance ?? concreteLogger, !useDynamicReload, sourceProviders);

Dans ce mode isolé, la couche Microsoft Logging pointera vers une instance distincte tandis que Serilog.Log.Logger gardera sa référence initiale. Par ailleurs, le paramètre writeToProviders de UseSerilog() étant vide par défaut, les autres fournisseurs déjà enregistrés dans le conteneur ne sont pas fusionnés automatiquement. Une configuration explicite via .WriteTo.Providers(...) reste nécessaire pour activer cette interopérabilité.

Étiquettes: Serilog ASP.NET Core Dependency Injection ILoggerFactory ReloadableLogger

Publié le 27 septembre à 03h21