Обучение
Модуль
Форматирование буквенно-цифровых данных для представления в C# - Training
Изучите основные методы в C# для форматирования буквенно-цифровых данных.
Этот браузер больше не поддерживается.
Выполните обновление до Microsoft Edge, чтобы воспользоваться новейшими функциями, обновлениями для системы безопасности и технической поддержкой.
.NET поддерживает высокую производительность, структурированное ведение журнала через ILogger API для мониторинга поведения приложений и диагностики проблем. Журналы можно записать в разные места назначения, настроив разных поставщиков ведения журнала. Основные поставщики ведения журналов являются встроенными и есть множество сторонних поставщиков, доступных также.
В первом примере показаны основные сведения, но он подходит только для тривиального консольного приложения. В этом примере консольного приложения используются следующие пакеты NuGet:
В следующем разделе вы узнаете, как улучшить код, учитывая масштаб, производительность, конфигурацию и типичные шаблоны программирования.
using Microsoft.Extensions.Logging;
using ILoggerFactory factory = LoggerFactory.Create(builder => builder.AddConsole());
ILogger logger = factory.CreateLogger("Program");
logger.LogInformation("Hello World! Logging is {Description}.", "fun");
Предшествующий пример:
ILoggerFactory
всю конфигурацию, которая определяет, куда отправляются сообщения журнала. В этом случае вы настроите поставщик ведения журнала консоли таким образом, чтобы сообщения журнала записылись в консоль.string
категория, связанная с каждым сообщениемILogger
, зарегистрированным объектом. Он используется для группирования сообщений журнала из одного класса (или категории) вместе при поиске или фильтрации журналов.Information
уровне. Уровень журнала указывает серьезность зарегистрированного события и используется для фильтрации менее важных сообщений журнала. Запись журнала также включает шаблон "Hello World! Logging is {Description}."
сообщения и пару Description = fun
"ключ-значение". Имя ключа (или заполнитель) происходит из слова внутри фигурных фигурных скобок в шаблоне, а значение исходит от оставшегося аргумента метода.Этот файл проекта для этого примера включает два пакета NuGet:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="9.0.0" />
</ItemGroup>
</Project>
Совет
Весь пример исходного кода для ведения журнала доступен для загрузки в Обозревателе примеров. Дополнительные сведения см. в разделе Обзор примеров кода: ведение журнала в .NET.
Существует несколько изменений, которые следует внести в предыдущий пример при входе в менее тривиальный сценарий:
Если приложение использует внедрение зависимостей (DI) или узел, например ASP. Затем webApplication или универсальный узел NET следует использовать ILoggerFactory
и ILogger
объекты из соответствующих контейнеров DI, а не создавать их напрямую. Дополнительные сведения см. в разделе "Интеграция с di и hosts".
Создание источника во время компиляции ведения журнала обычно является лучшей альтернативой ILogger
методам расширения, таким какLogInformation
. Создание источника ведения журнала обеспечивает более высокую производительность, более сильную типизацию и избегает распространения string
констант во всех методах. Компромисс заключается в том, что использование этого метода требует немного большего кода.
using Microsoft.Extensions.Logging;
internal partial class Program
{
static void Main(string[] args)
{
using ILoggerFactory factory = LoggerFactory.Create(builder => builder.AddConsole());
ILogger logger = factory.CreateLogger("Program");
LogStartupMessage(logger, "fun");
}
[LoggerMessage(Level = LogLevel.Information, Message = "Hello World! Logging is {Description}.")]
static partial void LogStartupMessage(ILogger logger, string description);
}
Type
чтобы сделать это именование простым.using Microsoft.Extensions.Logging;
internal class Program
{
static void Main(string[] args)
{
using ILoggerFactory factory = LoggerFactory.Create(builder => builder.AddConsole());
ILogger logger = factory.CreateLogger<Program>();
logger.LogInformation("Hello World! Logging is {Description}.", "fun");
}
}
using Microsoft.Extensions.Logging;
using OpenTelemetry.Logs;
using ILoggerFactory factory = LoggerFactory.Create(builder =>
{
builder.AddOpenTelemetry(logging =>
{
logging.AddOtlpExporter();
});
});
ILogger logger = factory.CreateLogger("Program");
logger.LogInformation("Hello World! Logging is {Description}.", "fun");
Если приложение использует внедрение зависимостей (DI) или узел, например ASP. Затем webApplication или универсальный узел NET следует использовать ILoggerFactory
и ILogger
объекты из контейнера DI, а не создавать их напрямую.
В этом примере получается объект ILogger в размещенном приложении с помощью ASP.NET минимальных API:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<ExampleHandler>();
var app = builder.Build();
var handler = app.Services.GetRequiredService<ExampleHandler>();
app.MapGet("/", handler.HandleRequest);
app.Run();
partial class ExampleHandler(ILogger<ExampleHandler> logger)
{
public string HandleRequest()
{
LogHandleRequest(logger);
return "Hello World";
}
[LoggerMessage(LogLevel.Information, "ExampleHandler.HandleRequest was called")]
public static partial void LogHandleRequest(ILogger logger);
}
Предшествующий пример:
ExampleHandler
и сопоставляет входящие веб-запросы для запуска ExampleHandler.HandleRequest
функции.ILogger<ExampleHandler>
. ILogger<TCategoryName> является производным от ILogger и указывает, какая категория ILogger
имеет объект. Контейнер DI находит правильную ILogger
категорию и предоставляет его в качестве аргумента конструктора. Если эта категория еще не ILogger
существует, контейнер DI автоматически создает его из ILoggerFactory
поставщика услуг.logger
полученный в конструкторе, использовался для ведения журнала в HandleRequest
функции.Построитель узлов инициализирует конфигурацию по умолчанию, а затем добавляет настроенный ILoggerFactory
объект в контейнер DI узла при создании узла. Перед сборкой узла можно настроить конфигурацию ведения журнала с помощью HostApplicationBuilder.LoggingWebApplicationBuilder.Loggingили аналогичных API на других узлах. Узлы также применяют конфигурацию ведения журнала из источников конфигурации по умолчанию в качестве appsettings.json и переменных среды. Дополнительные сведения см. в статье Конфигурация в .NET.
Этот пример расширяет предыдущий, чтобы настроить предоставленный ILoggerFactory
WebApplicationBuilder
. Он добавляет OpenTelemetry в качестве поставщика ведения журнала, передавающего журналы по протоколу OTLP (протокол OpenTelemetry):
var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddOpenTelemetry(logging => logging.AddOtlpExporter());
builder.Services.AddSingleton<ExampleHandler>();
var app = builder.Build();
Если вы используете контейнер DI без узла, используйте AddLogging для настройки и добавления ILoggerFactory
в контейнер.
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
// Add services to the container including logging
var services = new ServiceCollection();
services.AddLogging(builder => builder.AddConsole());
services.AddSingleton<ExampleService>();
IServiceProvider serviceProvider = services.BuildServiceProvider();
// Get the ExampleService object from the container
ExampleService service = serviceProvider.GetRequiredService<ExampleService>();
// Do some pretend work
service.DoSomeWork(10, 20);
class ExampleService(ILogger<ExampleService> logger)
{
public void DoSomeWork(int x, int y)
{
logger.LogInformation("DoSomeWork was called. x={X}, y={Y}", x, y);
}
}
Предшествующий пример:
ILoggerFactory
для записи в консольExampleService
в контейнерExampleService
контейнера DI, который также автоматически создал объект ILogger<ExampleService>
для использования в качестве аргумента конструктора.ExampleService.DoSomeWork
, который использовался ILogger<ExampleService>
для записи сообщения в консоль.Конфигурация ведения журнала устанавливается в коде или через внешние источники, такие как файлы конфигурации и переменные среды. Использование внешней конфигурации полезно, если это возможно, так как его можно изменить, не перестроив приложение. Однако некоторые задачи, такие как настройка поставщиков ведения журнала, можно настроить только из кода.
Для приложений, использующих узел, конфигурация ведения журнала обычно предоставляется разделом "Logging"
приложенийettings.{Environment}
.json файлов. Для приложений, которые не используют узел, внешние источники конфигурации настраиваются явно или настраиваются в коде.
Шаблоны рабочей службы .NET создают следующий файл appsettings.Development.json:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
В приведенном выше документе JSON:
"Default"
"Microsoft"
Указаны категории уровня журнала и "Microsoft.Hosting.Lifetime"
параметров уровня журнала."Default"
применяется ко всем категориям, которые не указаны в противном случае, эффективно делая все значения по умолчанию для всех категорий "Information"
. Это поведение можно переопределить, указав значение для категории."Microsoft"
применяется ко всем категориям, начинающимся с "Microsoft"
."Microsoft"
категорий на уровне Warning
журнала и выше."Microsoft.Hosting.Lifetime"
более конкретна, чем "Microsoft"
категория, поэтому "Microsoft.Hosting.Lifetime"
журналы категорий на уровне "Information"
журнала и выше.LogLevel
применяется ко всем включенным поставщикам, за исключением Windows EventLog.Свойство Logging
может иметь свойство LogLevel и свойства поставщика журналов. Свойство LogLevel
указывает минимальный уровень журнала для выбранных категорий. В приведенном выше коде JSON заданы уровни ведения журнала Information
и Warning
. LogLevel
определяет степень серьезности журнала и задается в диапазоне от 0 до 6:
Trace
= 0, Debug
= 1, Information
= 2, Warning
= 3, Error
= 4, Critical
= 5 и None
= 6.
Если задан LogLevel
, журналы будут вестись для сообщений с указанным и более высокими уровнями. В приведенном выше коде JSON задается ведение журналов для категории Default
для сообщений с уровнем Information
и более высоким. Например, в журнал записываются сообщения с уровнями Information
, Warning
, Error
и Critical
. Если LogLevel
не задан, по умолчанию устанавливается уровень ведения журналов Information
. Дополнительные сведения см. в статье Уровни ведения журналов.
Свойство поставщика может задавать свойство LogLevel
. Свойство LogLevel
поставщика определяет уровень ведения журналов для этого поставщика и переопределяет любые другие не относящиеся к поставщику параметры ведения журналов. Рассмотрите следующий файл appsettings.json:
{
"Logging": {
"LogLevel": {
"Default": "Error",
"Microsoft": "Warning"
},
"Debug": {
"LogLevel": {
"Default": "Information",
"Microsoft.Hosting": "Trace"
}
},
"EventSource": {
"LogLevel": {
"Default": "Warning"
}
}
}
}
Параметры в Logging.{ProviderName}.LogLevel
переопределяют параметры в Logging.LogLevel
. В приведенном выше коде JSON для поставщика Debug
задается уровень ведения журнала по умолчанию Information
:
Logging:Debug:LogLevel:Default:Information
Приведенный выше параметр задает уровень ведения журнала Information
для всех категорий Logging:Debug:
, за исключением Microsoft.Hosting
. Если задана конкретная категория, она переопределяет категорию по умолчанию. В приведенном выше коде JSON категории Logging:Debug:LogLevel
"Microsoft.Hosting"
и "Default"
переопределяют параметры в Logging:LogLevel
.
Минимальный уровень ведения журнала можно указать для:
Logging:EventSource:LogLevel:Default:Information
Logging:LogLevel:Microsoft:Warning
Logging:LogLevel:Default:Warning
Любые журналы с уровнем ниже минимального:
Чтобы отключить все журналы, укажите LogLevel.None. LogLevel.None
имеет значение 6, то есть выше LogLevel.Critical
(5).
Если поставщик поддерживает области журналов, IncludeScopes
определяет, включены ли они. Дополнительные сведения см. в статье Области журналов.
Следующий файл appsettings.json содержит параметры для всех встроенных поставщиков:
{
"Logging": {
"LogLevel": {
"Default": "Error",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Warning"
},
"Debug": {
"LogLevel": {
"Default": "Information"
}
},
"Console": {
"IncludeScopes": true,
"LogLevel": {
"Microsoft.Extensions.Hosting": "Warning",
"Default": "Information"
}
},
"EventSource": {
"LogLevel": {
"Microsoft": "Information"
}
},
"EventLog": {
"LogLevel": {
"Microsoft": "Information"
}
},
"AzureAppServicesFile": {
"IncludeScopes": true,
"LogLevel": {
"Default": "Warning"
}
},
"AzureAppServicesBlob": {
"IncludeScopes": true,
"LogLevel": {
"Microsoft": "Information"
}
},
"ApplicationInsights": {
"LogLevel": {
"Default": "Information"
}
}
}
}
В предыдущем примере:
Logging.{ProviderName}.LogLevel
переопределяют параметры в Logging.LogLevel
. Например, уровень в Debug.LogLevel.Default
переопределяет уровень в LogLevel.Default
.Console
Debug
EventSource
EventLog
AzureAppServicesFile
AzureAppServicesBlob
ApplicationInsights
Уровень ведения журнала может задаваться любыми поставщиками конфигурации. Например, вы можете создать хранимую переменную среды с именем Logging:LogLevel:Microsoft
и значением Information
.
Создайте хранимую переменную среды и присвойте ей значение уровня ведения журнала.
:: Assigns the env var to the value
setx "Logging__LogLevel__Microsoft" "Information" /M
В новом экземпляре командной строки считайте эту переменную среды.
:: Prints the env var value
echo %Logging__LogLevel__Microsoft%
Указанный выше параметр среды сохраняется в среде. Чтобы проверить параметры при работе с приложением, созданным на базе шаблонов рабочей службы .NET, выполните команду dotnet run
в каталоге проекта после назначения переменной среды.
dotnet run
Совет
После настройки переменной среды перезапустите интегрированную среду разработки, чтобы гарантировать доступность добавленных переменных среды.
В Службе приложений Azure выберите Новый параметр приложения на странице Параметры > Конфигурация. Параметры приложения Службы приложений Azure:
Дополнительные сведения о настройке значений конфигурации .NET с помощью переменных среды см. в разделе Поставщик конфигурации переменных среды.
Чтобы настроить ведение журнала в коде ILoggingBuilder , используйте API. Доступ к ней можно получить из разных мест:
ILoggerFactory
настройте в LoggerFactory.Create.В этом примере показано задание поставщика ведения журнала консоли и нескольких фильтров.
using Microsoft.Extensions.Logging;
using var loggerFactory = LoggerFactory.Create(static builder =>
{
builder
.AddFilter("Microsoft", LogLevel.Warning)
.AddFilter("System", LogLevel.Warning)
.AddFilter("LoggingConsoleApp.Program", LogLevel.Debug)
.AddConsole();
});
ILogger logger = loggerFactory.CreateLogger<Program>();
logger.LogDebug("Hello {Target}", "Everyone");
В предыдущем примере AddFilter используется для настройки уровня журнала, включенного для различных категорий. AddConsole используется для добавления поставщика ведения журнала консоли. По умолчанию журналы с Debug
серьезностью не включены, но так как конфигурация настраивает фильтры, на консоли отображается сообщение отладки "Hello Everyone".
При создании объекта ILogger<TCategoryName> объект ILoggerFactory выбирает одно правило для каждого поставщика, которое будет применено к этому средству ведения журналов. Все сообщения, записываемые с помощью экземпляра ILogger
, фильтруются на основе выбранных правил. Самое подробное правило для каждой пары поставщика и категории выбирается из списка доступных правил.
При создании ILogger
для данной категории для каждого поставщика используется приведенный далее алгоритм:
При создании объекта ILogger
указывается категория. Эта категория входит в состав каждого сообщения журнала, создаваемого этим экземпляром ILogger
. Строка категории является произвольной, но соглашение заключается в том, чтобы использовать полное имя класса. Например, категория может называться "Example.DefaultService"
, если служба в приложении определяется как следующий объект:
namespace Example
{
public class DefaultService : IService
{
private readonly ILogger<DefaultService> _logger;
public DefaultService(ILogger<DefaultService> logger) =>
_logger = logger;
// ...
}
}
Если требуется дальнейшая классификация, соглашение заключается в том, чтобы использовать иерархическое имя путем добавления подкатегории к полному имени класса и явного указания категории с помощью LoggerFactory.CreateLogger:
namespace Example
{
public class DefaultService : IService
{
private readonly ILogger _logger;
public DefaultService(ILoggerFactory loggerFactory) =>
_logger = loggerFactory.CreateLogger("Example.DefaultService.CustomCategory");
// ...
}
}
Вызов CreateLogger
с фиксированным именем может быть полезным при использовании в нескольких классах или типах, чтобы события можно было упорядочить по категориям.
Использование ILogger<T>
эквивалентно вызову CreateLogger
с полным именем типа T
.
В следующей таблице перечислены значения LogLevel, используемый для удобства метод расширения Log{LogLevel}
, а также приводятся сведения о предполагаемом применении:
LogLevel | Значение | Метод | Description |
---|---|---|---|
Трассировка | 0 | LogTrace | Содержит наиболее подробные сообщения. Эти сообщения могут содержать конфиденциальные данные приложения. Эти сообщения по умолчанию отключены, и их никогда не следует включать в рабочей среде. |
Debug | 1 | LogDebug | Используется для отладки и разработки. В рабочей среде следует использовать с осторожностью из-за большого объема. |
Информация | 2 | LogInformation | Отслеживание общего потока работы приложения. Может использоваться в долгосрочных целях. |
Предупреждения | 3 | LogWarning | Для нестандартных или непредвиденных событий. Обычно содержит ошибки или условия, которые не приводят к сбою приложения. |
Ошибка | 4 | LogError | Для ошибок и исключений, которые не могут быть обработаны. Эти сообщения указывают на сбой текущих операции или запроса, а не на ошибку уровня приложения. |
Критически | 5 | LogCritical | Для сбоев, которые требуют немедленного внимания. Примеры: потеря данных, нехватка места на диске. |
Не допускается | 6 | Указывает, что сообщения не должны записываться. |
В приведенной выше таблице значения LogLevel
приведены в порядке от самого низкого к самому высокому уровню серьезности.
Первый параметр метода Log, LogLevel, указывает на степень серьезности журнала. Вместо вызова Log(LogLevel, ...)
большинство разработчиков вызывают методы расширения Log{LogLevel}. Log{LogLevel}
Методы расширения вызывают Log
метод и указывают LogLevel
метод. Например, следующие два вызова ведения журнала функционально эквивалентны и позволяют получить одинаковые журналы:
public void LogDetails()
{
var logMessage = "Details for log.";
_logger.Log(LogLevel.Information, AppLogEvents.Details, logMessage);
_logger.LogInformation(AppLogEvents.Details, logMessage);
}
AppLogEvents.Details
содержит идентификатор события и неявным образом представляется постоянным значением Int32. AppLogEvents
обозначает класс, который предоставляет разные именованные константы для идентификаторов и отображается в разделе Идентификатор события журнала.
Следующий код создает журналы Information
и Warning
:
public async Task<T> GetAsync<T>(string id)
{
_logger.LogInformation(AppLogEvents.Read, "Reading value for {Id}", id);
var result = await _repository.GetAsync(id);
if (result is null)
{
_logger.LogWarning(AppLogEvents.ReadNotFound, "GetAsync({Id}) not found", id);
}
return result;
}
В приведенном выше коде первый Log{LogLevel}
параметр AppLogEvents.Read
— это идентификатор события журнала. Второй параметр — это шаблон сообщения с заполнителями для значений аргументов, предоставляемых оставшимися параметрами метода. Параметры метода рассматриваются более подробно в разделе, посвященном шаблону сообщений далее в этой статье.
Настройте подходящий уровень ведения журнала и вызовите правильные методы Log{LogLevel}
, чтобы управлять объемом данных журнала, записываемых на определенный носитель. Например:
Trace
или Debug
создается большой объем подробных сообщений журнала. Чтобы контролировать затраты и не превысить лимиты объема хранилища данных, записывайте сообщения на уровнях Trace
и Debug
в хранилище данных с низкими затратами и большим объемом. Рассмотрите возможность ограничения уровней Trace
и Debug
конкретными категориями.Warning
по Critical
создается немного сообщений.
Warning
.Trace
или Debug
при устранении неполадок. Чтобы ограничить объем выходных данных, задавайте уровни Trace
или Debug
только для исследуемых категорий.Приведенный ниже код JSON задает уровень Logging:Console:LogLevel:Microsoft:Information
:
{
"Logging": {
"LogLevel": {
"Microsoft": "Warning"
},
"Console": {
"LogLevel": {
"Microsoft": "Information"
}
}
}
}
В каждом журнале может быть задан идентификатор события EventId, представляющий собой структуру с доступными только для чтения свойствами Id
(идентификатор) и Name
(имя, необязательно). В этом примере исходного кода для определения идентификаторов событий используется класс AppLogEvents
.
using Microsoft.Extensions.Logging;
internal static class AppLogEvents
{
internal static EventId Create = new(1000, "Created");
internal static EventId Read = new(1001, "Read");
internal static EventId Update = new(1002, "Updated");
internal static EventId Delete = new(1003, "Deleted");
// These are also valid EventId instances, as there's
// an implicit conversion from int to an EventId
internal const int Details = 3000;
internal const int Error = 3001;
internal static EventId ReadNotFound = 4000;
internal static EventId UpdateNotFound = 4001;
// ...
}
Совет
Дополнительные сведения о преобразовании объекта int
EventId
в оператор EventId.Implicit(Int32 в EventId).
Идентификатор события связывает набор событий. Например, все журналы, связанные с чтением значений из репозитория, могут иметь идентификатор 1001
.
Поставщик ведения журналов может записывать идентификатор события в поле идентификатора, в сообщении журнала, или вообще не сохранять его. Поставщик Debug не отображает идентификаторы событий. Поставщик Console отображает идентификаторы событий в квадратных скобках после категории:
info: Example.DefaultService.GetAsync[1001]
Reading value for a1b2c3
warn: Example.DefaultService.GetAsync[4000]
GetAsync(a1b2c3) not found
Некоторые поставщики ведения журнала хранят идентификатор события в поле, что позволяет выполнять фильтрацию по идентификатору.
Каждый API ведения журнала использует шаблон сообщения. Шаблон сообщения может содержать заполнители, для которых предоставляются аргументы. Используйте для заполнителей имена, а не числа. Параметры, используемые для предоставления значений, определяются порядком заполнителей, а не их именами. В приведенном ниже коде имена параметров идут не по порядку в шаблоне сообщения:
string p1 = "param1";
string p2 = "param2";
_logger.LogInformation("Parameter values: {p2}, {p1}", p1, p2);
Приведенный выше код создает сообщение журнала со значениями параметров в определенном порядке:
Parameter values: param1, param2
Примечание
Помните, что при использовании нескольких заполнителей в одном шаблоне сообщения, так как они основаны на порядковых номерах. Имена не используются для выравнивания аргументов с заполнителями.
Такой подход позволяет поставщикам ведения журнала реализовывать семантическое или структурированное ведение журналов. Сами аргументы передаются в систему ведения журналов, а не только в отформатированный шаблон сообщения. Это позволяет поставщикам ведения журнала хранить значения параметров как поля. Давайте рассмотрим следующий метод средства ведения журнала:
_logger.LogInformation("Getting item {Id} at {RunTime}", id, DateTime.Now);
Например, при ведении журнала в хранилище таблиц Azure:
ID
и RunTime
;RunTime
, не анализируя время ожидания текстового сообщения.Шаблоны сообщений журнала поддерживают форматирование заполнителей. Шаблоны можно указать любой допустимый формат для заданного аргумента типа. Например, рассмотрим следующий Information
шаблон сообщения средства ведения журнала:
_logger.LogInformation("Logged on {PlaceHolderName:MMMM dd, yyyy}", DateTimeOffset.UtcNow);
// Logged on January 06, 2022
В предыдущем примере DateTimeOffset
экземпляр — это тип, соответствующий PlaceHolderName
шаблону сообщения средства ведения журнала. Это имя может быть любым, так как значения основаны на порядковых значениях. Допустимый MMMM dd, yyyy
DateTimeOffset
формат для типа.
Дополнительные сведения о DateTime
DateTimeOffset
форматировании и форматировании см . в строках пользовательского формата даты и времени.
В следующих примерах показано, как отформатировать шаблон сообщения с помощью синтаксиса {}
заполнителя. Кроме того, показан пример экранирования синтаксиса {}
заполнителя со своими выходными данными. Наконец, интерполяция строк с заполнителями шаблонов также показана:
logger.LogInformation("Number: {Number}", 1); // Number: 1
logger.LogInformation("{{Number}}: {Number}", 3); // {Number}: 3
logger.LogInformation($"{{{{Number}}}}: {{Number}}", 5); // {Number}: 5
Совет
Методы средства ведения журнала имеют перегрузки, которые принимают параметр исключения:
public void Test(string id)
{
try
{
if (id is "none")
{
throw new Exception("Default Id detected.");
}
}
catch (Exception ex)
{
_logger.LogWarning(
AppLogEvents.Error, ex,
"Failed to process iteration: {Id}", id);
}
}
Принципы записи исключений в журнал зависят от конкретного поставщика.
Если не задан уровень ведения журнала по умолчанию, то по умолчанию используется уровень Information
.
Давайте рассмотрим следующее приложение службы рабочей роли:
В рамках приведенной выше конфигурации при переходе на страницу сведений о конфиденциальности или домашнюю страницу создается множество сообщений с уровнем Trace
, Debug
и Information
, в имени категории которых используется Microsoft
.
В следующем коде задается уровень ведения журнала по умолчанию в том случае, если этот уровень не определен в конфигурации:
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Logging.SetMinimumLevel(LogLevel.Warning);
using IHost host = builder.Build();
await host.RunAsync();
Функция фильтрации вызывается для всех поставщиков и категорий, которым в конфигурации и (или) коде не назначены правила:
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Logging.AddFilter((provider, category, logLevel) =>
{
return provider.Contains("ConsoleLoggerProvider")
&& (category.Contains("Example") || category.Contains("Microsoft"))
&& logLevel >= LogLevel.Information;
});
using IHost host = builder.Build();
await host.RunAsync();
Приведенный выше код отображает журналы консоли, если категория содержит Example
или Microsoft
и задан уровень ведения журнала Information
или выше.
Область группируйте набор логических операций. Эту возможность можно использовать для присоединения одних и тех же данных к каждому журналу, созданному как часть набора. Например, каждый журнал, созданный в ходе обработки транзакции, может включать идентификатор транзакции.
Область:
Области поддерживаются следующими поставщиками:
Используйте область, заключив вызовы средства ведения журналов в блок using
:
public async Task<T> GetAsync<T>(string id)
{
T result;
var transactionId = Guid.NewGuid().ToString();
using (_logger.BeginScope(new List<KeyValuePair<string, object>>
{
new KeyValuePair<string, object>("TransactionId", transactionId),
}))
{
_logger.LogInformation(
AppLogEvents.Read, "Reading value for {Id}", id);
var result = await _repository.GetAsync(id);
if (result is null)
{
_logger.LogWarning(
AppLogEvents.ReadNotFound, "GetAsync({Id}) not found", id);
}
}
return result;
}
Следующий код JSON предоставляет области для поставщика Console:
{
"Logging": {
"Debug": {
"LogLevel": {
"Default": "Information"
}
},
"Console": {
"IncludeScopes": true,
"LogLevel": {
"Microsoft": "Warning",
"Default": "Information"
}
},
"LogLevel": {
"Default": "Debug"
}
}
}
Следующий код предоставляет области для поставщика Console:
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Logging.ClearProviders();
builder.Logging.AddConsole(options => options.IncludeScopes = true);
using IHost host = builder.Build();
await host.RunAsync();
Следующий код создает журналы в Main
, получая экземпляр ILogger
путем внедрения зависимостей после создания узла:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using IHost host = Host.CreateApplicationBuilder(args).Build();
var logger = host.Services.GetRequiredService<ILogger<Program>>();
logger.LogInformation("Host created.");
await host.RunAsync();
Предыдущий код основан на двух пакетах NuGet:
Его файл проекта будет выглядеть примерно так:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" />
</ItemGroup>
</Project>
Скорость ведения журналов не должна влиять на производительность выполнения асинхронного кода. Если хранилище данных, предназначенное для регистрации сообщений журнала, работает медленно, сначала записывайте эти сообщения в быстродействующее хранилище, а затем перемещайте их в медленное хранилище. Например, если вы записываете журналы в SQL Server, вам не нужно делать это непосредственно в методе Log
, так как методы Log
являются синхронными. Вместо этого синхронно добавьте сообщения журнала в очередь в памяти, и фоновый рабочий поток извлечет сообщения из очереди для выполнения асинхронных операций передачи данных в SQL Server.
API ведения журнала не включает сценарий для изменения уровней журнала во время работы приложения. Однако некоторые поставщики конфигурации могут перезагружать конфигурацию, что немедленно влияет на конфигурацию ведения журнала. Например, поставщик конфигурации файлов по умолчанию перезагружает конфигурацию ведения журнала. Если конфигурация изменяется в коде во время выполнения приложения, приложение может вызвать IConfigurationRoot.Reload , чтобы обновить конфигурацию ведения журнала приложения.
Интерфейсы ILogger<TCategoryName> и ILoggerFactory реализации включены в большинство пакетов SDK для .NET как неявная ссылка на пакет. Они также доступны явным образом в следующих пакетах NuGet, если в противном случае неявно ссылается:
Дополнительные сведения о том, какой пакет SDK для .NET содержит неявные ссылки на пакеты, см. в пакете SDK для .NET: таблица для неявного пространства имен.
Отзыв о .NET
.NET — это проект с открытым исходным кодом. Выберите ссылку, чтобы оставить отзыв:
Обучение
Модуль
Форматирование буквенно-цифровых данных для представления в C# - Training
Изучите основные методы в C# для форматирования буквенно-цифровых данных.