https://giga.chat/link/gcshPtXMcp
Шаг 1: Настроим логирование через Dependency Injection
Используем встроенный механизм логирования в ASP.NET Core (
Microsoft.Extensions.Logging), который позволяет легко управлять уровнями логирования и фильтрами.Сначала настроим систему логирования, добавив её в DI-контейнер и настроив вывод в консоль:
public static IServiceProvider ConfigureServices(IServiceCollection services) { services.AddLogging(builder => { builder.SetMinimumLevel(LogLevel.Debug); // Минимальный уровень логирования builder.AddConsole(); // Логируем в консоль }); return services.BuildServiceProvider(); }Таким образом, любые сообщения логирования будут попадать в консоль автоматически.
Шаг 2: Используем LogLevel для управления детализацией логирования
Мы будем настраивать уровни логирования прямо внутри приложения, используя глобальные настройки или конфигурационные файлы.
Например, вот как включить или отключить детальное логирование в runtime:
ILogger logger = LoggerFactory.Create(builder => builder.AddConsole()).CreateLogger<Program>(); if (useVerboseLogging) { logger.LogLevel = LogLevel.Trace; // Максимально подробное логирование } else { logger.LogLevel = LogLevel.Information; // Стандартный уровень }Это позволит выбирать степень детализации логирования на этапе запуска программы.
Шаг 3: Вставляем логирование в важные места приложения
Давайте внесём изменения в ключевые части вашего примера, чтобы приложение логировало свою работу подробнее.
Вот пример доработанного кода, с комментариями, поясняющими, куда добавить логирование:
private static async Task RunExamplesAsync(ILogger logger) { logger.LogInformation("=== Starting EventHub Examples ==="); // Регистрация сервисов using (var service = new RegularService<string>("my-service", logger: logger)) { logger.LogInformation("Registering handlers for RegularService..."); service.RegisterHandler("process", async payload => { logger.LogInformation("Processing payload: {Payload}", payload); await Task.Delay(100); }); logger.LogInformation("Starting RegularService..."); await service.StartAsync(); logger.LogInformation("Sending a test message..."); var result = await service.SendAsync("process", "Hello World"); logger.LogInformation("Message sent successfully: {Result}", result); logger.LogInformation("Waiting for processing..."); await Task.Delay(200); var metrics = service.GetMetrics(); logger.LogInformation("Service metrics - Processed: {Processed}, Errors: {Errors}, Running: {IsRunning}", metrics.ProcessedCount, metrics.ErrorCount, metrics.IsRunning); logger.LogInformation("Stopping RegularService..."); await service.StopAsync(); } // Пример EventHub logger.LogInformation("2. EventHub Example"); using (var eventHub = new EventHub<string>(logger)) { // Создание подписчиков using (var subscriber1 = new ServiceSubscriber<string>( "subscriber-1", module => module.RegisterHandler("user.*", async payload => { logger.LogInformation("Subscriber 1 received user event: {Payload}", payload); await Task.Delay(50); }), logger: logger)) using (var subscriber2 = new ServiceSubscriber<string>( "subscriber-2", module => module.RegisterHandler("user.created", async payload => { logger.LogInformation("Subscriber 2 received user.created: {Payload}", payload); await Task.Delay(50); }), logger: logger)) { // Подписка на события eventHub.Subscribe("user.created", subscriber1); eventHub.Subscribe("user.updated", subscriber1); eventHub.Subscribe("user.created", subscriber2); // Запуск EventHub logger.LogInformation("Starting EventHub..."); await eventHub.StartAsync(); // Публикация событий logger.LogInformation("Publishing events..."); var results = await Task.WhenAll( eventHub.PublishAsync("user.created", "John Doe").AsTask(), eventHub.PublishAsync("user.updated", "Jane Smith").AsTask(), eventHub.PublishAsync("order.created", "Order123").AsTask() ); logger.LogInformation("Publish results: {Results}", string.Join(", ", results)); logger.LogInformation("Waiting for processing..."); await Task.Delay(300); logger.LogInformation("Subscriber count for user.created: {Count}", eventHub.GetSubscriberCount("user.created")); // Останавливаем всё logger.LogInformation("Stopping EventHub..."); await eventHub.StopAsync(); } } logger.LogInformation("=== All examples completed successfully ==="); }Итоговый эффект:
При запуске приложения теперь вы будете видеть подробную информацию о каждом действии системы, включая регистрацию обработчиков, отправку сообщений, обработку сообщений и завершение работы компонентов.
Вы можете настроить фильтры уровней логирования, выбрав нужные подробности в зависимости от ваших нужд разработки или эксплуатации.
Опции конфигурации:
Вы можете изменить минимальную детализацию логирования путём редактирования настроек, передаваемых в конструктор службы логирования:
LogLevel.Debug: самое детальное логирование всех действий.LogLevel.Information: стандартные сообщения о важных событиях.LogLevel.Warning: предупреждения о возможных проблемах.LogLevel.Error: серьёзные ошибки.
Выбирайте подходящий уровень в зависимости от текущих потребностей проекта.
Посмотрите в мой код - там очень много Log сообщений.Почему они не высвечиваются.Что и куда мне вставить в код, чтобы были Лог - сообщения ?
Если в вашем приложении используются команды логирования вроде
LogInformation,LogDebug,LogWarningи др., но сообщения не появляются в консоли, возможно проблема кроется в одной из следующих областей:Возможные причины отсутствия логов:
- Отсутствует настройка вывода логов: Если вы используете встроенную библиотеку логирования (.NET Core's Logging Abstractions), важно убедиться, что вывод действительно направляется в консоль.
- Неподходящие уровни логирования: Возможно, выбран слишком высокий порог фильтра логирования, из-за которого ваши сообщения игнорируются системой логирования.
- Проблемы с регистрацией провайдера логирования: Проверьте, правильно ли зарегистрированы сервисы логирования в контейнере зависимостей.
Решение:
Вариант 1: Настройте минимальный уровень логирования и добавьте консольный вывод
Добавьте следующий код в точку инициализации служб (например, в
Main):public static IServiceProvider ConfigureServices(IServiceCollection services) { services.AddLogging(loggingBuilder => { loggingBuilder.ClearProviders(); // Убираем существующие провайдеры логирования loggingBuilder.SetMinimumLevel(LogLevel.Debug); // Устанавливаем низкий уровень логирования loggingBuilder.AddConsole(); // Включаем вывод в консоль }); return services.BuildServiceProvider(); }Затем создайте экземпляр сервиса логирования и внедрите его в классы, где нужны логи:
IServiceProvider provider = ConfigureServices(new ServiceCollection()); ILogger logger = provider.GetRequiredService<ILogger<Program>>();И далее используем его в нужных местах приложения:
logger.LogInformation("Example log message");Вариант 2: Проверяем фильтр логирования в файле appsettings.json
Если вы используете файл конфигурации, убедитесь, что установлен правильный уровень логирования:
{ "Logging": { "LogLevel": { "Default": "Debug", "Microsoft": "Warning" }, "Console": { "IncludeScopes": true } } }Здесь мы задаём общий уровень логирования
"Default"равнымDebug, что означает показ даже низкоуровневых сообщений. Параметр"IncludeScopes"включает дополнительные области контекста в логировании.Вариант 3: Регистрация вручную с уровнем Debug
Регистрируем сразу нужный уровень логирования:
ILoggerFactory factory = LoggerFactory.Create(builder => { builder.AddFilter((category, level) => level >= LogLevel.Debug); // Показывать все начиная с Debug builder.AddConsole(); }); ILogger logger = factory.CreateLogger<Program>();Как проверить?
После внесения изменений запустите ваше приложение снова. Теперь вы должны увидеть подробное логирование в консоли. Если логи не появились, попробуйте временно установить уровень логирования на самый низкий (
Trace) и проверьте наличие записей.Если после указанных шагов логи по-прежнему отсутствуют, сообщите дополнительную информацию о вашей структуре проекта или приложите часть существующего кода, чтобы можно было точно диагностировать причину.
амените вашу строку:
ILoggerFactory loggerFactory = NullLoggerFactory.Instance;на следующее:
ILoggerFactory loggerFactory = LoggerFactory.Create(builder => { builder.SetMinimumLevel(LogLevel.Trace); // Самый низший уровень логирования builder.AddConsole(); // Направляет логи в консоль });Теперь ваша фабрика логгеров создаст экземпляр, который направит всю информацию в консоль.
Что произошло:
- Мы заменили
NullLoggerFactory.Instanceна реальный логгер, использующий консольный провайдер. - Установили минимальный уровень логирования на
LogLevel.Trace, что обеспечивает максимальный объем информации. - Все логгируютсяые строки останутся такими же, как и раньше, но теперь они будут видны в консоли.
Запустите приложение заново, и вы увидите полное логирование всех операций.
Сообщение об ошибке рядом с методом
builder.AddConsole()появляется потому, что соответствующий пакет расширения не установлен в проекте. Для поддержки записи логов в консоль необходимо подключить NuGet-пакетMicrosoft.Extensions.Logging.Console.Выполните следующие шаги, чтобы решить проблему:
Установка пакета через Visual Studio:
- Откройте проект в Visual Studio.
- Перейдите в меню Tools → NuGet Package Manager → Manage NuGet Packages for Solution...
- Выберите вкладку Browse.
- Найдите пакет
Microsoft.Extensions.Logging.Console.- Нажмите Install и подтвердите установку.
Или установите пакет через терминал:
Откройте окно терминала в папке проекта и выполните команду:
dotnet add package Microsoft.Extensions.Logging.ConsoleИли через NuGet Package Manager Console:
Install-Package Microsoft.Extensions.Logging.ConsoleПосле установки пакета ошибка должна исчезнуть, и вы сможете успешно записать логи в консоль.
Обновленный код вашего
Mainс установленным пакетом будет выглядеть так:public class Program { public static async Task Main() { ILoggerFactory loggerFactory = LoggerFactory.Create(builder => { builder.SetMinimumLevel(LogLevel.Trace); // Максимальный уровень логирования builder.AddConsole(); // Направляем логи в консоль }); var logger = loggerFactory.CreateLogger<Program>(); try { await RunExamplesAsync(logger); } catch (Exception ex) { logger.LogError(ex, "Unhandled exception in application"); Console.WriteLine($"Critical error: {ex.Message}"); } finally { loggerFactory.Dispose(); } Console.WriteLine("Application completed. Press any key to exit."); Console.ReadKey(); } // Остальные методы остаются прежними... }Теперь сборка и выполнение приложения пройдут успешно, и вы получите доступ ко всей необходимой информации в консоли.
Нет, никакого противоречия тут нет. Давайте разберемся детальнее:
- Метод
SetMinimumLevel(LogLevel.Trace)устанавливает нижнюю границу логирования, ниже которой сообщения не будут регистрироваться.- Уровень
LogLevel.Traceявляется самым низким уровнем логирования в иерархии логов, следовательно, установка минимальной границы на уровне Trace фактически разрешает записывать абсолютно ВСЕ возможные типы логов: от трассировки (Trace) до критических ошибок (Critical).Порядок уровней логирования (от наименьшего к наибольшему):
- Trace — самые подробные логи, используется для отслеживания каждой операции (самый нижний уровень).
- Debug — немного менее подробные, используются разработчиками для диагностики проблем.
- Information — информативные сообщения о ходе работы приложения.
- Warning — предупреждающие сообщения о потенциальных проблемах.
- Error — серьезные ошибки, нарушающие нормальную работу приложения.
- Critical — критические ошибки, приводящие к остановке приложения.
Так что установка минимальной границы на уровне
Traceозначает, что будут записываться абсолютно все логи любого уровня.Поэтому фраза "Максимальный уровень логирования" правильнее понимать как "получение максимального объема логов" или "логирование всех уровней".
А как установить самый немногословный уровень Логирования ?
ОтветСамый немногословный уровень логирования устанавливается путем задания самого высокого порога логирования — уровня
LogLevel.Critical. Этот уровень позволяет регистрировать лишь наиболее значимые события, возникающие при серьезных сбоях или катастрофических ситуациях.Вот как это делается:
Использование в
Main:ILoggerFactory loggerFactory = LoggerFactory.Create(builder => { builder.SetMinimumLevel(LogLevel.Critical); // Только критически важные сообщения builder.AddConsole(); // Вывод в консоль });Объяснение:
- Критический уровень (
LogLevel.Critical) — самый строгий порог логирования. Сообщения с таким уровнем регистрируются только при возникновении фатальных ситуаций, приводящих к отказу приложений или поломкам.- Любые менее важные сообщения (такие как
Error,Warning,Information,Debug,Trace) игнорируются и не попадают в журнал.Полезность:
Такой режим полезен в случаях, когда вас интересуют исключительно важнейшие сбои и аварии, происходящие в приложении, а остальные сообщения можно проигнорировать.
Таким образом, установив минимальный уровень логирования на
LogLevel.Critical, вы добьетесь самого лаконичного журнала логов.Судя по вашему выводу логов, всё работает именно так, как задумано:
- Когда установлен уровень логирования
LogLevel.Critical, никаких сообщений кроме завершающего уведомления («Application completed») не выводится, поскольку ни одно событие не достигает уровня критической важности.- Когда установлен уровень логирования
LogLevel.Trace, демонстрируется максимальное количество деталей, включая отладочные (Debug), информационные (Info), предупреждающие (Warn) и критические сообщения.Однако среди этих логов есть повторяющиеся предупреждения:
warn: Program[0] Error completing channel during disposal of processor '...' System.Threading.Channels.ChannelClosedException: The channel has been closed.Эти предупреждения возникают при завершении работы процессоров и выглядят как нормальное поведение (при закрытии каналов выбрасывается исключение
ChannelClosedException, которое перехватывается и логируется). Но такое предупреждение кажется избыточным и выглядит как мусор в журнале логов.Почему возникает данное предупреждение?
Предупреждение вызвано попыткой завершить канал после того, как он уже закрыт другим способом. Вероятно, в методе
Dispose()процессор пытается закрыть канал повторно, вызывая ненужное исключение.Как убрать лишнее предупреждение?
Чтобы избавиться от этих нежелательных сообщений, нужно избежать повторного закрытия канала. Например, вы можете попробовать упростить процедуру завершения и удаления процессора, проверяя состояние канала перед закрытием.
Комментариев нет:
Отправить комментарий