Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Как автор библиотеки, предоставление логирования — отличный способ дать потребителям представление о внутренних процессах вашей библиотеки. Это руководство помогает обеспечивать логирование таким образом, чтобы оно соответствовало другим библиотекам и фреймворкам .NET. Это также помогает избежать распространенных узких мест производительности, которые могут не быть очевидными в противном случае.
Когда следует использовать ILoggerFactory
интерфейс
При написании библиотеки, которая выдает журналы, требуется ILogger объект для записи журналов. Чтобы получить этот объект, ваше API может принять ILogger<TCategoryName> параметр или принять ILoggerFactory, после чего вы вызываете ILoggerFactory.CreateLogger. Какой подход следует предпочесть?
Если вам нужен объект ведения журнала, который можно передать вместе с несколькими классами, чтобы все из них могли выдавать журналы, используйте
ILoggerFactory
. Рекомендуется, чтобы каждый класс создает журналы с отдельной категорией, которая называется той же, что и класс. Для этого необходимо, чтобы фабрика создавала уникальныеILogger<TCategoryName>
объекты для каждого класса, который ведет журнал. Распространенные примеры включают API общедоступной точки входа для библиотеки или общедоступных конструкторов типов, которые могут создавать вспомогательные классы внутри системы.Если вам нужен объект ведения журнала, который используется только в одном классе и никогда не используется совместно, используйте
ILogger<TCategoryName>
, гдеTCategoryName
— это тип, который создает журналы. Типичным примером этого является конструктор для класса, созданного путем внедрения зависимостей.
Если вы разрабатываете общедоступный API, который должен оставаться стабильным с течением времени, помните, что в будущем может потребоваться рефакторинг внутренней реализации. Даже если класс изначально не создает внутренние вспомогательные типы, которые могут измениться по мере развития кода. Использование ILoggerFactory
облегчает создание новых объектов для новых классов ILogger<TCategoryName>
, не изменяя общедоступный API.
Дополнительные сведения см. в статье о применении правил фильтрации.
Предпочитать ведение журнала, генерируемого из исходного кода
API ILogger
поддерживает два подхода к использованию API. Можно вызывать такие методы, как LoggerExtensions.LogError и LoggerExtensions.LogInformation, или использовать генератор источников ведения журнала для определения строго типизированных методов ведения журнала. В большинстве случаев генератор исходного кода рекомендуется, так как он обеспечивает более высокую производительность и строгую типизацию. Он также изолирует такие аспекты, как шаблоны сообщений, идентификаторы и уровни ведения журнала от вызывающего кода. Подход без генерации из исходного кода преимущественно полезен для сценариев, когда вы готовы пожертвовать этими преимуществами, чтобы сделать код более кратким.
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);
}
Предыдущий код:
- Определяет
partial class
с именемLogMessages
, который являетсяstatic
, чтобы его можно было использовать для определения методов расширения на типеILogger
. - Декорирует
LogProductSaleDetails
метод расширения с атрибутомLoggerMessage
и шаблономMessage
. - Объявляется
LogProductSaleDetails
, который расширяетILogger
и принимаетquantity
иdescription
.
Подсказка
Во время отладки можно перейти в исходный код, так как он является частью той же сборки, что и код, вызывающий его.
Использование IsEnabled
, чтобы избежать дорогостоящих вычислений параметров
Могут возникнуть ситуации, когда оценка параметров является дорогой. Расширяя предыдущий пример, представьте, что параметр description
— это string
, вычисление которого дорого обходится. Возможно, продаваемый продукт получает дружелюбное описание, основанное на запросе базы данных или на чтении данных из файла. В таких ситуациях можно указать генератору пропустить охранник IsEnabled
и вручную добавить охранник IsEnabled
в точке вызова. Это позволяет пользователю определить, где вызывается охранник, и гарантирует, что параметры, которые могут быть дорогостоящими для вычислений, оцениваются только при необходимости. Рассмотрим следующий код:
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
, охранник IsEnabled
вызывается вручную, и оценка дорогостоящих параметров ограничивается только в тех случаях, когда это необходимо. Рассмотрим следующий код:
if (_logger.IsEnabled(LogLevel.Information))
{
// Expensive parameter evaluation
var description = product.GetFriendlyProductDescription();
_logger.LogProductSaleDetails(
quantity,
description);
}
Дополнительные сведения см. в разделах Генерация источников журнала во время компиляции и высокопроизводительное ведение журнала в .NET.
Избегайте интерполяции строк в журнале
Распространенная ошибка заключается в использовании интерполяции строк для создания сообщений журнала. Интерполяция строк в логировании проблематична для производительности, так как строка вычисляется, даже если соответствующий LogLevel
не включен. Вместо интерполяции строк используйте шаблон сообщения журнала, форматирование и список аргументов. Дополнительные сведения см. в разделе "Ведение журнала в .NET: шаблон сообщения журнала".
Используйте настройки журнала no-op по умолчанию
Иногда при использовании библиотеки, которая предоставляет API ведения журнала, ожидающие либо ILogger
либо ILoggerFactory
, вы можете решить не предоставлять средство ведения журнала. В этих случаях пакет NuGet Microsoft.Extensions.Logging.Abstractions предоставляет no-op ведения журнала по умолчанию.
Потребители библиотеки могут по умолчанию регистрировать значение NULL , если не ILoggerFactory
указано. Использование ведения журнала NULL отличается от определения типов как допускающих значение NULL (ILoggerFactory?
), так как типы не являются null. Эти типы, основанные на удобстве, не логируют ничего и, по сути, не выполняют никаких операций. Рекомендуется использовать любой из доступных типов абстракции, в которых применимо: