Ведение журнала в .NET

.NET поддерживает API ведения журнала, который работает с разными встроенными и сторонними поставщиками. В этой статье описано, как использовать в коде API ведения журналов, работающего со встроенными поставщиками. Большинство примеров кода, приведенных в этой статье, применимы к любому приложению .NET, которое использует универсальный узел. Если вы используете приложения, которые не используют универсальный узел, см. статью Консольное приложение без размещения.

Совет

Весь пример исходного кода для ведения журнала доступен для загрузки в Обозревателе примеров. Дополнительные сведения см. в разделе Обзор примеров кода: ведение журнала в .NET.

Важно!

Начиная с .NET 6 службу ведения журналов больше не регистрируют тип ILogger. Если используется средство ведения журнала, укажите альтернативу ILogger<TCategoryName> универсального типа или выполните регистрацию ILogger с помощью внедрения зависимости (DI).

Создание журналов

Чтобы создать журналы, используйте объект ILogger<TCategoryName> из внедрения зависимости.

В следующем примере происходит следующее:

  • Создает средство ведения журнала ILogger<Worker>, которое использует категорию журналов с полным именем типа Worker. Категория ведения журналов представляет строку, которая связана с каждым журналом.
  • Вызывает метод LogInformation для ведения журналов на уровне Information. Уровень ведения журналов определяет степень серьезности или важности записанного в журнал события.
public class Worker : BackgroundService
{
    private readonly ILogger<Worker> _logger;

    public Worker(ILogger<Worker> logger) =>
        _logger = logger;

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            _logger.LogInformation("Worker running at: {time}", DateTimeOffset.UtcNow);
            await Task.Delay(1000, stoppingToken);
        }
    }
}

Уровни и категории рассматриваются подробнее далее в этой статье.

Настройка журнала

Конфигурацию ведения журналов обычно предоставляет раздел Logging в файлах appsettings.{Environment}.json. Шаблоны рабочей службы .NET создают следующий файл appsettings.Development.json:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  }
}

В приведенном выше документе JSON:

  • Указаны категории "Default", "Microsoft"и "Microsoft.Hosting.Lifetime".
  • Категория "Microsoft" применяется ко всем категориям, начинающимся с "Microsoft".
  • Категория "Microsoft" задает ведение журналов на уровне Warning и более высоком.
  • Категория "Microsoft.Hosting.Lifetime" является более детальной по сравнению с "Microsoft", поэтому при выборе категории "Microsoft.Hosting.Lifetime" ведение журналов осуществляется на уровне "Информация" и более высоком.
  • Поскольку конкретный поставщик журналов не указан, LogLevel применяется ко всем включенным поставщикам, за исключением Windows EventLog.

Свойство Logging может иметь свойство LogLevel и свойства поставщика журналов. Свойство LogLevel указывает минимальный уровень журнала для выбранных категорий. В приведенном выше коде JSON заданы уровни ведения журнала Information и Warning. LogLevel определяет степень серьезности журнала и задается в диапазоне от 0 до 6:

Trace = 0, Debug = 1, Information = 2, Warning = 3, Error = 4, Critical = 5 и None = 6.

Если задан LogLevel, журналы будут вестись для сообщений с указанным и более высокими уровнями. В приведенном выше коде JSON задается ведение журналов для категории Default для сообщений с уровнем Information и более высоким. Например, в журнал записываются сообщения с уровнями Information, Warning, Error и Critical. Если LogLevel не задан, по умолчанию устанавливается уровень ведения журналов Information. Дополнительные сведения см. в статье Уровни ведения журналов.

Свойство поставщика может задавать свойство LogLevel. Свойство LogLevel поставщика определяет уровень ведения журналов для этого поставщика и переопределяет любые другие не относящиеся к поставщику параметры ведения журналов. Рассмотрите следующий файл appsettings.json:

{
    "Logging": {
        "LogLevel": {
            "Default": "Error",
            "Microsoft": "Warning"
        },
        "Debug": {
            "LogLevel": {
                "Default": "Information",
                "Microsoft.Hosting": "Trace"
            }
        },
        "EventSource": {
            "LogLevel": {
                "Default": "Warning"
            }
        }
    }
}

Параметры в Logging.{ProviderName}.LogLevel переопределяют параметры в Logging.LogLevel. В приведенном выше коде JSON для поставщика Debug задается уровень ведения журнала по умолчанию Information:

Logging:Debug:LogLevel:Default:Information

Приведенный выше параметр задает уровень ведения журнала Information для всех категорий Logging:Debug:, за исключением Microsoft.Hosting. Если задана конкретная категория, она переопределяет категорию по умолчанию. В приведенном выше коде JSON категории Logging:Debug:LogLevel"Microsoft.Hosting" и "Default" переопределяют параметры в Logging:LogLevel.

Минимальный уровень ведения журнала можно указать для:

  • конкретных поставщиков, например Logging:EventSource:LogLevel:Default:Information
  • конкретных категорий. Например: Logging:LogLevel:Microsoft:Warning
  • всех поставщиков и всех категорий: Logging:LogLevel:Default:Warning

Любые журналы с уровнем ниже минимального:

  • не передаются поставщику;
  • не записываются в журнал и не отображаются.

Чтобы отключить все журналы, укажите LogLevel.None. LogLevel.None имеет значение 6, то есть выше LogLevel.Critical (5).

Если поставщик поддерживает области журналов, IncludeScopes определяет, включены ли они. Дополнительные сведения см. в статье Области журналов.

Следующий файл appsettings.json содержит параметры для всех встроенных поставщиков:

{
    "Logging": {
        "LogLevel": {
            "Default": "Error",
            "Microsoft": "Warning",
            "Microsoft.Hosting.Lifetime": "Warning"
        },
        "Debug": {
            "LogLevel": {
                "Default": "Information"
            }
        },
        "Console": {
            "IncludeScopes": true,
            "LogLevel": {
                "Microsoft.Extensions.Hosting": "Warning",
                "Default": "Information"
            }
        },
        "EventSource": {
            "LogLevel": {
                "Microsoft": "Information"
            }
        },
        "EventLog": {
            "LogLevel": {
                "Microsoft": "Information"
            }
        },
        "AzureAppServicesFile": {
            "IncludeScopes": true,
            "LogLevel": {
                "Default": "Warning"
            }
        },
        "AzureAppServicesBlob": {
            "IncludeScopes": true,
            "LogLevel": {
                "Microsoft": "Information"
            }
        },
        "ApplicationInsights": {
            "LogLevel": {
                "Default": "Information"
            }
        }
    }
}

В предыдущем примере:

  • Категории и уровни не являются предлагаемыми значениями. Этот пример представлен с целью продемонстрировать все поставщики по умолчанию.
  • Параметры в Logging.{ProviderName}.LogLevel переопределяют параметры в Logging.LogLevel. Например, уровень в Debug.LogLevel.Default переопределяет уровень в LogLevel.Default.
  • Для каждого поставщика используется псевдоним. Каждый поставщик определяет псевдоним, используемый в конфигурации вместо полного имени типа. Ниже перечислены псевдонимы встроенных поставщиков.
    • Консоль
    • Отладка
    • EventSource
    • EventLog
    • AzureAppServicesFile
    • AzureAppServicesBlob
    • ApplicationInsights

Настройка уровня ведения журнала с помощью командной строки, переменных среды и других способов конфигурации

Уровень ведения журнала может задаваться любыми поставщиками конфигурации. Например, вы можете создать хранимую переменную среды с именем Logging:LogLevel:Microsoft и значением Information.

Создайте хранимую переменную среды и присвойте ей значение уровня ведения журнала.

:: Assigns the env var to the value
setx "Logging__LogLevel__Microsoft" "Information" /M

В новом экземпляре командной строки считайте эту переменную среды.

:: Prints the env var value
echo %Logging__LogLevel__Microsoft%

Указанный выше параметр среды сохраняется в среде. Чтобы проверить параметры при работе с приложением, созданным на базе шаблонов рабочей службы .NET, выполните команду dotnet run в каталоге проекта после назначения переменной среды.

dotnet run

Совет

После настройки переменной среды перезапустите интегрированную среду разработки, чтобы гарантировать доступность добавленных переменных среды.

В Службе приложений Azure выберите Новый параметр приложения на странице Параметры > Конфигурация. Параметры приложения Службы приложений Azure:

  • Шифруются, когда они неактивны, и передаются по зашифрованному каналу.
  • Предоставляются как переменные среды.

Дополнительные сведения о настройке значений конфигурации .NET с помощью переменных среды см. в разделе Поставщик конфигурации переменных среды.

Применение правил фильтрации

При создании объекта ILogger<TCategoryName> объект ILoggerFactory выбирает одно правило для каждого поставщика, которое будет применено к этому средству ведения журналов. Все сообщения, записываемые с помощью экземпляра ILogger, фильтруются на основе выбранных правил. Самое подробное правило для каждой пары поставщика и категории выбирается из списка доступных правил.

При создании ILogger для данной категории для каждого поставщика используется приведенный далее алгоритм:

  • Выберите все правила, которые соответствуют поставщику или его псевдониму. Если ничего не найдено, выберите все правила с пустым поставщиком.
  • В результатах предыдущего шага выберите правила с самым длинным соответствующим префиксом категории. Если ничего не найдено, выберите все правила, которые не указывают категорию.
  • Если выбрано несколько правил, примите последнее.
  • Если правила не выбраны, укажите минимальный уровень ведения журнала с помощью LoggingBuilderExtensions.SetMinimumLevel(ILoggingBuilder, LogLevel).

Категория журнала

При создании объекта ILogger указывается категория. Эта категория входит в состав каждого сообщения журнала, создаваемого этим экземпляром ILogger. Строка категории является необязательной, однако по соглашению следует использовать имя класса. Например, категория может называться "Example.DefaultService", если служба в приложении определяется как следующий объект:

namespace Example
{
    public class DefaultService : IService
    {
        private readonly ILogger<DefaultService> _logger;

        public DefaultService(ILogger<DefaultService> logger) =>
            _logger = logger;

        // ...
    }
}

Чтобы явно указать категорию, вызовите LoggerFactory.CreateLogger:

namespace Example
{
    public class DefaultService : IService
    {
        private readonly ILogger _logger;

        public DefaultService(ILoggerFactory loggerFactory) =>
            _logger = loggerFactory.CreateLogger("CustomCategory");

        // ...
    }
}

Вызов CreateLogger с фиксированным именем может быть полезным при использовании в нескольких классах или типах, чтобы события можно было упорядочить по категориям.

Использование ILogger<T> эквивалентно вызову CreateLogger с полным именем типа T.

Уровень ведения журнала

В следующей таблице перечислены значения LogLevel, используемый для удобства метод расширения Log{LogLevel}, а также приводятся сведения о предполагаемом применении:

LogLevel Значение Метод Описание
Трассировка 0 LogTrace Содержит наиболее подробные сообщения. Эти сообщения могут содержать конфиденциальные данные приложения. Эти сообщения по умолчанию отключены, и их никогда не следует включать в рабочей среде.
Отладка 1 LogDebug Используется для отладки и разработки. В рабочей среде следует использовать с осторожностью из-за большого объема.
Информация 2 LogInformation Отслеживание общего потока работы приложения. Может использоваться в долгосрочных целях.
Предупреждение 3 LogWarning Для нестандартных или непредвиденных событий. Обычно содержит ошибки или условия, которые не приводят к сбою приложения.
Ошибка 4 LogError Для ошибок и исключений, которые не могут быть обработаны. Эти сообщения указывают на сбой текущих операции или запроса, а не на ошибку уровня приложения.
Критическая 5 LogCritical Для сбоев, которые требуют немедленного внимания. Примеры: потеря данных, нехватка места на диске.
None 6 Указывает, что сообщения не должны записываться.

В приведенной выше таблице значения LogLevel приведены в порядке от самого низкого к самому высокому уровню серьезности.

Первый параметр метода Log, LogLevel, указывает на степень серьезности журнала. Вместо вызова Log(LogLevel, ...) большинство разработчиков вызывают методы расширения Log{LogLevel}. Методы расширения Log{LogLevel}вызывают метод Log и задают значение LogLevel. Например, следующие два вызова ведения журнала функционально эквивалентны и позволяют получить одинаковые журналы:

public void LogDetails()
{
    var logMessage = "Details for log.";

    _logger.Log(LogLevel.Information, AppLogEvents.Details, logMessage);
    _logger.LogInformation(AppLogEvents.Details, logMessage);
}

AppLogEvents.Details содержит идентификатор события и неявным образом представляется постоянным значением Int32. AppLogEvents обозначает класс, который предоставляет разные именованные константы для идентификаторов и отображается в разделе Идентификатор события журнала.

Следующий код создает журналы Informationи Warning:

public async Task<T> GetAsync<T>(string id)
{
    _logger.LogInformation(AppLogEvents.Read, "Reading value for {Id}", id);

    var result = await _repository.GetAsync(id);
    if (result is null)
    {
        _logger.LogWarning(AppLogEvents.ReadNotFound, "GetAsync({Id}) not found", id);
    }

    return result;
}

В коде выше первый параметр, AppLogEvents.Read, — это Log{LogLevel}идентификатор события журнала. Второй параметр — это шаблон сообщения с заполнителями для значений аргументов, предоставляемых оставшимися параметрами метода. Параметры метода рассматриваются более подробно в разделе, посвященном шаблону сообщений далее в этой статье.

Настройте подходящий уровень ведения журнала и вызовите правильные методы Log{LogLevel}, чтобы управлять объемом данных журнала, записываемых на определенный носитель. Пример:

  • В рабочей среде:
    • При ведении журнала на уровнях Trace или Debug создается большой объем подробных сообщений журнала. Чтобы контролировать затраты и не превысить лимиты объема хранилища данных, записывайте сообщения на уровнях Trace и Debug в хранилище данных с низкими затратами и большим объемом. Рассмотрите возможность ограничения уровней Trace и Debug конкретными категориями.
    • При ведении журналов на уровнях с Warning по Critical создается немного сообщений.
      • При этом стоимость и ограничения хранения, как правило, не важны.
      • Меньший объем журналов позволяет выбирать среди большего количества вариантов хранения данных.
  • В среде разработки:
    • Задайте значение Warning.
    • Добавляйте сообщения уровней Trace или Debug при устранении неполадок. Чтобы ограничить объем выходных данных, задавайте уровни Trace или Debug только для исследуемых категорий.

Приведенный ниже код JSON задает уровень Logging:Console:LogLevel:Microsoft:Information:

{
    "Logging": {
        "LogLevel": {
            "Microsoft": "Warning"
        },
        "Console": {
            "LogLevel": {
                "Microsoft": "Information"
            }
        }
    }
}

Идентификатор события журнала

В каждом журнале может быть задан идентификатор событияEventId, представляющий собой структуру с доступными только для чтения свойствами Id (идентификатор) и Name (имя, необязательно). В этом примере исходного кода для определения идентификаторов событий используется класс AppLogEvents.

using Microsoft.Extensions.Logging;

internal static class AppLogEvents
{
    internal EventId Create = new(1000, "Created");
    internal EventId Read = new(1001, "Read");
    internal EventId Update = new(1002, "Updated");
    internal EventId Delete = new(1003, "Deleted");

    // These are also valid EventId instances, as there's
    // an implicit conversion from int to an EventId
    internal const int Details = 3000;
    internal const int Error = 3001;

    internal EventId ReadNotFound = 4000;
    internal EventId UpdateNotFound = 4001;

    // ...
}

Совет

Дополнительные сведения о преобразовании объекта int в оператор EventId.Implicit(Int32 в EventId).EventId

Идентификатор события связывает набор событий. Например, все журналы, связанные с чтением значений из репозитория, могут иметь идентификатор 1001.

Поставщик ведения журналов может записывать идентификатор события в поле идентификатора, в сообщении журнала, или вообще не сохранять его. Поставщик Debug не отображает идентификаторы событий. Поставщик Console отображает идентификаторы событий в квадратных скобках после категории:

info: Example.DefaultService.GetAsync[1001]
      Reading value for a1b2c3
warn: Example.DefaultService.GetAsync[4000]
      GetAsync(a1b2c3) not found

Некоторые поставщики ведения журнала хранят идентификатор события в поле, что позволяет выполнять фильтрацию по идентификатору.

Шаблон сообщения журнала

Каждый API ведения журнала использует шаблон сообщения. Шаблон сообщения может содержать заполнители, для которых предоставляются аргументы. Используйте для заполнителей имена, а не числа. Параметры, используемые для предоставления значений, определяются порядком заполнителей, а не их именами. В приведенном ниже коде имена параметров идут не по порядку в шаблоне сообщения:

string p1 = "param1";
string p2 = "param2";
_logger.LogInformation("Parameter values: {p2}, {p1}", p1, p2);

Приведенный выше код создает сообщение журнала со значениями параметров в определенном порядке:

Parameter values: param1, param2

Примечание

Учитывайте при использовании нескольких заполнителей в одном шаблоне сообщения, так как они основаны на порядковых номерах. Имена не используются для выравнивания аргументов с заполнителями.

Такой подход позволяет поставщикам ведения журнала реализовывать семантическое или структурированное ведение журналов. Сами аргументы передаются в систему ведения журналов, а не только в отформатированный шаблон сообщения. Это позволяет поставщикам ведения журнала хранить значения параметров как поля. Давайте рассмотрим следующий метод средства ведения журнала:

_logger.LogInformation("Getting item {Id} at {RunTime}", id, DateTime.Now);

Например, при ведении журнала в хранилище таблиц Azure:

  • каждая сущность таблицы Azure может иметь свойства ID и RunTime;
  • использование таблиц со свойствами позволяет упростить выполнение запросов к данным журнала. Например, с помощью запроса можно находить все журналы в пределах определенного диапазона RunTime, не анализируя время ожидания текстового сообщения.

Форматирование шаблона сообщения журнала

Шаблоны сообщений журнала поддерживают форматирование заполнителей. Шаблоны могут указывать любой допустимый формат для заданного аргумента типа. Например, рассмотрим следующий Information шаблон сообщения средства ведения журнала:

_logger.LogInformation("Logged on {PlaceHolderName:MMMM dd, yyyy}", DateTimeOffset.UtcNow);
// Logged on January 06, 2022

В предыдущем примере экземпляр — это тип, DateTimeOffset соответствующий PlaceHolderName шаблону сообщения средства ведения журнала. Это имя может быть любым, так как значения основаны на порядковом номере. Формат MMMM dd, yyyy допустим для DateTimeOffset типа.

Дополнительные сведения о DateTime форматировании и DateTimeOffset форматировании см. в строках настраиваемого формата даты и времени.

Примеры форматирования шаблона сообщения журнала

Шаблоны сообщений журнала разрешают форматирование заполнителей. В следующих примерах показано, как отформатировать шаблон сообщения с помощью синтаксиса {} заполнителя. Кроме того, показан пример экранирования синтаксиса {} заполнителя со своими выходными данными. Наконец, интерполяция строк с заполнителями шаблонов также показана:

logger.LogInformation("Number: {Number}", 1);               // Number: 1
logger.LogInformation("{{Number}}: {Number}", 3);           // {Number}: 3
logger.LogInformation($"{{{{Number}}}}: {{Number}}", 5);    // {Number}: 5

Совет

При ведении журнала всегда следует использовать форматирование шаблона сообщения журнала. Следует избегать интерполяции строк, так как это может привести к проблемам с производительностью.

Запись исключений в журнал

Методы средства ведения журнала имеют перегрузки, которые принимают параметр исключения:

public void Test(string id)
{
    try
    {
        if (id == "none")
        {
            throw new Exception("Default Id detected.");
        }
    }
    catch (Exception ex)
    {
        _logger.LogWarning(
            AppLogEvents.Error, ex,
            "Failed to process iteration: {Id}", id);
    }
}

Принципы записи исключений в журнал зависят от конкретного поставщика.

Уровень ведения журнала по умолчанию

Если не задан уровень ведения журнала по умолчанию, то по умолчанию используется уровень Information.

Давайте рассмотрим следующее приложение службы рабочей роли:

  • Создано на основе шаблонов рабочей роли .NET.
  • файлы appsettings.json и appsettings.Development.json были удалены или переименованы.

В рамках приведенной выше конфигурации при переходе на страницу сведений о конфиденциальности или домашнюю страницу создается множество сообщений с уровнем Trace, Debug и Information, в имени категории которых используется Microsoft.

В следующем коде задается уровень ведения журнала по умолчанию в том случае, если этот уровень не определен в конфигурации:

class Program
{
    static Task Main(string[] args) =>
        CreateHostBuilder(args).Build().RunAsync();

    static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureLogging(logging => logging.SetMinimumLevel(LogLevel.Warning));
}

Функция фильтрации

Функция фильтрации вызывается для всех поставщиков и категорий, которым в конфигурации и (или) коде не назначены правила:

await Host.CreateDefaultBuilder(args)
    .ConfigureLogging(logging =>
        logging.AddFilter((provider, category, logLevel) =>
        {
            return provider.Contains("ConsoleLoggerProvider")
                && (category.Contains("Example") || category.Contains("Microsoft"))
                && logLevel >= LogLevel.Information;
        }))
    .Build()
    .RunAsync();

Приведенный выше код отображает журналы консоли, если категория содержит Example или Microsoft и задан уровень ведения журнала Information или выше.

Области журналов

Область может группировать набор логических операций. Эту возможность можно использовать для присоединения одних и тех же данных к каждому журналу, созданному как часть набора. Например, каждый журнал, созданный в ходе обработки транзакции, может включать идентификатор транзакции.

Область:

  • имеет тип IDisposable, который возвращается методом BeginScope;
  • действует вплоть до удаления.

Области поддерживаются следующими поставщиками:

Используйте область, заключив вызовы средства ведения журналов в блок using:

public async Task<T> GetAsync<T>(string id)
{
    T result;

    using (_logger.BeginScope("using block message"))
    {
        _logger.LogInformation(
            AppLogEvents.Read, "Reading value for {Id}", id);

        var result = await _repository.GetAsync(id);
        if (result is null)
        {
            _logger.LogWarning(
                AppLogEvents.ReadNotFound, "GetAsync({Id}) not found", id);
        }
    }

    return result;
}

Следующий код JSON предоставляет области для поставщика Console:

{
    "Logging": {
        "Debug": {
            "LogLevel": {
                "Default": "Information"
            }
        },
        "Console": {
            "IncludeScopes": true,
            "LogLevel": {
                "Microsoft": "Warning",
                "Default": "Information"
            }
        },
        "LogLevel": {
            "Default": "Debug"
        }
    }
}

Следующий код предоставляет области для поставщика Console:

await Host.CreateDefaultBuilder(args)
    .ConfigureLogging((_, logging) =>
        logging.ClearProviders()
            .AddConsole(options => options.IncludeScopes = true))
    .Build()
    .RunAsync();

Консольные приложения без размещения

Код ведения журнала для приложений без универсального узла отличается тем, как добавляются поставщики и создаются средства ведения журнала. В консольном приложении, не использующем узел, вызовите метод расширения Add{provider name} поставщика при создании LoggerFactory:

using var loggerFactory = LoggerFactory.Create(builder =>
{
    builder
        .AddFilter("Microsoft", LogLevel.Warning)
        .AddFilter("System", LogLevel.Warning)
        .AddFilter("LoggingConsoleApp.Program", LogLevel.Debug)
        .AddConsole();
});

ILogger logger = loggerFactory.CreateLogger<Program>();
logger.LogInformation("Example log message");

Объект loggerFactory используется для создания экземпляра ILogger.

Создание журналов в классе Main

Следующий код создает журналы в Main, получая экземпляр ILogger путем внедрения зависимостей после создания узла:

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

IHost host = Host.CreateDefaultBuilder(args).Build();

var logger = host.Services.GetRequiredService<ILogger<Program>>();
logger.LogInformation("Host created.");

await host.RunAsync();

Приведенный выше код основан на двух пакетах NuGet:

Его файл проекта будет выглядеть примерно так:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1" />
    <PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
  </ItemGroup>

</Project>

Асинхронные методы ведения журналов не выполняются

Скорость ведения журналов не должна влиять на производительность выполнения асинхронного кода. Если хранилище данных, предназначенное для регистрации сообщений журнала, работает медленно, сначала записывайте эти сообщения в быстродействующее хранилище, а затем перемещайте их в медленное хранилище. Например, если вы записываете журналы в SQL Server, вам не нужно делать это непосредственно в методе Log, так как методы Log являются синхронными. Вместо этого синхронно добавьте сообщения журнала в очередь в памяти, и фоновый рабочий поток извлечет сообщения из очереди для выполнения асинхронных операций передачи данных в SQL Server.

Изменение уровней ведения журнала в работающем приложении

API ведения журнала не включает сценарий для изменения уровней журнала во время работы приложения. Однако некоторые поставщики конфигурации могут перезагружать конфигурацию, что немедленно влияет на конфигурацию ведения журнала. Например, поставщик конфигурации файлов по умолчанию перезагружает конфигурацию ведения журнала. Если конфигурация изменяется в коде во время выполнения приложения, приложение может вызвать IConfigurationRoot.Reload, чтобы обновить конфигурацию ведения журнала приложения.

Пакеты NuGet

Интерфейсы ILogger<TCategoryName> и ILoggerFactory, а также их реализации включены в пакет SDK для .NET. Кроме того, они доступны в следующих пакетах NuGet:

Применение правил фильтрации журналов в коде

Для настройки правил фильтрации журналов рекомендуется использовать конфигурацию.

В следующем примере показано, как зарегистрировать в коде правила фильтрации:

await Host.CreateDefaultBuilder(args)
    .ConfigureLogging(logging =>
        logging.AddFilter("System", LogLevel.Debug)
            .AddFilter<DebugLoggerProvider>("Microsoft", LogLevel.Information)
            .AddFilter<ConsoleLoggerProvider>("Microsoft", LogLevel.Trace))
    .Build()
    .RunAsync();

logging.AddFilter("System", LogLevel.Debug) задает категорию System и уровень ведения журнала Debug. Поскольку конкретный поставщик не задан, фильтр применяется ко всем поставщикам.

AddFilter<DebugLoggerProvider>("Microsoft", LogLevel.Information) задает:

  • поставщик ведения журнала Debug;
  • уровень ведения журнала Information и выше;
  • все категории, начинающиеся с "Microsoft".

См. также раздел