Condividi tramite


Materiale sussidiario sulla registrazione per gli autori di librerie .NET

In qualità di autore di una libreria, esporre la registrazione è un ottimo modo per fornire ai consumer informazioni dettagliate sul funzionamento interno della libreria. Questo materiale sussidiario consente di esporre la registrazione in modo coerente con altre librerie e framework .NET. Consente inoltre di evitare colli di bottiglia comuni che potrebbero non essere altrimenti evidenti.

Quando usare l'interfaccia ILoggerFactory

Quando si scrive una libreria che genera i log, è necessario un oggetto ILogger per registrare i log. Per ottenere tale oggetto, l'API può accettare un parametro ILogger<TCategoryName>, oppure può accettare un ILoggerFactory dopo il quale si chiama ILoggerFactory.CreateLogger. Quale approccio preferire?

  • Quando è necessario un oggetto di registrazione che può essere passato a più classi in modo che tutte possano generare log, usare ILoggerFactory. È consigliabile che ogni classe crei log con una categoria separata, che abbia lo stesso nome della classe. A tale scopo, è necessario che la factory crei oggetti ILogger<TCategoryName> univoci per ogni classe che genera log. Esempi comuni includono API del punto di ingresso pubblico per una libreria o costruttori pubblici di tipi che potrebbero creare classi helper internamente.

  • Quando è necessario un oggetto di registrazione usato solo all'interno di una classe e mai condiviso, usare ILogger<TCategoryName>, in cui TCategoryName è il tipo che produce i log. Un esempio comune di questo tipo è il costruttore di una classe creata tramite iniezione di dipendenza.

Se si progetta un'API pubblica che deve rimanere stabile nel tempo, tenere presente che potrebbe essere opportuno effettuare il refactoring dell'implementazione interna in futuro. Anche se inizialmente una classe non crea alcun tipo di helper interno, ciò potrebbe cambiare man mano che il codice si evolve. L'uso di ILoggerFactory consente di creare nuovi oggetti ILogger<TCategoryName>per qualsiasi nuova classe senza modificare l'API pubblica.

Per altre informazioni, vedere Come vengono applicate le regole di filtro.

Preferire la registrazione generata dall'origine

L'API ILogger supporta due approcci all'uso dell'API. È possibile chiamare metodi come LoggerExtensions.LogError e LoggerExtensions.LogInformation, oppure usare il generatore di origine della registrazione per definire metodi di registrazione fortemente tipizzati. Per la maggior parte delle situazioni, è consigliabile usare il generatore di origine, in quanto offre prestazioni superiori e una tipizzazione più forte. Inoltre, isola dal codice chiamante i problemi specifici della registrazione, ad esempio modelli di messaggio, ID e livelli di log. L'approccio non generato dall'origine è utile principalmente per gli scenari in cui si è disposti a rinunciare a tali vantaggi per rendere il codice più conciso.

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);
}

Il codice precedente:

  • Definisce un partial class oggetto denominato LogMessages, che è static, in modo che possa essere usato per definire i metodi di estensione del tipo ILogger.
  • Decora un metodo di estensione LogProductSaleDetails con l'attributo LoggerMessage e il modello Message.
  • Dichiara LogProductSaleDetails, che estende il ILogger e accetta un quantity e description.

Suggerimento

È possibile eseguire l'istruzione nel codice generato dall'origine durante il debug, perché fa parte dello stesso assembly del codice che lo chiama.

Usare IsEnabled per evitare costose valutazioni dei parametri

Possono verificarsi situazioni in cui la valutazione dei parametri è costosa. Espandendo l'esempio precedente, si supponga che il parametro description sia un string costoso da calcolare. Ad esempio, il prodotto venduto ottiene una descrizione amichevole del prodotto e si basa su una query del database o sulla lettura di un file. In queste situazioni, è possibile indicare al generatore di origine di ignorare la guard IsEnabled e aggiungere manualmente la guard IsEnabled nel sito di chiamata. Ciò consente all'utente di determinare dove viene chiamata la guard e garantisce che i parametri che potrebbero essere costosi da calcolare vengano valutati solo quando veramente necessari. Osservare il codice seguente:

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);
}

Quando viene chiamato il metodo di estensione LogProductSaleDetails, la guard IsEnabled viene richiamata manualmente e la costosa valutazione dei parametri viene limitata al momento in cui è necessaria. Osservare il codice seguente:

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

    _logger.LogProductSaleDetails(
        quantity,
        description);
}

Per altre informazioni, vedere Generazione dell'origine di registrazione in fase di compilazione e Registrazione ad alte prestazioni in .NET.

Evitare l'interpolazione di stringhe nella registrazione

Un errore comune consiste nell'usare l'interpolazione di stringhe per creare messaggi di log. L'interpolazione di stringhe durante la registrazione è problematica in termini di prestazioni, poiché la stringa viene valutata anche se la corrispondente LogLevel non è abilitata. Anziché l'interpolazione di stringhe, usare il modello di messaggio di log, la formattazione e l'elenco di argomenti. Per altre informazioni, vedere Registrazione in .NET: modello di messaggio di log.

Usare le impostazioni predefinite per la registrazione no-op

In alcuni casi, quando si usa una libreria che espone le API di registrazione che prevedono un ILogger oggetto o ILoggerFactory, che non si vuole fornire un logger. In questi casi, il pacchetto NuGet Microsoft.Extensions.Logging.Abstractions fornisce impostazioni predefinite di registrazione senza operazioni.

I consumer di libreria possono impostare come impostazione predefinita la registrazione Null se non viene fornito alcun ILoggerFactory valore. L'uso della registrazione Null differisce dalla definizione dei tipi come nullable (ILoggerFactory?), in quanto i tipi non sono Null. Questi tipi basati su praticità non registrano nulla e sono essenzialmente no-op. È consigliabile usare uno dei tipi astratti disponibili, se applicabile: