Sdílet prostřednictvím


Pokyny k protokolování pro autory knihoven .NET

Jako autor knihovny představuje zveřejnění protokolování skvělý způsob, jak uživatelům poskytnout přehled o vnitřních pracovních činnostech vaší knihovny. Tyto pokyny vám pomůžou odhalit protokolování způsobem, který je konzistentní s ostatními knihovnami a architekturami .NET. Pomůže vám také vyhnout se běžným kritickým bodům výkonu.

Kdy použít ILoggerFactory rozhraní

Při zápisu knihovny, která generuje protokoly, potřebujete ILogger objekt k zaznamenání protokolů. Pokud chcete tento objekt získat, vaše rozhraní API může buď přijmout parametr ILogger<TCategoryName>, nebo přijmout ILoggerFactory, po kterém zavolá ILoggerFactory.CreateLogger. Který přístup by měl být upřednostňovaný?

  • Pokud potřebujete objekt protokolování, který lze předat do více tříd, aby všechny z nich mohly generovat protokoly, použijte ILoggerFactory. Doporučuje se, aby každá třída vytvářela logy s oddělenou kategorií, která má stejný název jako třída. K tomu potřebujete, aby továrna vytvořila jedinečné ILogger<TCategoryName> objekty pro každou třídu, která generuje logy. Mezi běžné příklady patří rozhraní API veřejného vstupního bodu pro knihovnu nebo veřejné konstruktory typů, které můžou interně vytvářet pomocné třídy.
  • Pokud potřebujete objekt protokolování, který se používá pouze v jedné třídě a nikdy nesdílí, použijte ILogger<TCategoryName>, kde TCategoryName je typ, který vytváří protokoly. Běžným příkladem je konstruktor pro třídu vytvořenou vkládáním závislostí.

Pokud navrhujete veřejné rozhraní API, které musí v průběhu času zůstat stabilní, mějte na paměti, že v budoucnu budete chtít refaktorovat interní implementaci. I když třída zpočátku nevytvoří žádné interní pomocné typy, může se to při vývoji kódu změnit. Pomocí ILoggerFactory je možné vytvářet nové ILogger<TCategoryName> objekty pro všechny nové třídy, aniž by se změnilo veřejné rozhraní API.

Další informace naleznete v tématu Jak se používají pravidla filtrování.

Preferujte protokolování generované zdrojem

Rozhraní ILogger API podporuje dva přístupy k používání rozhraní API. Můžete buď volat takové metody, jako LoggerExtensions.LogError a LoggerExtensions.LogInformation, nebo můžete použít generátor zdroje logování k definování silně typovaných metod protokolování. Ve většině situací se doporučuje generátor zdrojového kódu, protože nabízí vynikající výkon a silnější typování. Izoluje také aspekty specifické pro protokolování, jako jsou šablony zpráv, ID a úrovně protokolů, od volajícího kódu. Negenerovaný přístup je primárně užitečný pro scénáře, kdy jste ochotni tyto výhody vzdát, aby byl kód výstižnější.

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

Předchozí kód:

  • Definuje partial class pojmenovaný LogMessages, což je static, aby mohly být použity k definování rozšiřujících metod na typu ILogger.
  • Ozdobí rozšiřující metodu LogProductSaleDetails atributem LoggerMessage a Message šablonou.
  • Deklaruje se LogProductSaleDetails, který rozšiřuje ILogger a přijímá quantity a description.

Návod

Během ladění můžete vstupovat do zdrojového kódu, protože je součástí stejného sestavení jako kód, který ho volá.

Slouží IsEnabled k zabránění nákladnému vyhodnocení parametrů.

Při vyhodnocování parametrů mohou nastat situace, kdy je vyhodnocení parametrů nákladné. Rozšířením předchozího příkladu description si představte, že parametr je nákladný string pro výpočty. Možná, že produkt, který je prodáván, získá přátelský popis a spoléhá se na dotaz do databáze nebo na čtení ze souboru. V těchto situacích můžete dát generátoru zdroje pokyn, aby přeskočil IsEnabled stráž a ručně přidal IsEnabled stráž v místě volání. To uživateli umožňuje určit, kde se stráž volá, a zajišťuje, že parametry, které by mohly být nákladné na výpočet, se vyhodnocují pouze tehdy, když je to skutečně potřeba. Vezměte v úvahu následující kód:

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

LogProductSaleDetails Při zavolání IsEnabled metody rozšíření je ochrana vyvolána ručně a nákladné vyhodnocení parametrů je omezené na to, kdy je potřeba. Vezměte v úvahu následující kód:

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

    _logger.LogProductSaleDetails(
        quantity,
        description);
}

Další informace najdete v tématu Generování zdroje protokolování v době kompilace a protokolování s vysokým výkonem v .NET.

Vyhněte se interpolaci řetězců při protokolování

Běžnou chybou je použití interpolace řetězců k vytváření zpráv protokolu. Interpolace řetězců v logování je problematická pro výkon, protože se řetězec vyhodnotí i v případě, že odpovídající LogLevel není povoleno. Místo interpolace řetězců použijte šablonu zprávy protokolu, formátování a seznam argumentů. Další informace naleznete v tématu Protokolování v .NET: Šablona zprávy protokolu.

Použití výchozích hodnot protokolování no-op

Když využíváte knihovnu poskytující rozhraní API pro protokolování, které očekávají buď ILogger nebo ILoggerFactory, může se stát, že nebudete chtít poskytnout logger. V těchto případech balíček NuGet Microsoft.Extensions.Logging.Abstractions poskytuje výchozí nastavení protokolování no-op.

Uživatelé knihovny mohou použít výchozí protokolování s hodnotou null, pokud není poskytováno ILoggerFactory. Použití null logging se liší od definování typů jako nullable (ILoggerFactory?), protože typy nejsou nullovatelné. Tyto typy zaměřené na pohodlí nic nezapisují a v podstatě neprovádí žádnou operaci. Zvažte použití některého z dostupných typů abstrakce, pokud je to možné: