Partager via


Conseils de journalisation pour les auteurs de bibliothèques .NET

En tant qu’auteur de bibliothèque, l’exposition de la journalisation est un excellent moyen de fournir aux consommateurs un aperçu des fonctionnements internes de votre bibliothèque. Cette aide vous aide à exposer la journalisation de manière cohérente avec d’autres bibliothèques et frameworks .NET. Elle vous permet également d’éviter les goulots d’étranglement des performances courants, qui peuvent ne pas être évidents autrement.

Quand utiliser l’interface ILoggerFactory

Lors de l’écriture d’une librairie qui émet des logs, vous avez besoin d’un ILogger objet pour enregistrer les logs. Pour obtenir cet objet, votre API peut accepter un ILogger<TCategoryName> paramètre ou accepter un ILoggerFactory après lequel vous appelez ILoggerFactory.CreateLogger. Quelle approche doit être recommandée ?

  • Lorsque vous avez besoin d'un objet de journalisation qui peut être transmis à plusieurs classes afin que toutes puissent générer des logs, utilisez ILoggerFactory. Il est recommandé que chaque classe crée des journaux d’activité avec une catégorie distincte, nommée de la même façon que la classe. Pour ce faire, vous avez besoin de la fabrique pour créer des objets ILogger<TCategoryName> uniques pour chaque classe qui émet des journaux. Les exemples courants incluent des API de point d’entrée publique pour une bibliothèque ou des constructeurs publics de types susceptibles de créer des classes d’assistance en interne.

  • Lorsque vous avez besoin d’un objet de journalisation qui n’est utilisé qu’à l’intérieur d’une classe et qui n’est jamais partagé, utilisez ILogger<TCategoryName>, où TCategoryName est le type qui produit les journaux. Un exemple courant est un constructeur pour une classe créée par l’injection de dépendances.

Si vous concevez une API publique qui doit rester stable au fil du temps, gardez à l’esprit que vous souhaiterez peut-être refactoriser votre implémentation interne à l’avenir. Même si une classe ne crée pas initialement de types d’assistance internes, cela peut changer à mesure que le code évolue. L’utilisation ILoggerFactory permet de créer ILogger<TCategoryName> des objets pour toutes les nouvelles classes sans modifier l’API publique.

Pour plus d’informations, consultez Comment les règles de filtrage sont appliquées.

Préférer la journalisation générée par la source

L’API ILogger prend en charge deux approches pour utiliser l’API. Vous pouvez appeler des méthodes telles que LoggerExtensions.LogError et LoggerExtensions.LogInformation, ou utiliser le générateur de source de journalisation pour définir des méthodes de journalisation fortement typées. Pour la plupart des situations, le générateur source est recommandé, car il offre des performances supérieures et un typage renforcé. Il isole également les problèmes spécifiques à la journalisation tels que les modèles de message, les ID et les niveaux de journalisation du code appelant. L’approche non générée par la source est principalement utile pour les scénarios où vous êtes prêt à renoncer à ces avantages pour rendre le code plus concis.

using Microsoft.Extensions.Logging;

namespace Logging.LibraryAuthors;

internal static partial class LogMessages
{
    [LoggerMessage(
        Message = "Sold {Quantity} of {Description}",
        Level = LogLevel.Information)]
    internal static partial void LogProductSaleDetails(
        this ILogger logger,
        int quantity,
        string description);
}

Code précédent :

  • Définit un partial class nommé LogMessages, qui est static afin qu’il puisse être utilisé pour définir des méthodes d’extension sur le type ILogger.
  • Décore une méthode d’extension LogProductSaleDetails avec l’attribut LoggerMessage et le modèle Message.
  • Déclare LogProductSaleDetails, qui étend le ILogger et accepte un quantity et un description.

Conseil / Astuce

Vous pouvez passer au code généré par la source pendant le débogage, car il fait partie du même assembly que le code qui l’appelle.

Utiliser IsEnabled pour éviter une évaluation coûteuse des paramètres

Il peut y avoir des situations où l’évaluation des paramètres est coûteuse. En développant l’exemple précédent, imaginez que le description paramètre est un string paramètre coûteux à calculer. Peut-être que le produit vendu obtient une description de produit conviviale et s’appuie sur une requête de base de données ou la lecture à partir d’un fichier. Dans ces situations, vous pouvez demander au générateur de code de sauter la protection IsEnabled et d'ajouter manuellement la protection IsEnabled au point d'appel. Cela permet à l’utilisateur de déterminer où le garde est appelé et garantit que les paramètres susceptibles d’être coûteux pour le calcul ne sont évalués que si nécessaire. Considérez le code suivant :

using Microsoft.Extensions.Logging;

namespace Logging.LibraryAuthors;

internal static partial class LogMessages
{
    [LoggerMessage(
        Message = "Sold {Quantity} of {Description}",
        Level = LogLevel.Information,
        SkipEnabledCheck = true)]
    internal static partial void LogProductSaleDetails(
        this ILogger logger,
        int quantity,
        string description);
}

Lorsque la méthode d'extension LogProductSaleDetails est appelée, la méthode de garde IsEnabled est exécutée manuellement, et l'évaluation coûteuse des paramètres est limitée aux cas où elle est nécessaire. Considérez le code suivant :

if (_logger.IsEnabled(LogLevel.Information))
{
    // Expensive parameter evaluation
    var description = product.GetFriendlyProductDescription();

    _logger.LogProductSaleDetails(
        quantity,
        description);
}

Pour plus d’informations, consultez Génération de la source de journalisation au moment de la compilation et journalisation à hautes performances dans .NET.

Éviter l’interpolation de chaîne dans la journalisation

Une erreur courante consiste à utiliser l’interpolation de chaîne pour générer des messages de journal. L’interpolation de chaîne dans la journalisation est problématique pour les performances, car la chaîne est évaluée même si la chaîne correspondante LogLevel n’est pas activée. Au lieu d’interpolation de chaîne, utilisez le modèle de message de journal, la mise en forme et la liste d’arguments. Pour plus d’informations, consultez Journalisation dans .NET : Modèle de message de journal.

Utiliser les paramètres par défaut de la journalisation no-op (sans opération)

Dans certains cas, lorsque vous consommez une bibliothèque exposant les API de journalisation qui s’attendent à un ILogger ou à un ILoggerFactory, vous ne souhaitez pas forcément fournir d’enregistreur d’événements. Dans ces cas, le package NuGet Microsoft.Extensions.Logging.Abstractions fournit no-op paramètres de journalisation par défaut.

Les utilisateurs de la bibliothèque peuvent utiliser la journalisation null par défaut si aucun ILoggerFactory n’est fourni. L’utilisation de la journalisation null diffère de la définition des types comme pouvant accéder à la valeur null (ILoggerFactory?), car les types ne sont pas null. Ces types pratiques ne journalisent rien et ne sont essentiellement sans opération. Envisagez d’utiliser l’un des types d’abstraction disponibles le cas échéant :