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

Авторы: Кирк Ларкин (Kirk Larkin), Юрген Гутч (Juergen Gutsch) и Рик Андерсн (Rick Anderson)

В этой статье описывается ведение журнала в .NET, которое применяется к приложениям ASP.NET Core. Подробные сведения о ведении журналов в .NET см. в разделе Ведение журнала в .NET. Дополнительные сведения о ведении журналов в приложениях Blazor см. в статье Ведение журналов в ASP.NET Core Blazor.

Поставщики ведения журнала

Поставщики ведения журнала обеспечивают хранение журналов, за исключением поставщика Console, который служит для их отображения. Например, поставщик Azure Application Insights хранит журналы в Azure Application Insights. Вы можете включить несколько поставщиков.

Шаблоны по умолчанию для веб-приложений ASP.NET Core:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

В предыдущем коде показан файл Program.cs, созданный с использованием шаблонов веб-приложений ASP.NET Core. В следующих разделах приводятся примеры, которые построены на основе шаблонов веб-приложений ASP.NET Core и используют универсальный узел.

Следующий код переопределяет набор по умолчанию поставщиков ведения журнала, добавленных WebApplication.CreateBuilder:

var builder = WebApplication.CreateBuilder(args);
builder.Logging.ClearProviders();
builder.Logging.AddConsole();

builder.Services.AddRazorPages();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

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

var builder = WebApplication.CreateBuilder();
builder.Host.ConfigureLogging(logging =>
{
    logging.ClearProviders();
    logging.AddConsole();
});

Сведения о других поставщиках см. в следующих статьях:

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

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

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

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

    public AboutModel(ILogger<AboutModel> logger)
    {
        _logger = logger;
    }

    public void OnGet()
    {
        _logger.LogInformation("About page visited at {DT}", 
            DateTime.UtcNow.ToLongTimeString());
    }
}

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

Дополнительные сведения о Blazor см. в статье Ведение журналов в ASP.NET Core Blazor.

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

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

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

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

  • Указаны категории "Default" и "Microsoft.AspNetCore".
  • Категория "Microsoft.AspNetCore" применяется ко всем категориям, начинающимся с "Microsoft.AspNetCore". Например, этот параметр применяется к категории "Microsoft.AspNetCore.Routing.EndpointMiddleware".
  • Категория "Microsoft.AspNetCore" задает ведение журналов на уровне Warning и более высоком.
  • Поскольку конкретный поставщик журналов не указан, 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": { // All providers, LogLevel applies to all the enabled providers.
      "Default": "Error", // Default logging, Error and higher.
      "Microsoft": "Warning" // All Microsoft* categories, Warning and higher.
    },
    "Debug": { // Debug provider.
      "LogLevel": {
        "Default": "Information", // Overrides preceding LogLevel:Default setting.
        "Microsoft.Hosting": "Trace" // Debug:Microsoft.Hosting category.
      }
    },
    "EventSource": { // EventSource provider
      "LogLevel": {
        "Default": "Warning" // All categories of EventSource provider.
      }
    }
  }
}

Параметры переопределения Logging.{PROVIDER NAME}.LogLevel в Logging.LogLevel, где заполнитель {PROVIDER NAME} является именем поставщика. В приведенном выше коде 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": { // No provider, LogLevel applies to all the enabled providers.
      "Default": "Error",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Warning"
    },
    "Debug": { // Debug provider.
      "LogLevel": {
        "Default": "Information" // Overrides preceding LogLevel:Default setting.
      }
    },
    "Console": {
      "IncludeScopes": true,
      "LogLevel": {
        "Microsoft.AspNetCore.Mvc.Razor.Internal": "Warning",
        "Microsoft.AspNetCore.Mvc.Razor.Razor": "Debug",
        "Microsoft.AspNetCore.Mvc.Razor": "Error",
        "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.{PROVIDER NAME}.LogLevel в Logging.LogLevel, где заполнитель {PROVIDER NAME} является именем поставщика. Например, уровень в Debug.LogLevel.Default переопределяет уровень в LogLevel.Default.
  • Каждый поставщик по умолчанию использует псевдоним. Каждый поставщик определяет псевдоним, используемый в конфигурации вместо полного имени типа. Ниже приведены псевдонимы встроенных поставщиков:
    • Console
    • Debug
    • EventSource
    • EventLog
    • AzureAppServicesFile
    • AzureAppServicesBlob
    • ApplicationInsights

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

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

Разделитель : не работает с иерархическими ключами переменных среды на всех платформах. __ (двойной символ подчеркивания):

  • Поддерживается всеми платформами. Например, разделитель : не поддерживается Bash, а __ — поддерживается.
  • Автоматически заменяется на :

Приведенные ниже команды:

  • присваивают ключу среды Logging:LogLevel:Microsoft значение Information в Windows;
  • проверяют параметры при использовании приложения, созданного на основе шаблонов веб-приложений ASP.NET Core. Команда dotnet run должна выполняться в каталоге проекта после использования set.
set Logging__LogLevel__Microsoft=Information
dotnet run

Приведенный выше параметр среды:

  • задается только в процессах, запускаемых из командного окна, в котором он был установлен;
  • не будет считываться браузерами, запущенными в Visual Studio.

Приведенная ниже команда Setx также задает ключ среды и значение в Windows. В отличие от set, параметры setx сохраняются. Параметр /M задает переменную в системной среде. Если параметр /M не используется, задается переменная среды пользователя.

setx Logging__LogLevel__Microsoft Information /M

Рассмотрим следующий файл appsettings.json :

"Logging": {
  "Console": {
    "LogLevel": {
      "Microsoft.Hosting.Lifetime": "Trace"
    }
  }
}

Следующая команда задает предыдущую конфигурацию в среде:

setx Logging__Console__LogLevel__Microsoft.Hosting.Lifetime Trace /M

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

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

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

Дополнительные сведения о настройке значений конфигурации ASP.NET Core с помощью переменных среды см. в статье Переменные среды. Дополнительные сведения об использовании других источников конфигурации, включая командную строку, Azure Key Vault, службу конфигурации приложений Azure, различные форматы файлов и другие, см. в статье Конфигурация в ASP.NET Core.

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

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

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

  • Выберите все правила, которые соответствуют поставщику или его псевдониму. Если ничего не найдено, выберите все правила с пустым поставщиком.
  • В результатах предыдущего шага выберите правила с самым длинным соответствующим префиксом категории. Если ничего не найдено, выберите все правила, которые не указывают категорию.
  • Если выбрано несколько правил, примите последнее.
  • Если правила не выбраны, используйте MinimumLevel.

Запись в журнал выходных данных dotnet run и Visual Studio

Журналы, созданные с помощью установленных по умолчанию поставщиков ведения журнала, отображаются:

  • В Visual Studio
    • в окне выходных данных отладки при отладке;
    • в окне веб-сервера ASP.NET Core.
  • В окне консоли при запуске приложения с помощью команды dotnet run.

Журналы, которые начинаются с категорий Microsoft, входят в код платформы ASP.NET Core. В ASP.NET Core и коде приложения используются один и тот же API ведения журнала и одни и те же поставщики.

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

При создании объекта ILogger указывается категория. Эта категория входит в состав каждого сообщения журнала, создаваемого этим экземпляром ILogger. Строка категории является необязательной, однако по соглашению следует использовать имя класса. Например, в контроллере может использоваться имя "TodoApi.Controllers.TodoController". Веб-приложения ASP.NET Core используют ILogger<T> для автоматического получения экземпляра ILogger, который использует полное имя типа T в качестве категории:

public class PrivacyModel : PageModel
{
    private readonly ILogger<PrivacyModel> _logger;

    public PrivacyModel(ILogger<PrivacyModel> logger)
    {
        _logger = logger;
    }

    public void OnGet()
    {
        _logger.LogInformation("GET Pages.PrivacyModel called.");
    }
}

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

public class ContactModel : PageModel
{
    private readonly ILogger _logger;

    public ContactModel(ILoggerFactory logger)
    {
        _logger = logger.CreateLogger("MyCategory");
    }

    public void OnGet()
    {
        _logger.LogInformation("GET Pages.ContactModel called.");
    }

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

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

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

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

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

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

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

[HttpGet]
public IActionResult Test1(int id)
{
    var routeInfo = ControllerContext.ToCtxString(id);

    _logger.Log(LogLevel.Information, MyLogEvents.TestItem, routeInfo);
    _logger.LogInformation(MyLogEvents.TestItem, routeInfo);

    return ControllerContext.MyDisplayRouteInfo();
}

MyLogEvents.TestItem — это идентификатор события. MyLogEvents является частью примера приложения и отображается в разделе Идентификатор события журнала.

MyDisplayRouteInfo и ToCtxString предоставляются пакетом NuGet Rick.Docs.Samples.RouteInfo. Эти методы отображают Controller информацию о маршруте Razor Page.

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

[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
    _logger.LogInformation(MyLogEvents.GetItem, "Getting item {Id}", id);

    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        _logger.LogWarning(MyLogEvents.GetItemNotFound, "Get({Id}) NOT FOUND", id);
        return NotFound();
    }

    return ItemToDTO(todoItem);
}

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

С помощью вызова соответствующего метода Log{LOG LEVEL} можно управлять объемом выходных данных, записываемых на определенный носитель. Пример:

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

ASP.NET Core создает журналы для событий платформы. В качестве примера рассмотрим выходные данные журнала для:

  • приложения страниц Razor, созданного на основе шаблонов ASP.NET Core;
  • Уровень ведения журналов равен Logging:Console:LogLevel:Microsoft:Information.
  • Переход на страницу Privacy:
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
      Request starting HTTP/2 GET https://localhost:5001/Privacy
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
      Executing endpoint '/Privacy'
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[3]
      Route matched with {page = "/Privacy"}. Executing page /Privacy
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[101]
      Executing handler method DefaultRP.Pages.PrivacyModel.OnGet - ModelState is Valid
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[102]
      Executed handler method OnGet, returned result .
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[103]
      Executing an implicit handler method - ModelState is Valid
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[104]
      Executed an implicit handler method, returned result Microsoft.AspNetCore.Mvc.RazorPages.PageResult.
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[4]
      Executed page /Privacy in 74.5188ms
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
      Executed endpoint '/Privacy'
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
      Request finished in 149.3023ms 200 text/html; charset=utf-8

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

{
  "Logging": {      // Default, all providers.
    "LogLevel": {
      "Microsoft": "Warning"
    },
    "Console": { // Console provider.
      "LogLevel": {
        "Microsoft": "Information"
      }
    }
  }
}

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

Каждый журнал может указывать идентификатор события. В этом примере приложения используется класс MyLogEvents для определения идентификаторов событий:

public class MyLogEvents
{
    public const int GenerateItems = 1000;
    public const int ListItems     = 1001;
    public const int GetItem       = 1002;
    public const int InsertItem    = 1003;
    public const int UpdateItem    = 1004;
    public const int DeleteItem    = 1005;

    public const int TestItem      = 3000;

    public const int GetItemNotFound    = 4000;
    public const int UpdateItemNotFound = 4001;
}
[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
    _logger.LogInformation(MyLogEvents.GetItem, "Getting item {Id}", id);

    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        _logger.LogWarning(MyLogEvents.GetItemNotFound, "Get({Id}) NOT FOUND", id);
        return NotFound();
    }

    return ItemToDTO(todoItem);
}

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

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

info: TodoApi.Controllers.TodoItemsController[1002]
      Getting item 1
warn: TodoApi.Controllers.TodoItemsController[4000]
      Get(1) NOT FOUND

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

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

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

[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
    _logger.LogInformation(MyLogEvents.GetItem, "Getting item {Id}", id);

    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        _logger.LogWarning(MyLogEvents.GetItemNotFound, "Get({Id}) NOT FOUND", id);
        return NotFound();
    }

    return ItemToDTO(todoItem);
}

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

string apples = 1;
string pears = 2;
string bananas = 3;

_logger.LogInformation("Parameters: {pears}, {bananas}, {apples}", apples, pears, bananas);

Однако параметры присваиваются заполнителям в порядке: apples, pears, bananas. Сообщение журнала отражает порядок параметров:

Parameters: 1, 2, 3

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

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

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

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

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

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

[HttpGet("{id}")]
public IActionResult TestExp(int id)
{
    var routeInfo = ControllerContext.ToCtxString(id);
    _logger.LogInformation(MyLogEvents.TestItem, routeInfo);

    try
    {
        if (id == 3)
        {
            throw new Exception("Test exception");
        }
    }
    catch (Exception ex)
    {
        _logger.LogWarning(MyLogEvents.GetItemNotFound, ex, "TestExp({Id})", id);
        return NotFound();
    }

    return ControllerContext.MyDisplayRouteInfo();
}

MyDisplayRouteInfo и ToCtxString предоставляются пакетом NuGet Rick.Docs.Samples.RouteInfo. Эти методы отображают Controller информацию о маршруте Razor Page.

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

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

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

Рассмотрим в качестве примера следующее веб-приложение:

  • приложение создано на основе шаблонов веб-приложений ASP.NET;
  • appsettings.json и appsettings.Development.json удалены или переименованы.

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

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

var builder = WebApplication.CreateBuilder();
builder.Logging.SetMinimumLevel(LogLevel.Warning);

Как правило, уровни ведения журнала следует задавать не в коде, а в конфигурации.

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

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

var builder = WebApplication.CreateBuilder();
builder.Logging.AddFilter((provider, category, logLevel) =>
{
    if (provider.Contains("ConsoleLoggerProvider")
        && category.Contains("Controller")
        && logLevel >= LogLevel.Information)
    {
        return true;
    }
    else if (provider.Contains("ConsoleLoggerProvider")
        && category.Contains("Microsoft")
        && logLevel >= LogLevel.Information)
    {
        return true;
    }
    else
    {
        return false;
    }
});

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

Как правило, уровни ведения журнала следует задавать не в коде, а в конфигурации.

Категории ASP.NET Core и EF Core

В следующей таблице приведены некоторые категории, используемые ASP.NET Core и Entity Framework Core с заметками о журналах:

Категория Примечания
Microsoft.AspNetCore Общая диагностика ASP.NET Core.
Microsoft.AspNetCore.DataProtection Распознанные, найденные и использованные ключи.
Microsoft.AspNetCore.HostFiltering Разрешенные узлы.
Microsoft.AspNetCore.Hosting Время начала и длительность выполнения HTTP-запросов. Определение загруженных начальных сборок размещения.
Microsoft.AspNetCore.Mvc Диагностика MVC и Razor. Привязка моделей, выполнение фильтра, компиляция представлений, выбор действия.
Microsoft.AspNetCore.Routing Перенаправление соответствующих сведений.
Microsoft.AspNetCore.Server Запуск, остановка и сохранение ответов. Сведения о сертификате HTTPS.
Microsoft.AspNetCore.StaticFiles Обработанные файлы.
Microsoft.EntityFrameworkCore Общая диагностика Entity Framework Core. Действия и конфигурация базы данных, обнаружение изменений, переносы.

Чтобы просмотреть в окне консоли другие категории, выполните следующее присвоение appsettings.Development.json:

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

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

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

Область:

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

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

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

[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
    TodoItem todoItem;

    using (_logger.BeginScope("using block message"))
    {
        _logger.LogInformation(MyLogEvents.GetItem, "Getting item {Id}", id);

        todoItem = await _context.TodoItems.FindAsync(id);

        if (todoItem == null)
        {
            _logger.LogWarning(MyLogEvents.GetItemNotFound, 
                "Get({Id}) NOT FOUND", id);
            return NotFound();
        }
    }

    return ItemToDTO(todoItem);
}

Встроенные поставщики ведения журналов

ASP.NET Core включает в состав общей платформы следующие поставщики ведения журналов:

Следующие поставщики ведения журналов поставляются корпорацией Майкрософт, но не в составе общей платформы. Их необходимо устанавливать в виде дополнительных пакетов NuGet.

ASP.NET Core не содержит поставщика ведения журналов для записи журналов в файлы. Чтобы записать журналы в файлы из приложения ASP.NET Core, рассмотрите возможность использования стороннего поставщика ведения журналов.

Сведения о stdout и ведении журналов отладки с помощью модуля ASP.NET Core см. в статье Устранение неполадок ASP.NET Core в Службе приложений Azure и IIS и Модуль ASP.NET Core (ANCM) для IIS.

Консоль

Поставщик Console выводит выходные данные в консоль. Дополнительные сведения о просмотре журналов Console в среде разработки см. в статье Запись в журнал выходных данных dotnet run и Visual Studio.

Отладка

Поставщик Debug записывает выходные данные журнала с помощью класса System.Diagnostics.Debug. При вызове методов System.Diagnostics.Debug.WriteLine выполняется запись в поставщик Debug.

В Linux расположение журнала поставщика Debug зависит от дистрибутива и может быть одним из следующих:

  • /var/log/message
  • /var/log/syslog

Источник события

Поставщик EventSource выполняет запись в кроссплатформенный источник событий с именем Microsoft-Extensions-Logging. В Windows поставщик использует ETW.

Средства трассировки dotnet

Средство dotnet-trace — это универсальное кроссплатформенное средство командной строки, которое выполняет сбор трассировок .NET Core для запущенного процесса. Средство собирает данные поставщика Microsoft.Extensions.Logging.EventSource с помощью LoggingEventSource.

Инструкции по установке см. в разделе dotnet-trace.

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

  1. Запустите приложение с помощью команды dotnet run.

  2. Определите идентификатор процесса (PID) приложения .NET Core:

    dotnet trace ps
    

    Найдите идентификатор процесса, имя которого совпадает с именем сборки приложения.

  3. Выполните команду dotnet trace.

    Общий синтаксис команды:

    dotnet trace collect -p {PID} 
        --providers Microsoft-Extensions-Logging:{Keyword}:{Provider Level}
            :FilterSpecs=\"
                {Logger Category 1}:{Category Level 1};
                {Logger Category 2}:{Category Level 2};
                ...
                {Logger Category N}:{Category Level N}\"
    

    При использовании командной оболочки PowerShell заключите значение --providers в одинарные кавычки ('):

    dotnet trace collect -p {PID} 
        --providers 'Microsoft-Extensions-Logging:{Keyword}:{Provider Level}
            :FilterSpecs=\"
                {Logger Category 1}:{Category Level 1};
                {Logger Category 2}:{Category Level 2};
                ...
                {Logger Category N}:{Category Level N}\"'
    

    На платформах, отличных от Windows, добавьте параметр -f speedscope, чтобы изменить формат выходного файла трассировки на speedscope.

    В следующей таблице определяется ключевое слово:

    Ключевое слово Описание
    1 Занесите в журнал метасобытия о LoggingEventSource. Не заносит в журнал события из ILogger.
    2 Включает событие Message при вызове ILogger.Log(). Предоставляет сведения в исходном виде (без форматирования).
    4 Включает событие FormatMessage при вызове ILogger.Log(). Предоставляет сведения в виде отформатированной строки.
    8 Включает событие MessageJson при вызове ILogger.Log(). Предоставляет представление аргументов в формате JSON.

    В следующей таблице перечислены уровни поставщика:

    Уровень поставщика Описание
    0 LogAlways
    1 Critical
    2 Error
    3 Warning
    4 Informational
    5 Verbose

    Анализ для уровня категории может быть строкой или числом:

    Значение с именем категории Числовое значение
    Trace 0
    Debug 1
    Information 2
    Warning 3
    Error 4
    Critical 5

    Уровень поставщика и уровень категории:

    • В обратном порядке.
    • Не все строковые константы не идентичны.

    Если значение FilterSpecs не указано, то реализация EventSourceLogger пытается преобразовать уровень поставщика в уровень категории и применяет его ко всем категориям.

    Уровень поставщика Уровень категории
    Verbose(5) Debug(1)
    Informational(4) Information(2)
    Warning(3) Warning(3)
    Error(2) Error(4)
    Critical(1) Critical(5)

    Если указаны FilterSpecs, любая категория, включенная в список, использует уровень, закодированный в этой категории, а все остальные категории отфильтровываются.

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

    • Приложение работает и вызывает logger.LogDebug("12345").
    • Идентификатор процесса (PID) был задан через set PID=12345, где 12345 — фактический идентификатор процесса.

    Рассмотрим следующую команду:

    dotnet trace collect -p %PID% --providers Microsoft-Extensions-Logging:4:5
    

    Предыдущая команда:

    • Фиксирует сообщения отладки.
    • Не применяет FilterSpecs.
    • Указывает уровень 5, который сопоставляет категорию отладки (Debug).

    Рассмотрим следующую команду:

    dotnet trace collect -p %PID%  --providers Microsoft-Extensions-Logging:4:5:\"FilterSpecs=*:5\"
    

    Предыдущая команда:

    • Не фиксирует сообщения отладки, так как уровень категории 5 — Critical.
    • Предоставляет FilterSpecs.

    Следующая команда фиксирует сообщения отладке, так как уровень категории 1 указывает Debug.

    dotnet trace collect -p %PID%  --providers Microsoft-Extensions-Logging:4:5:\"FilterSpecs=*:1\"
    

    Следующая команда фиксирует сообщения отладке, так как категория указывает Debug.

    dotnet trace collect -p %PID%  --providers Microsoft-Extensions-Logging:4:5:\"FilterSpecs=*:Debug\"
    

    Записи FilterSpecs для {Logger Category} и {Category Level} представляют дополнительные условия фильтрации журналов. Разделяйте записи FilterSpecs символом точки с запятой ;.

    Пример с использованием командной оболочки Windows:

    dotnet trace collect -p %PID% --providers Microsoft-Extensions-Logging:4:2:FilterSpecs=\"Microsoft.AspNetCore.Hosting*:4\"
    

    Предыдущая команда активирует:

    • Средство ведения журнала источника событий для создания форматированных строк (4) для ошибок (2).
    • Ведение журнала Microsoft.AspNetCore.Hosting на уровне ведения журнала Informational (4).
  4. Остановите средства трассировки dotnet, нажав клавишу ENTER или CTRL+C.

    Трассировка сохраняется с именем trace.nettrace в папке, в которой выполняется команда dotnet trace.

  5. Откройте трассировку с помощью Perfview. Откройте файл trace.nettrace и изучите события трассировки.

Если приложение не создает узел с WebApplication.CreateBuilder, добавьте Поставщика источника событий в конфигурацию ведения журнала приложения.

Дополнительные сведения см. в разделе:

Perfview

Для сбора и просмотра данных журналов рекомендуется использовать программу PerfView. Существуют и другие средства для просмотра журналов трассировки событий Windows, но PerfView обеспечивает максимальное удобство работы с событиями трассировки событий Windows, создаваемыми ASP.NET Core.

Чтобы настроить PerfView для сбора событий, регистрируемых этим поставщиком, добавьте строку *Microsoft-Extensions-Logging в список Дополнительные поставщики. Не пропустите символ * в начале строки.

Windows EventLog

Поставщик EventLog отправляет выходные данные журнала в журнал событий Windows. В отличие от других поставщиков, поставщик EventLogне наследует параметры по умолчанию, не относящиеся к поставщику. Если параметры журнала EventLog не указаны, то принимается значение по умолчанию LogLevel.Warning.

Чтобы регистрировать события с уровнем ниже LogLevel.Warning, следует явно задать уровень ведения журнала. В следующем примере для журнала событий по умолчанию задается уровень LogLevel.Information:

"Logging": {
  "EventLog": {
    "LogLevel": {
      "Default": "Information"
    }
  }
}

Перегрузки AddEventLog позволяют передавать EventLogSettings. Если null или не указан, используются следующие параметры по умолчанию:

  • LogName. "Application"
  • SourceName: ".NET Runtime"
  • MachineName. Используется имя локального компьютера.

Следующий код изменяет SourceName со значения по умолчанию ".NET Runtime" на MyLogs:


var builder = WebApplication.CreateBuilder();
builder.Logging.AddEventLog(eventLogSettings =>
{
    eventLogSettings.SourceName = "MyLogs";
});

Служба приложений Azure

Пакет поставщика Microsoft.Extensions.Logging.AzureAppServices записывает журналы в текстовые файлы в файловой системе приложения службы приложений Azure и в хранилище больших двоичных объектов в учетной записи хранения Azure.

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

Для настройки параметров поставщика используйте AzureFileLoggerOptions и AzureBlobLoggerOptions, как показано в следующем примере:

using Microsoft.Extensions.Logging.AzureAppServices;

var builder = WebApplication.CreateBuilder();
builder.Logging.AddAzureWebAppDiagnostics();
builder.Services.Configure<AzureFileLoggerOptions>(options =>
{
    options.FileName = "azure-diagnostics-";
    options.FileSizeLimit = 50 * 1024;
    options.RetainedFileCountLimit = 5;
});
builder.Services.Configure<AzureBlobLoggerOptions>(options =>
{
    options.BlobName = "log.txt";
});

При развертывании в службе приложений Azure ваше приложение использует параметры в разделе Журналы службы приложений на странице Служба приложений на портале Azure. При обновлении следующих параметров изменения вступают в силу немедленно без перезапуска или повторного развертывания приложения:

  • Ведение журнала приложения (файловая система) ;
  • Ведение журнала приложения (BLOB-объект) .

По умолчанию файлы журнала находятся в папке D:\\home\\LogFiles\\Application. Имя файла по умолчанию — diagnostics-yyyymmdd.txt. Максимальный размер файла по умолчанию составляет 10 МБ, а максимальное количество сохраняемых по умолчанию файлов равно 2. Имя большого двоичного объекта по умолчанию — {app-name}{timestamp}/yyyy/mm/dd/hh/{guid}-applicationLog.txt.

Этот поставщик работает только при выполнении проекта в среде Azure.

Потоковая передача журналов Azure

Потоковая передача журналов Azure позволяет просматривать активность журнала в реальном времени из следующих источников:

  • сервер приложений;
  • веб-сервер;
  • трассировка неудачно завершенных запросов.

Настройка потоковой передачи журналов Azure

  • Со страницы портала приложения перейдите на страницу Журналы службы приложений.
  • Включите параметр Ведение журнала приложения (файловая система) .
  • Выберите уровень ведения журнала. Этот параметр применяется только к потоковой передаче журналов Azure.

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

Azure Application Insights

Пакет поставщика Microsoft.Extensions.Logging.ApplicationInsights записывает журналы в Azure Application Insights. Служба Application Insights отслеживает веб-приложения и предоставляет средства для создания запросов и анализа данных телеметрии. Используя этого поставщика, вы сможете выполнять запросы к журналам и их анализ с помощью средств Application Insights.

Поставщик ведения журнала включается как зависимость Microsoft.ApplicationInsights.AspNetCore. Этот пакет предоставляет всю доступную телеметрию для ASP.NET Core. Если вы используете этот пакет, пакет поставщика устанавливать не нужно.

Пакет Microsoft.ApplicationInsights.Web предназначен для ASP.NET 4. x, но не ASP.NET Core.

Дополнительные сведения см. в следующих ресурсах:

Сторонние поставщики ведения журналов

Некоторые сторонние платформы ведения журналов, которые работают с ASP.NET Core:

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

Использование сторонней платформы аналогично использованию одного из встроенных поставщиков:

  1. Добавьте пакет NuGet в проект.
  2. Вызовите метод расширения ILoggerFactory, предоставляемый платформой ведения журналов.

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

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

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

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

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

ILogger и ILoggerFactory

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

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

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

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

using Microsoft.Extensions.Logging.Console;
using Microsoft.Extensions.Logging.Debug;

var builder = WebApplication.CreateBuilder();
builder.Logging.AddFilter("System", LogLevel.Debug);
builder.Logging.AddFilter<DebugLoggerProvider>("Microsoft", LogLevel.Information);
builder.Logging.AddFilter<ConsoleLoggerProvider>("Microsoft", LogLevel.Trace);

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

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

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

Автоматически вести журнал в области с помощью SpanId, TraceId, ParentId, Baggage и Tags.

Библиотеки ведения журналов неявно создают объект области с SpanId, TraceId, ParentId,Baggage и Tags. Это поведение настраивается с помощью ActivityTrackingOptions.

  var loggerFactory = LoggerFactory.Create(logging =>
  {
      logging.Configure(options =>
      {
          options.ActivityTrackingOptions = ActivityTrackingOptions.SpanId
                                              | ActivityTrackingOptions.TraceId
                                              | ActivityTrackingOptions.ParentId
                                              | ActivityTrackingOptions.Baggage
                                              | ActivityTrackingOptions.Tags;
      }).AddSimpleConsole(options =>
      {
          options.IncludeScopes = true;
      });
  });

Если задан заголовок HTTP-запроса traceparent, ParentId области журнала отображает parent-id W3C от входящего заголовка traceparent, а SpanId в области журнала — обновленное значение parent-id для следующего исходящего шага/диапазона. Дополнительные сведения см. в статье Изменение поля traceparent.

Создание пользовательского средства ведения журнала

Сведения о создании пользовательского средства ведения журнала см. в статье Реализация пользовательского поставщика ведения журнала в .NET.

Дополнительные ресурсы

Авторы: Кирк Ларкин (Kirk Larkin), Юрген Гутч (Juergen Gutsch) и Рик Андерсн (Rick Anderson)

В этой статье описывается ведение журнала в .NET, которое применяется к приложениям ASP.NET Core. Подробные сведения о ведении журналов в .NET см. в разделе Ведение журнала в .NET. Дополнительные сведения о ведении журналов в приложениях Blazor см. в статье Ведение журналов в ASP.NET Core Blazor.

Просмотреть или скачать пример кода (описание скачивания).

Поставщики ведения журнала

Поставщики ведения журнала обеспечивают хранение журналов, за исключением поставщика Console, который служит для их отображения. Например, поставщик Azure Application Insights хранит журналы в Azure Application Insights. Вы можете включить несколько поставщиков.

Шаблоны по умолчанию для веб-приложений ASP.NET Core:

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

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

Чтобы переопределить заданный по умолчанию набор поставщиков ведения журнала, добавленных с помощью Host.CreateDefaultBuilder, вызовите метод ClearProviders и добавьте необходимые поставщики. Например, приведенный ниже код

  • вызывает метод ClearProviders для удаления всех экземпляров ILoggerProvider из построителя;
  • добавляет поставщик ведения журнала Console.
public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureLogging(logging =>
        {
            logging.ClearProviders();
            logging.AddConsole();
        })
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        });

Сведения о других поставщиках см. в следующих статьях:

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

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

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

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

    public AboutModel(ILogger<AboutModel> logger)
    {
        _logger = logger;
    }
    public string Message { get; set; }

    public void OnGet()
    {
        Message = $"About page visited at {DateTime.UtcNow.ToLongTimeString()}";
        _logger.LogInformation(Message);
    }
}

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

Дополнительные сведения о Blazor см. в статье Ведение журналов в ASP.NET Core Blazor.

В разделах, посвященных созданию журналов в классах Main и Startup, описывается создание журналов в Main и Startup.

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

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

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

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

  • Указаны категории "Default", "Microsoft"и "Microsoft.Hosting.Lifetime".
  • Категория "Microsoft" применяется ко всем категориям, начинающимся с "Microsoft". Например, этот параметр применяется к категории "Microsoft.AspNetCore.Routing.EndpointMiddleware".
  • Категория "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": { // All providers, LogLevel applies to all the enabled providers.
      "Default": "Error", // Default logging, Error and higher.
      "Microsoft": "Warning" // All Microsoft* categories, Warning and higher.
    },
    "Debug": { // Debug provider.
      "LogLevel": {
        "Default": "Information", // Overrides preceding LogLevel:Default setting.
        "Microsoft.Hosting": "Trace" // Debug:Microsoft.Hosting category.
      }
    },
    "EventSource": { // EventSource provider
      "LogLevel": {
        "Default": "Warning" // All categories of EventSource provider.
      }
    }
  }
}

Параметры в 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": { // No provider, LogLevel applies to all the enabled providers.
      "Default": "Error",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Warning"
    },
    "Debug": { // Debug provider.
      "LogLevel": {
        "Default": "Information" // Overrides preceding LogLevel:Default setting.
      }
    },
    "Console": {
      "IncludeScopes": true,
      "LogLevel": {
        "Microsoft.AspNetCore.Mvc.Razor.Internal": "Warning",
        "Microsoft.AspNetCore.Mvc.Razor.Razor": "Debug",
        "Microsoft.AspNetCore.Mvc.Razor": "Error",
        "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

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

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

Разделитель : не работает с иерархическими ключами переменных среды на всех платформах. __ (двойной символ подчеркивания):

  • Поддерживается всеми платформами. Например, разделитель : не поддерживается Bash, а __ — поддерживается.
  • Автоматически заменяется на :

Приведенные ниже команды:

  • присваивают ключу среды Logging:LogLevel:Microsoft значение Information в Windows;
  • проверяют параметры при использовании приложения, созданного на основе шаблонов веб-приложений ASP.NET Core. Команда dotnet run должна выполняться в каталоге проекта после использования set.
set Logging__LogLevel__Microsoft=Information
dotnet run

Приведенный выше параметр среды:

  • задается только в процессах, запускаемых из командного окна, в котором он был установлен;
  • не будет считываться браузерами, запущенными в Visual Studio.

Приведенная ниже команда Setx также задает ключ среды и значение в Windows. В отличие от set, параметры setx сохраняются. Параметр /M задает переменную в системной среде. Если параметр /M не используется, задается переменная среды пользователя.

setx Logging__LogLevel__Microsoft Information /M

Рассмотрим следующий файл appsettings.json :

"Logging": {
    "Console": {
      "LogLevel": {
        "Microsoft.Hosting.Lifetime": "Trace"
      }
    }
}

Следующая команда задает предыдущую конфигурацию в среде:

setx Logging__Console__LogLevel__Microsoft.Hosting.Lifetime Trace /M

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

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

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

Дополнительные сведения о настройке значений конфигурации ASP.NET Core с помощью переменных среды см. в статье Переменные среды. Дополнительные сведения об использовании других источников конфигурации, включая командную строку, Azure Key Vault, службу конфигурации приложений Azure, различные форматы файлов и другие, см. в статье Конфигурация в ASP.NET Core.

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

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

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

  • Выберите все правила, которые соответствуют поставщику или его псевдониму. Если ничего не найдено, выберите все правила с пустым поставщиком.
  • В результатах предыдущего шага выберите правила с самым длинным соответствующим префиксом категории. Если ничего не найдено, выберите все правила, которые не указывают категорию.
  • Если выбрано несколько правил, примите последнее.
  • Если правила не выбраны, используйте MinimumLevel.

Запись в журнал выходных данных dotnet run и Visual Studio

Журналы, созданные с помощью установленных по умолчанию поставщиков ведения журнала, отображаются:

  • В Visual Studio
    • в окне выходных данных отладки при отладке;
    • в окне веб-сервера ASP.NET Core.
  • В окне консоли при запуске приложения с помощью команды dotnet run.

Журналы, которые начинаются с категорий Microsoft, входят в код платформы ASP.NET Core. В ASP.NET Core и коде приложения используются один и тот же API ведения журнала и одни и те же поставщики.

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

При создании объекта ILogger указывается категория. Эта категория входит в состав каждого сообщения журнала, создаваемого этим экземпляром ILogger. Строка категории является необязательной, однако по соглашению следует использовать имя класса. Например, в контроллере может использоваться имя "TodoApi.Controllers.TodoController". Веб-приложения ASP.NET Core используют ILogger<T> для автоматического получения экземпляра ILogger, который использует полное имя типа T в качестве категории:

public class PrivacyModel : PageModel
{
    private readonly ILogger<PrivacyModel> _logger;

    public PrivacyModel(ILogger<PrivacyModel> logger)
    {
        _logger = logger;
    }

    public void OnGet()
    {
        _logger.LogInformation("GET Pages.PrivacyModel called.");
    }
}

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

public class ContactModel : PageModel
{
    private readonly ILogger _logger;

    public ContactModel(ILoggerFactory logger)
    {
        _logger = logger.CreateLogger("MyCategory");
    }

    public void OnGet()
    {
        _logger.LogInformation("GET Pages.ContactModel called.");
    }

Вызов 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. Например, следующие два вызова ведения журнала функционально эквивалентны и позволяют получить одинаковые журналы:

[HttpGet]
public IActionResult Test1(int id)
{
    var routeInfo = ControllerContext.ToCtxString(id);

    _logger.Log(LogLevel.Information, MyLogEvents.TestItem, routeInfo);
    _logger.LogInformation(MyLogEvents.TestItem, routeInfo);

    return ControllerContext.MyDisplayRouteInfo();
}

MyLogEvents.TestItem — это идентификатор события. MyLogEvents является частью примера приложения и отображается в разделе Идентификатор события журнала.

MyDisplayRouteInfo и ToCtxString предоставляются пакетом NuGet Rick.Docs.Samples.RouteInfo. Эти методы отображают Controller информацию о маршруте Razor Page.

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

[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
    _logger.LogInformation(MyLogEvents.GetItem, "Getting item {Id}", id);

    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        _logger.LogWarning(MyLogEvents.GetItemNotFound, "Get({Id}) NOT FOUND", id);
        return NotFound();
    }

    return ItemToDTO(todoItem);
}

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

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

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

ASP.NET Core создает журналы для событий платформы. В качестве примера рассмотрим выходные данные журнала для:

  • приложения страниц Razor, созданного на основе шаблонов ASP.NET Core;
  • уровня ведения журналов Logging:Console:LogLevel:Microsoft:Information;
  • Переход на страницу Privacy:
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
      Request starting HTTP/2 GET https://localhost:5001/Privacy
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
      Executing endpoint '/Privacy'
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[3]
      Route matched with {page = "/Privacy"}. Executing page /Privacy
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[101]
      Executing handler method DefaultRP.Pages.PrivacyModel.OnGet - ModelState is Valid
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[102]
      Executed handler method OnGet, returned result .
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[103]
      Executing an implicit handler method - ModelState is Valid
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[104]
      Executed an implicit handler method, returned result Microsoft.AspNetCore.Mvc.RazorPages.PageResult.
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[4]
      Executed page /Privacy in 74.5188ms
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
      Executed endpoint '/Privacy'
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
      Request finished in 149.3023ms 200 text/html; charset=utf-8

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

{
  "Logging": {      // Default, all providers.
    "LogLevel": {
      "Microsoft": "Warning"
    },
    "Console": { // Console provider.
      "LogLevel": {
        "Microsoft": "Information"
      }
    }
  }
}

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

Каждый журнал может указывать идентификатор события. В этом примере приложения используется класс MyLogEvents для определения идентификаторов событий:

public class MyLogEvents
{
    public const int GenerateItems = 1000;
    public const int ListItems     = 1001;
    public const int GetItem       = 1002;
    public const int InsertItem    = 1003;
    public const int UpdateItem    = 1004;
    public const int DeleteItem    = 1005;

    public const int TestItem      = 3000;

    public const int GetItemNotFound    = 4000;
    public const int UpdateItemNotFound = 4001;
}
[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
    _logger.LogInformation(MyLogEvents.GetItem, "Getting item {Id}", id);

    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        _logger.LogWarning(MyLogEvents.GetItemNotFound, "Get({Id}) NOT FOUND", id);
        return NotFound();
    }

    return ItemToDTO(todoItem);
}

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

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

info: TodoApi.Controllers.TodoItemsController[1002]
      Getting item 1
warn: TodoApi.Controllers.TodoItemsController[4000]
      Get(1) NOT FOUND

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

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

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

[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
    _logger.LogInformation(MyLogEvents.GetItem, "Getting item {Id}", id);

    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        _logger.LogWarning(MyLogEvents.GetItemNotFound, "Get({Id}) NOT FOUND", id);
        return NotFound();
    }

    return ItemToDTO(todoItem);
}

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

string apples = 1;
string pears = 2;
string bananas = 3;

_logger.LogInformation("Parameters: {pears}, {bananas}, {apples}", apples, pears, bananas);

Однако параметры присваиваются заполнителям в порядке: apples, pears, bananas. Сообщение журнала отражает порядок параметров:

Parameters: 1, 2, 3

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

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

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

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

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

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

[HttpGet("{id}")]
public IActionResult TestExp(int id)
{
    var routeInfo = ControllerContext.ToCtxString(id);
    _logger.LogInformation(MyLogEvents.TestItem, routeInfo);

    try
    {
        if (id == 3)
        {
            throw new Exception("Test exception");
        }
    }
    catch (Exception ex)
    {
        _logger.LogWarning(MyLogEvents.GetItemNotFound, ex, "TestExp({Id})", id);
        return NotFound();
    }

    return ControllerContext.MyDisplayRouteInfo();
}

MyDisplayRouteInfo и ToCtxString предоставляются пакетом NuGet Rick.Docs.Samples.RouteInfo. Эти методы отображают Controller информацию о маршруте Razor Page.

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

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

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

Рассмотрим в качестве примера следующее веб-приложение:

  • приложение создано на основе шаблонов веб-приложений ASP.NET;
  • appsettings.json и appsettings.Development.json удалены или переименованы.

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

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

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureLogging(logging => logging.SetMinimumLevel(LogLevel.Warning))
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

Как правило, уровни ведения журнала следует задавать не в коде, а в конфигурации.

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

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

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureLogging(logging =>
            {
                logging.AddFilter((provider, category, logLevel) =>
                {
                    if (provider.Contains("ConsoleLoggerProvider")
                        && category.Contains("Controller")
                        && logLevel >= LogLevel.Information)
                    {
                        return true;
                    }
                    else if (provider.Contains("ConsoleLoggerProvider")
                        && category.Contains("Microsoft")
                        && logLevel >= LogLevel.Information)
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                });
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

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

Как правило, уровни ведения журнала следует задавать не в коде, а в конфигурации.

Категории ASP.NET Core и EF Core

В следующей таблице приведены некоторые категории, используемые ASP.NET Core и Entity Framework Core с заметками о журналах:

Категория Примечания
Microsoft.AspNetCore Общая диагностика ASP.NET Core.
Microsoft.AspNetCore.DataProtection Распознанные, найденные и использованные ключи.
Microsoft.AspNetCore.HostFiltering Разрешенные узлы.
Microsoft.AspNetCore.Hosting Время начала и длительность выполнения HTTP-запросов. Определение загруженных начальных сборок размещения.
Microsoft.AspNetCore.Mvc Диагностика MVC и Razor. Привязка моделей, выполнение фильтра, компиляция представлений, выбор действия.
Microsoft.AspNetCore.Routing Перенаправление соответствующих сведений.
Microsoft.AspNetCore.Server Запуск, остановка и сохранение ответов. Сведения о сертификате HTTPS.
Microsoft.AspNetCore.StaticFiles Обработанные файлы.
Microsoft.EntityFrameworkCore Общая диагностика Entity Framework Core. Действия и конфигурация базы данных, обнаружение изменений, переносы.

Чтобы просмотреть в окне консоли другие категории, выполните следующее присвоение appsettings.Development.json:

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

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

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

Область:

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

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

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

[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
    TodoItem todoItem;

    using (_logger.BeginScope("using block message"))
    {
        _logger.LogInformation(MyLogEvents.GetItem, "Getting item {Id}", id);

        todoItem = await _context.TodoItems.FindAsync(id);

        if (todoItem == null)
        {
            _logger.LogWarning(MyLogEvents.GetItemNotFound, 
                "Get({Id}) NOT FOUND", id);
            return NotFound();
        }
    }

    return ItemToDTO(todoItem);
}

Встроенные поставщики ведения журналов

ASP.NET Core включает в состав общей платформы следующие поставщики ведения журналов:

Следующие поставщики ведения журналов поставляются корпорацией Майкрософт, но не в составе общей платформы. Их необходимо устанавливать в виде дополнительных пакетов NuGet.

ASP.NET Core не содержит поставщика ведения журналов для записи журналов в файлы. Чтобы записать журналы в файлы из приложения ASP.NET Core, рассмотрите возможность использования стороннего поставщика ведения журналов.

Сведения о stdout и ведении журналов отладки с помощью модуля ASP.NET Core см. в статье Устранение неполадок ASP.NET Core в Службе приложений Azure и IIS и Модуль ASP.NET Core (ANCM) для IIS.

Консоль

Поставщик Console выводит выходные данные в консоль. Дополнительные сведения о просмотре журналов Console в среде разработки см. в статье Запись в журнал выходных данных dotnet run и Visual Studio.

Отладка

Поставщик Debug записывает выходные данные журнала с помощью класса System.Diagnostics.Debug. При вызове методов System.Diagnostics.Debug.WriteLine выполняется запись в поставщик Debug.

В Linux расположение журнала поставщика Debug зависит от дистрибутива и может быть одним из следующих:

  • /var/log/message
  • /var/log/syslog

Источник события

Поставщик EventSource выполняет запись в кроссплатформенный источник событий с именем Microsoft-Extensions-Logging. В Windows поставщик использует ETW.

Средства трассировки dotnet

Средство dotnet-trace — это универсальное кроссплатформенное средство командной строки, которое выполняет сбор трассировок .NET Core для запущенного процесса. Средство собирает данные поставщика Microsoft.Extensions.Logging.EventSource с помощью LoggingEventSource.

Инструкции по установке см. в статье dotnet-trace.

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

  1. Запустите приложение с помощью команды dotnet run.

  2. Определите идентификатор процесса (PID) приложения .NET Core:

    dotnet trace ps
    

    Найдите идентификатор процесса, имя которого совпадает с именем сборки приложения.

  3. Выполните команду dotnet trace.

    Общий синтаксис команды:

    dotnet trace collect -p {PID} 
        --providers Microsoft-Extensions-Logging:{Keyword}:{Provider Level}
            :FilterSpecs=\"
                {Logger Category 1}:{Category Level 1};
                {Logger Category 2}:{Category Level 2};
                ...
                {Logger Category N}:{Category Level N}\"
    

    При использовании командной оболочки PowerShell заключите значение --providers в одинарные кавычки ('):

    dotnet trace collect -p {PID} 
        --providers 'Microsoft-Extensions-Logging:{Keyword}:{Provider Level}
            :FilterSpecs=\"
                {Logger Category 1}:{Category Level 1};
                {Logger Category 2}:{Category Level 2};
                ...
                {Logger Category N}:{Category Level N}\"'
    

    На платформах, отличных от Windows, добавьте параметр -f speedscope, чтобы изменить формат выходного файла трассировки на speedscope.

    В следующей таблице определяется ключевое слово:

    Ключевое слово Описание
    1 Занесите в журнал метасобытия о LoggingEventSource. Не заносит в журнал события из ILogger.
    2 Включает событие Message при вызове ILogger.Log(). Предоставляет сведения в исходном виде (без форматирования).
    4 Включает событие FormatMessage при вызове ILogger.Log(). Предоставляет сведения в виде отформатированной строки.
    8 Включает событие MessageJson при вызове ILogger.Log(). Предоставляет представление аргументов в формате JSON.

    В следующей таблице перечислены уровни поставщика:

    Уровень поставщика Описание
    0 LogAlways
    1 Critical
    2 Error
    3 Warning
    4 Informational
    5 Verbose

    Анализ для уровня категории может быть строкой или числом:

    Значение с именем категории Числовое значение
    Trace 0
    Debug 1
    Information 2
    Warning 3
    Error 4
    Critical 5

    Уровень поставщика и уровень категории:

    • В обратном порядке.
    • Не все строковые константы не идентичны.

    Если значение FilterSpecs не указано, то реализация EventSourceLogger пытается преобразовать уровень поставщика в уровень категории и применяет его ко всем категориям.

    Уровень поставщика Уровень категории
    Verbose(5) Debug(1)
    Informational(4) Information(2)
    Warning(3) Warning(3)
    Error(2) Error(4)
    Critical(1) Critical(5)

    Если указаны FilterSpecs, любая категория, включенная в список, использует уровень, закодированный в этой категории, а все остальные категории отфильтровываются.

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

    • Приложение работает и вызывает logger.LogDebug("12345").
    • Идентификатор процесса (PID) был задан через set PID=12345, где 12345 — фактический идентификатор процесса.

    Рассмотрим следующую команду:

    dotnet trace collect -p %PID% --providers Microsoft-Extensions-Logging:4:5
    

    Предыдущая команда:

    • Фиксирует сообщения отладки.
    • Не применяет FilterSpecs.
    • Указывает уровень 5, который сопоставляет категорию отладки (Debug).

    Рассмотрим следующую команду:

    dotnet trace collect -p %PID%  --providers Microsoft-Extensions-Logging:4:5:\"FilterSpecs=*:5\"
    

    Предыдущая команда:

    • Не фиксирует сообщения отладки, так как уровень категории 5 — Critical.
    • Предоставляет FilterSpecs.

    Следующая команда фиксирует сообщения отладке, так как уровень категории 1 указывает Debug.

    dotnet trace collect -p %PID%  --providers Microsoft-Extensions-Logging:4:5:\"FilterSpecs=*:1\"
    

    Следующая команда фиксирует сообщения отладке, так как категория указывает Debug.

    dotnet trace collect -p %PID%  --providers Microsoft-Extensions-Logging:4:5:\"FilterSpecs=*:Debug\"
    

    Записи FilterSpecs для {Logger Category} и {Category Level} представляют дополнительные условия фильтрации журналов. Разделяйте записи FilterSpecs символом точки с запятой ;.

    Пример с использованием командной оболочки Windows:

    dotnet trace collect -p %PID% --providers Microsoft-Extensions-Logging:4:2:FilterSpecs=\"Microsoft.AspNetCore.Hosting*:4\"
    

    Предыдущая команда активирует:

    • Средство ведения журнала источника событий для создания форматированных строк (4) для ошибок (2).
    • Ведение журнала Microsoft.AspNetCore.Hosting на уровне ведения журнала Informational (4).
  4. Остановите средства трассировки dotnet, нажав клавишу ENTER или CTRL+C.

    Трассировка сохраняется с именем trace.nettrace в папке, в которой выполняется команда dotnet trace.

  5. Откройте трассировку с помощью Perfview. Откройте файл trace.nettrace и изучите события трассировки.

Если приложение не создает узел с CreateDefaultBuilder, добавьте Поставщика источника событий в конфигурацию ведения журнала приложения.

Дополнительные сведения можно найти в разделе

Perfview

Для сбора и просмотра данных журналов рекомендуется использовать программу PerfView. Существуют и другие средства для просмотра журналов трассировки событий Windows, но PerfView обеспечивает максимальное удобство работы с событиями трассировки событий Windows, создаваемыми ASP.NET Core.

Чтобы настроить PerfView для сбора событий, регистрируемых этим поставщиком, добавьте строку *Microsoft-Extensions-Logging в список Дополнительные поставщики. Не пропустите символ * в начале строки.

Windows EventLog

Поставщик EventLog отправляет выходные данные журнала в журнал событий Windows. В отличие от других поставщиков, поставщик EventLogне наследует параметры по умолчанию, не относящиеся к поставщику. Если параметры журнала EventLog не указаны, по умолчанию используется уровень LogLevel.Warning.

Чтобы регистрировать события с уровнем ниже LogLevel.Warning, следует явно задать уровень ведения журнала. В следующем примере для журнала событий по умолчанию задается уровень LogLevel.Information:

"Logging": {
  "EventLog": {
    "LogLevel": {
      "Default": "Information"
    }
  }
}

Перегрузки AddEventLog позволяют передавать EventLogSettings. Если null или не указан, используются следующие параметры по умолчанию:

  • LogName. "Application"
  • SourceName: ".NET Runtime"
  • MachineName. Используется имя локального компьютера.

Следующий код изменяет SourceName со значения по умолчанию ".NET Runtime" на MyLogs:

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureLogging(logging =>
            {
                logging.AddEventLog(eventLogSettings =>
                {
                    eventLogSettings.SourceName = "MyLogs"; 
                });
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

Служба приложений Azure

Пакет поставщика Microsoft.Extensions.Logging.AzureAppServices записывает журналы в текстовые файлы в файловой системе приложения службы приложений Azure и в хранилище больших двоичных объектов в учетной записи хранения Azure.

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

Для настройки параметров поставщика используйте AzureFileLoggerOptions и AzureBlobLoggerOptions, как показано в следующем примере:

public class Scopes
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureLogging(logging => logging.AddAzureWebAppDiagnostics())
                .ConfigureServices(serviceCollection => serviceCollection
                    .Configure<AzureFileLoggerOptions>(options =>
                    {
                        options.FileName = "azure-diagnostics-";
                        options.FileSizeLimit = 50 * 1024;
                        options.RetainedFileCountLimit = 5;
                    })
                    .Configure<AzureBlobLoggerOptions>(options =>
                    {
                        options.BlobName = "log.txt";
                    }))
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }
}

При развертывании в службе приложений Azure ваше приложение использует параметры в разделе Журналы службы приложений на странице Служба приложений на портале Azure. При обновлении следующих параметров изменения вступают в силу немедленно без перезапуска или повторного развертывания приложения:

  • Ведение журнала приложения (файловая система) ;
  • Ведение журнала приложения (BLOB-объект) .

По умолчанию файлы журнала находятся в папке D:\home\LogFiles\Application, а имя файла по умолчанию — diagnostics-yyyymmdd.txt. Максимальный размер файла по умолчанию составляет 10 МБ, а максимальное количество сохраняемых по умолчанию файлов равно 2. Имя BLOB-объекта по умолчанию — {имя_приложения}{метка_времени}/yyyy/mm/dd/hh/{guid}-applicationLog.txt.

Этот поставщик работает только при выполнении проекта в среде Azure.

Потоковая передача журналов Azure

Потоковая передача журналов Azure позволяет просматривать активность журнала в реальном времени из следующих источников:

  • сервер приложений;
  • веб-сервер;
  • трассировка неудачно завершенных запросов.

Настройка потоковой передачи журналов Azure

  • Со страницы портала приложения перейдите на страницу Журналы службы приложений.
  • Включите параметр Ведение журнала приложения (файловая система) .
  • Выберите уровень ведения журнала. Этот параметр применяется только к потоковой передаче журналов Azure.

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

Azure Application Insights

Пакет поставщика Microsoft.Extensions.Logging.ApplicationInsights записывает журналы в Azure Application Insights. Служба Application Insights отслеживает веб-приложения и предоставляет средства для создания запросов и анализа данных телеметрии. Используя этого поставщика, вы сможете выполнять запросы к журналам и их анализ с помощью средств Application Insights.

Поставщик ведения журнала включается как зависимость Microsoft.ApplicationInsights.AspNetCore. Этот пакет предоставляет всю доступную телеметрию для ASP.NET Core. Если вы используете этот пакет, пакет поставщика устанавливать не нужно.

Пакет Microsoft.ApplicationInsights.Web предназначен для ASP.NET 4.x, а не для ASP.NET Core.

Дополнительные сведения см. в следующих ресурсах:

Сторонние поставщики ведения журналов

Некоторые сторонние платформы ведения журналов, которые работают с ASP.NET Core:

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

Использование сторонней платформы аналогично использованию одного из встроенных поставщиков:

  1. Добавьте пакет NuGet в проект.
  2. Вызовите метод расширения ILoggerFactory, предоставляемый платформой ведения журналов.

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

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

Пример использования универсального узла в приложении, не являющемся веб-консолью, см. в файле Program.csпримера приложения "Фоновые задачи" (Фоновые задачи с размещенными службами в ASP.NET Core).

Код ведения журнала для приложений без универсального узла отличается тем, как добавляются поставщики и создаются средства ведения журнала.

Поставщики ведения журнала

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

class Program
{
    static void Main(string[] args)
    {
        using var loggerFactory = LoggerFactory.Create(builder =>
        {
            builder
                .AddFilter("Microsoft", LogLevel.Warning)
                .AddFilter("System", LogLevel.Warning)
                .AddFilter("LoggingConsoleApp.Program", LogLevel.Debug)
                .AddConsole()
                .AddEventLog();
        });
        ILogger logger = loggerFactory.CreateLogger<Program>();
        logger.LogInformation("Example log message");
    }
}

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

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

В приведенном ниже примере для создается средство ведения журнала с категорией LoggingConsoleApp.Program.

class Program
{
    static void Main(string[] args)
    {
        using var loggerFactory = LoggerFactory.Create(builder =>
        {
            builder
                .AddFilter("Microsoft", LogLevel.Warning)
                .AddFilter("System", LogLevel.Warning)
                .AddFilter("LoggingConsoleApp.Program", LogLevel.Debug)
                .AddConsole()
                .AddEventLog();
        });
        ILogger logger = loggerFactory.CreateLogger<Program>();
        logger.LogInformation("Example log message");
    }
}

В приведенном ниже примере средство ведения журнала используется для создания журналов с уровнем Information. Уровень ведения журналов определяет степень серьезности или важности записанного в журнал события.

class Program
{
    static void Main(string[] args)
    {
        using var loggerFactory = LoggerFactory.Create(builder =>
        {
            builder
                .AddFilter("Microsoft", LogLevel.Warning)
                .AddFilter("System", LogLevel.Warning)
                .AddFilter("LoggingConsoleApp.Program", LogLevel.Debug)
                .AddConsole()
                .AddEventLog();
        });
        ILogger logger = loggerFactory.CreateLogger<Program>();
        logger.LogInformation("Example log message");
    }
}

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

Ведение журнала во время создания узла

Ведение журнала во время создания узла не поддерживается напрямую. Однако можно использовать отдельное средство ведения журнала. В следующем примере для входа в CreateHostBuilder используется средство ведения журнала Serilog. AddSerilog использует статическую конфигурацию, указанную в Log.Logger.

using System;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args)
    {
        var builtConfig = new ConfigurationBuilder()
            .AddJsonFile("appsettings.json")
            .AddCommandLine(args)
            .Build();

        Log.Logger = new LoggerConfiguration()
            .WriteTo.Console()
            .WriteTo.File(builtConfig["Logging:FilePath"])
            .CreateLogger();

        try
        {
            return Host.CreateDefaultBuilder(args)
                .ConfigureServices((context, services) =>
                {
                    services.AddRazorPages();
                })
                .ConfigureAppConfiguration((hostingContext, config) =>
                {
                    config.AddConfiguration(builtConfig);
                })
                .ConfigureLogging(logging =>
                {   
                    logging.AddSerilog();
                })
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
        }
        catch (Exception ex)
        {
            Log.Fatal(ex, "Host builder error");

            throw;
        }
        finally
        {
            Log.CloseAndFlush();
        }
    }
}

Настройка службы, зависящей от ILogger

Внедрение средства ведения журнала в класс Startup посредством конструктора работает в более ранних версиях ASP.NET Core, так как для веб-узла создается отдельный контейнер внедрения зависимостей. Сведения о том, почему для универсального узла создается только один контейнер, см. в объявлении о критическом изменении.

Чтобы настроить службу, зависящую от ILogger<T>, используйте внедрение конструктора или предоставьте фабричный метод. Фабричный метод рекомендуется использовать, только если нет других вариантов. Например, рассмотрим службу, которой требуется экземпляр ILogger<T>, предоставляемый путем внедрения зависимостей:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    services.AddRazorPages();

    services.AddSingleton<IMyService>((container) =>
    {
        var logger = container.GetRequiredService<ILogger<MyService>>();
        return new MyService() { Logger = logger };
    });
}

Выделенный выше код — это функция Func<T,TResult>, которая выполняется, когда контейнеру внедрения зависимостей впервые требуется создать экземпляр MyService. Таким образом можно обращаться к любым зарегистрированным службам.

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

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

public static void Main(string[] args)
{
    var host = CreateHostBuilder(args).Build();

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

    host.Run();
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        });

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

Следующий код записывает журналы в Startup.Configure:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env,
                      ILogger<Startup> logger)
{
    if (env.IsDevelopment())
    {
        logger.LogInformation("In Development.");
        app.UseDeveloperExceptionPage();
    }
    else
    {
        logger.LogInformation("Not Development.");
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
        endpoints.MapRazorPages();
    });
}

Запись журналов до завершения настройки контейнера внедрения зависимостей в методе Startup.ConfigureServices не поддерживается:

  • Внедрение средства ведения журнала в конструктор Startup не поддерживается.
  • Внедрение средства ведения журнала в сигнатуру метода Startup.ConfigureServices не поддерживается.

Причина этого ограничения заключается в том, что ведение журнала зависит от внедрения зависимостей и от конфигурации, которая, в свою очередь, зависит от внедрения зависимостей. Контейнер внедрения зависимостей не настраивается, пока не завершится выполнение ConfigureServices.

Дополнительные сведения о настройке службы, которая зависит от ILogger<T>, а также о причинах, по которым внедрение конструктора для средства ведения журнала в Startup работало в более ранних версиях, см. в разделе Настройка службы, зависящей от ILogger

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

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

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

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

ILogger и ILoggerFactory

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

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

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

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

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureLogging(logging =>
               logging.AddFilter("System", LogLevel.Debug)
                  .AddFilter<DebugLoggerProvider>("Microsoft", LogLevel.Information)
                  .AddFilter<ConsoleLoggerProvider>("Microsoft", LogLevel.Trace))
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

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

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

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

Автоматическая регистрация области действия с SpanId, TraceId, and ParentId

Библиотеки ведения журналов неявно создают объект области с SpanId, TraceId и ParentId. Это поведение настраивается с помощью ActivityTrackingOptions.

  var loggerFactory = LoggerFactory.Create(logging =>
  {
      logging.Configure(options =>
      {
          options.ActivityTrackingOptions = ActivityTrackingOptions.SpanId
                                              | ActivityTrackingOptions.TraceId
                                              | ActivityTrackingOptions.ParentId;
      }).AddSimpleConsole(options =>
      {
          options.IncludeScopes = true;
      });
  });

Если задан заголовок HTTP-запроса traceparent, ParentId области журнала отображает parent-id W3C от входящего заголовка traceparent, а SpanId в области журнала — обновленное значение parent-id для следующего исходящего шага/диапазона. Дополнительные сведения см. в статье Изменение поля traceparent.

Создание пользовательского средства ведения журнала

Сведения о создании пользовательского средства ведения журнала см. в статье Реализация пользовательского поставщика ведения журнала в .NET.

Дополнительные ресурсы