Нові стандартні механізми

Це невелика серія статей про нові стандартні механізми у .NET. Разом з випуском .NET Standard Microsoft випустили велику кількість обв'язок, які повинні упорядкувати деякий зоопарк використовуваних технологій.
У першій статті (IoC-контейнер) ми поговорили про те, чому це круто мати реалізацію DI-контейнера за замовчуванням, і чому в більшості випадків варто використовувати саме його. Також написали просту реалізацію біндингу за атрибутами.
У другій (Конфігурація) я розповів про недоліки старого способу конфігурування програми (через app.config/web.config) та про те, як вони виправлені у новому підході.
У цій - третьій - подивимося на стандартний інтерфейс логування і прикрутимо до нього звичний NLog.
- Контейнер IoC.
- Конфігурація
- Логування.
Логування
Навіщо взагалі новий інструмент для логування?
Ми вже маємо NLog, log4net, Serilog. Все це чудові інструменти, але дуже сумно, коли у великому рішенні зустрічаються всі вони. Тоді доводиться або перекладати все наодинці, або впилювати якусь абстракцію. Ще не дуже добре використовувати конкретне рішення без прошарку в бібліотеці, що поширюється, тому що це знову приведе кінцевих споживачів до необхідності використовувати ваш інструмент (а вони вже можуть використовувати інший).
Ми вже маємо Common.Logging, якщо ми хочемо відвернутися від конкретного інструменту (наприклад, у бібліотеках). Common.Logging - це, звичайно, добре, але не факт, що кінцеві споживачі вашої бібліотеки захочуть використовувати його. Ще великий мінус, що ви не будете використовувати Common.Logging за умовчанням скрізь, набагато частіше простовізьмете NLog і забудете про проблему, доки вона не спливе.
Microsoft.Extensions.Logging відмінно вирішує ці проблеми. Це такий Common.Logging, який використовується за замовчуванням у Core додатках, що призводить до того, що миточно будемо використовувати цей спосіб. Тепер не абстракція підлаштовується під інструменти (як Common.Logging), а інструмент під абстракцію.
Подивимося, як це працює. Створимо консольну програму .NET Core і встановимо пакети:
І напишемо наступний код, щоб розібратися, що відбувається.
Тут ми використовуємо найпростіший спосіб ініціалізації та використання логування. Спочатку створюється фабрика логів LoggerFactory. Потім додаються провайдери через методи-розширення AddConsole (виведення на консоль) і AddDebug (виведення в консоль налагодження). Параметри задають предикат запису логів у провайдер. У разі AddConsole ми передали лямбду, яка приймає рядок повідомлення та рівень протоколювання, а повертає bool. У AddDebug передали мінімально можливий рівень. У виведенні консолі налагодження побачимо:
У консоль виведеться:
Все правильно, для консолі пишемо все, для налагодження - тільки Debug і вище
AddConsole і AddDebug - це просто обгортки над void AddProvider(ILoggerProvider provider), який додає провайдер до цієї фабрики логерів. Відповідно, ми можемо додати консольний логер наступним чином:
Ну і звичайно, ми можемо написати свій провайдер, якщо раптом виникне така необхідність.
Ще варто згадати таку річ, як Scopes. Вони дозволяють краще прив'язати логування до бізнес-завдань. Як приклад, напишемо таку програму:
Виведення на консоль буде таким:

Видно, що скоупи впливають висновок, причому впливають попри всі логери.
ТеперСпробуємо прикрутити NLog в ASP.NET Core-додаток. Спочатку створимо проект за шаблоном «Web-додаток ASP.NET Core», «Порожній».
На момент написання статті NLog для .NET Core знаходиться в беті, тому ставимо наступною командою:
Після цього поставимо пакет NLog.Web.AspNetCore, який містить рендерери для веб-додатків.
Створимо в корені проекту файл NLog.config і виставимо йому правило копіювання у вихідний каталог Завжди копіювати. Вміст файлу:
У layout ми використовували кілька ASP.NET-специфічних рендерерів - наприклад, $ для відображення URL запиту.
Тепер змінимо наш Startup.cs, додавши туди підтримку NLog.
До методу ConfigureServices додамо:
Це дозволить нам інжектити IHttpContextAccessor у singleton-сервіси та мати доступ до поточного HttpContext.
А до методу Configure додамо наступне:
Метод AddNLogWeb зберігає в статичну змінну DI-контейнер (ServiceProvider), з якого NLog діставатиме необхідні речі (наприклад, той же IHttpContextAccessor).
loggerFactory.AddNlog — додає провайдер Nlog-а
Після запуску програми та виконання будь-якого запиту ми побачимо у нашому файлі рядки типу такого:
Тут ми бачимо все, що потрібне для розуміння, який це був запит.
Самі логери органічно вбудовані в інфраструктуру ASP.NET Core - ви можете інжектити ILogger в будь-який сервіс, і він розрізняється. Якщо ви хочете працювати як у класичних додатках і створювати логер руками, то просто збережіть екземпляр ILoggerFactory в статичне поле і смикайте CreateLogger, коли вам заманеться. Бажано не створювати статичних логерів, а мати індивідуальний екземпляр логгера на екземпляр класу.
Таким чином, інфраструктуралогування зазнала деяких змін, і тепер вам доведеться використати саме її. Протоколування піднято на новий рівень абстракції і ви можете вибрати, який спосіб логування використовувати. Усі системні інструменти/фреймворки (такі як ASP.NET Core) використовують саме такий підхід. Все це органічно вбудоване у загальну екосистему і вимагає від розробника якихось особливих знань.