https://d226lax1qjow5r.cloudfront.net/blog/blogposts/adaptive-library-logging-with-microsoft-extensions-logging-dr/E_Love-the-Log_1200x600.png

Journalisation adaptative de la bibliothèque avec Microsoft.Extensions.Logging

Publié le April 28, 2021

Temps de lecture : 4 minutes

Comment j'ai appris à ne plus m'inquiéter et à aimer le bûcheronnage

Au cours de ma carrière, j'ai travaillé sur plusieurs projets .NET de moyenne à grande envergure. Pour chaque projet, j'ai vu un type de logger différent, et en général, tous ces projets utilisaient plus d'un logger !

En général, l'histoire ressemble à ceci : "Au début, nous n'arrivions pas à choisir le logger que nous voulions utiliser, alors nous avons construit notre propre logger. Puis nous avons réalisé que la façon dont nous avions implémenté la journalisation n'était pas la plus efficace, et nous avons donc adopté le logger X au fur et à mesure de l'évolution de l'application. Nous ne voulions pas revenir en arrière et supprimer l'ancien logger car cela nous aurait obligés à toucher à tous les fichiers de notre solution, alors nous l'avons simplement supprimé des endroits où l'ancien logger posait des problèmes, et à partir de maintenant nous allons utiliser X logger pour tout.

Comme je l'ai dit, il s'agit d'un problème étonnamment courant, que l'on peut éviter en faisant abstraction de l'enregistreur et de la journalisation.

Connexion à la bibliothèque Nexmo .NET

Récemment, j'ai jeté un coup d'œil sur le SDK Nexmo .NET Server SDK de Nexmo de Nexmo et j'ai nettoyé certaines choses. En faisant cela, j'ai remarqué que notre cadre de journalisation LibLog était obsolète.

Cet outil était formidable, car il faisait abstraction de l'enregistreur et de l'opération d'enregistrement. Il permettait à toute personne développant avec notre SDK d'apporter son propre logger. Tant que votre logger était supporté, vous pouviez faire en sorte que le logger du SDK s'intègre dans le logger de votre choix sans aucune intervention (ce qui, de manière réaliste, peut être un avantage ou un inconvénient selon la manière dont vous le considérez).

En raison de la dépréciation de LibLog, j'ai été contraint de chercher ailleurs un outil de journalisation répondant à nos besoins. Heureusement, je n'ai pas eu à chercher bien loin.

Aller de l'avant avec Microsoft.Extensions.Logging

Le (relativement) nouveau Microsoft.Extensions.Logging a fait mouche en matière de fonctionnalité. Avec le package d'extension, vous pouvez simplement installer le package NuGet, ainsi que le framework de logging que vous avez choisi d'utiliser, mettre en place une usine et créer le logger.

Cela convient à notre cas d'utilisation, car nous ne voulons pas nécessairement que nos journaux se superposent et s'imbriquent automatiquement dans les journaux de nos utilisateurs - et en même temps, nous ne voulons pas dicter à nos utilisateurs exactement où, comment et avec quel cadre les journaux seront capturés.

Ainsi, avec notre prochaine version majeure, la 5.0.0, vous serez en mesure d'activer le niveau ou la catégorie que vous souhaitez dans le SDK de manière dynamique en remplaçant simplement l'usine d'enregistreurs dans le SDK.

Création de loggers avec Microsoft.Extensions.Logging

Construire le fournisseur de logs

Deux composants sont à la base de Microsoft.Extensions.Logging : ILoggerFactory et ILogger. La fabrique génère les enregistreurs et l'enregistreur se charge de l'enregistrement.

Ces deux composants sont utilisés dans la classe LogProvider pour nous permettre de créer un logger entièrement dynamique et extensible pour la bibliothèque, permettant au développeur d'apporter son propre logger.

public static class LogProvider
{
    private static IDictionary<string, ILogger> _loggers = new Dictionary<string, ILogger>();
    private static ILoggerFactory _loggerFactory = new LoggerFactory();

    public static void SetLogFactory(ILoggerFactory factory)
    {
        _loggerFactory?.Dispose();
        _loggerFactory = factory;
        _loggers.Clear();
    }

    public static ILogger GetLogger(string category)
    {
        if (!_loggers.ContainsKey(category))
        {
            _loggers[category] = _loggerFactory?.CreateLogger(category)?? NullLogger.Instance;
        }
        return _loggers[category];
    }
}

Dans notre modèle, nous créons une classe statique appelée LogProvider avec deux champs : _loggers, un dictionnaire contenant le logger pour chaque catégorie, et _loggerFactory, qui construit les loggers.

Il existe également deux méthodes : SetLogFactory, qui se débarrasse de l'ancienne LogFactory et définit la fabrique de logs avec la nouvelle fabrique de logs transmise, et GetLogger, qui vérifie dans _loggers si le logger de cette catégorie a été créé, et en crée un si ce n'est pas le cas.

Utilisation du fournisseur de journaux

Maintenant, au début de n'importe quelle méthode que nous voulons enregistrer, nous devons simplement appeler GetLogger avec la catégorie appropriée :

var logger = Api.Logger.LogProvider.GetLogger(LOGGER_CATEGORY);

Enregistrement

À partir de là, il suffit d'utiliser le logger comme n'importe quel autre logger que nous avons déjà vu. Par exemple :

logger.LogInformation("Available authentication: {0}", string.Join(",", authCapabilities));

Cette fonction enregistre comme information les capacités d'authentification disponibles dans le format que vous avez fourni à votre enregistreur.

Configuration des enregistreurs adaptatifs

Maintenant que nous avons abordé la création et l'utilisation des enregistreurs, voyons comment les configurer pour qu'ils fassent ce que nous voulons.

Sélectionnez votre fournisseur de logs

L'un des aspects intéressants de Microsoft.Extensions.Logging est qu'il est agonistique par rapport au fournisseur de logs que vous utilisez. Tant que ce dernier implémente l'interface, il peut être ce qu'il veut. ILogProvider l'interface, il peut être ce qu'il veut. Du point de vue du développeur qui essaie de l'exploiter, c'est encore plus simple. La plupart des principaux fournisseurs de logs tiers que vous êtes susceptible d'utiliser (par exemple Log4Net, Serilog, NLog, etc.) ont des packages d'extension qui facilitent l'ajout du logger souhaité.

Se connecter à la console avec Serilog

Pour démontrer comment nous pouvons construire ces loggers, prenons l'exemple de la déconnexion de la Console avec Serilog. Pour ce faire, vous aurez besoin des paquets NuGet suivants :

  • Microsoft.Extensions.Logging

  • Serilog.Extensions.Logging

  • Serilog.Sinks.Console

Vous ferez ensuite ce qui suit :

  • Créer un nouveau LoggerFactory qui sera utilisé pour créer

  • Créer une nouvelle LoggerConfiguration qui définira la configuration de Serilog

  • Appeler la fonction AddSerilog sur l'usine

  • Créer un logger de catégorie "test

  • Se déconnecter

Enchaînés les uns aux autres, ils se présentent comme suit :

var log = new LoggerConfiguration()
    .MinimumLevel.Debug()
    .WriteTo.Console(outputTemplate: "{Timestamp:HH:mm} [{Level}] ({Name:l}) {Message}\n")
    .CreateLogger();
var factory = new LoggerFactory();
factory.AddSerilog(log);
ILogger logger = factory.CreateLogger("test");
logger.LogInformation("Hello world");

Très propre et très simple.

Maintenant, pour interagir avec le Nexmo SDK, au lieu de créer un logger après avoir configuré la fabrique, il suffit de définir LogFactory dans le Log Provider à la fabrique de logs que vous avez créée et à laquelle vous avez ajouté Serilog, et vous verrez le logging venir du SDK.

var log = new LoggerConfiguration()
    .MinimumLevel.Debug()
    .WriteTo.Console(outputTemplate: "{Timestamp:HH:mm} [{Level}] ({Name:l}) {Message}\n")
    .CreateLogger();
var factory = new LoggerFactory();
factory.AddSerilog(log);
LogProvider.SetLogFactory(factory);

Et voilà - notre propre enregistreur de bibliothèque hautement configurable.

Avantages

Microsoft.Extensions.Logging nous permet d'éviter le scénario cauchemardesque qui consiste à démarrer un projet en utilisant un logger et à devoir, pour une raison ou une autre, passer à un autre.

Si vous souhaitez utiliser votre propre logger, vous êtes toujours libre de le faire, même en utilisant les Logging Extensions. Il vous suffit d'implémenter l'interface ILogProvider avec le logger que vous souhaitez utiliser et de l'ajouter à la fabrique.

Partager:

https://a.storyblok.com/f/270183/384x384/73d57fd8eb/stevelorello.png
Steve LorelloAnciens de Vonage

Ancien développeur .NET Advocate @Vonage, ingénieur logiciel polyglotte full-stack, AI/ML