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 infrastructures .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 bibliothèque qui émet des journaux, vous avez besoin d’un objet ILogger pour enregistrer les journaux. Pour obtenir cet objet, votre API peut accepter un paramètre ILogger<TCategoryName> ou accepter un ILoggerFactory après lequel vous appelez ILoggerFactory.CreateLogger. Quelle approche doit être préférée ?

  • Lorsque vous avez besoin d’un objet de journalisation qui peut être transmis à plusieurs classes afin que tous puissent émettre des journaux, 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 les API de point d’entrée publique pour une bibliothèque ou les 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 en 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 voudrez 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 avec l’évolution du code. L’utilisation de ILoggerFactory permet de créer de nouveaux objets ILogger<TCategoryName> pour toutes les nouvelles classes sans modifier l’API publique.

Pour plus d’informations, consultez Application des règles de filtrage.

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

L’API ILogger prend en charge deux approches pour l’utiliser. 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. Dans la plupart des cas, le générateur de source est recommandé car il offre des performances supérieures et une typage plus fort. Il isole également les problèmes spécifiques à la journalisation comme 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 dans lesquels 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);
}

Le code précédent :

  • Définit un partial class nommé LogMessages, qui est static de sorte qu’il peut ê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 ILogger et accepte une quantity et une description.

Conseil

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.

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

Il peut exister des situations où l’évaluation des paramètres est coûteuse. En développant de l’exemple précédent, imaginez que le paramètre description est un string 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 source d’ignorer la protection IsEnabled et d’ajouter manuellement la protection IsEnabled sur le site d’appel. Cela permet à l’utilisateur de déterminer où la protection est appelée et garantit que les paramètres susceptibles d’être coûteux à calculer ne sont évalués que si nécessaire. Examinons le code ci-dessous.

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 protection IsEnabled est appelée manuellement et l’évaluation coûteuse des paramètres est limitée aux moments où elle est nécessaire. Examinons le code ci-dessous.

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 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 le LogLevel correspondant n’est pas activé. Au lieu de l’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 qui expose les API de journalisation qui s’attendent à un ILogger ou ILoggerFactory, vous ne souhaitez pas forcément fournir d’enregistreur d’événements. Dans ce cas, le package NuGet Microsoft.Extensions.Logging.Abstractions fournit des valeurs par défaut de journalisation sans opération.

Les consommateurs de bibliothèques 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 :