NLog для C# (.NET): полное руководство с примерами
Добро пожаловать в подробное руководство по библиотеке NLog для платформы .NET. NLog — это мощная, гибкая и высокопроизводительная система логирования, которая стала стандартом де-факто для многих .NET-проектов. В этой статье мы разберём всё: от установки до продвинутых техник, с реальными примерами кода и советами по оптимизации.
1. Что такое NLog и зачем она нужна?
NLog (сокращение от ".NET Logging") — это бесплатная библиотека с открытым исходным кодом для платформы .NET, предназначенная для гибкого и производительного логирования. Она позволяет разработчикам записывать диагностическую информацию (логи) в различные места назначения: файлы, консоль, базы данных, сетевые сокеты, системы мониторинга (например, Seq, Elasticsearch, Sentry) и многие другие.
Зачем нужно логирование? В современной разработке программного обеспечения логи — это «чёрный ящик» приложения. Без них невозможно понять, почему упал сервер, где произошла ошибка, какие данные обрабатывались в момент сбоя. NLog решает эту проблему, предоставляя:
- Гибкость маршрутизации: Можно настроить разные уровни логирования (Trace, Debug, Info, Warn, Error, Fatal) для разных частей приложения.
- Производительность: Асинхронная запись, ленивая инициализация, минимальное влияние на скорость работы.
- Расширяемость: Сотни готовых таргетов (целей) и возможность писать свои.
- Конфигурация без перекомпиляции: Настройки можно менять на лету через XML, JSON или код.
NLog идеально подходит для: веб-приложений (ASP.NET Core), консольных утилит, микросервисов, десктопных приложений (WPF/WinForms) и фоновых служб (Windows Services, Worker Services).
2. Установка
Установка NLog производится через менеджер пакетов NuGet. Выполните одну из следующих команд в консоли диспетчера пакетов Visual Studio или в терминале .NET CLI:
// Через .NET CLI (рекомендуется)
dotnet add package NLog
// Через Package Manager Console
Install-Package NLog
// Для ASP.NET Core также рекомендуется установить интеграцию:
dotnet add package NLog.Web.AspNetCore
После установки вам потребуется создать конфигурационный файл nlog.config в корне проекта (или настроить NLog программно).
3. Быстрый старт — минимальный рабочий пример
Создайте консольное приложение и добавьте файл nlog.config (нажмите ПКМ по проекту → Add → New Item → XML File → назовите nlog.config). Вставьте в него:
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- Цель: куда писать логи -->
<targets>
<target name="console" xsi:type="Console" layout="${longdate} | ${level:uppercase=true} | ${message} ${exception:format=ToString}" />
<target name="file" xsi:type="File" fileName="${basedir}/logs/app-${shortdate}.log"
layout="${longdate} | ${level:uppercase=true} | ${logger} | ${message} ${exception:format=ToString}" />
</targets>
<!-- Правила маршрутизации -->
<rules>
<logger name="*" minlevel="Debug" writeTo="console,file" />
</rules>
</nlog>
Теперь напишем код в Program.cs:
using NLog;
public class Program
{
// Создаём логгер для текущего класса
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
public static void Main(string[] args)
{
Logger.Info("Приложение запущено");
try
{
var result = Divide(10, 0);
Logger.Debug($"Результат: {result}");
}
catch (Exception ex)
{
Logger.Error(ex, "Произошла ошибка при делении");
}
Logger.Warn("Это предупреждение");
Logger.Trace("Это трассировочное сообщение (самый низкий уровень)");
// Важно: перед завершением приложения вызываем Shutdown
LogManager.Shutdown();
}
static int Divide(int a, int b) => a / b;
}
Запустите приложение — вы увидите логи в консоли и в файле logs/app-YYYY-MM-DD.log.
4. Основные методы/функции/классы
Рассмотрим ключевые элементы NLog, которые вы будете использовать ежедневно.
4.1. Logger — основной класс для логирования
Сигнатура: Logger LogManager.GetCurrentClassLogger()
Что делает: Создаёт экземпляр логгера, автоматически привязанный к имени текущего класса. Это самый распространённый способ получения логгера.
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
4.2. LogManager — фабрика логгеров и управление конфигурацией
Сигнатура: LogManager.GetLogger(string name)
Что делает: Позволяет получить логгер по произвольному имени (не обязательно имя класса). Полезно для создания иерархических логгеров.
var dbLogger = LogManager.GetLogger("Database");
dbLogger.Info("Подключение к БД установлено");
var authLogger = LogManager.GetLogger("Security.Auth");
authLogger.Warn("Неудачная попытка входа");
4.3. Методы уровней логирования (Trace, Debug, Info, Warn, Error, Fatal)
Сигнатура: void Logger.Trace(string message) / Debug(...) / Info(...) / Warn(...) / Error(...) / Fatal(...)
Что делает: Записывают сообщение с соответствующим уровнем важности. Trace — самый детальный, Fatal — критическая ошибка.
Logger.Trace("Вход в метод Calculate");
Logger.Debug("Переменная x = 42");
Logger.Info("Пользователь успешно авторизован");
Logger.Warn("Диск заполнен на 85%");
Logger.Error("Не удалось сохранить файл");
Logger.Fatal("Критическая ошибка: потеря соединения с БД");
4.4. Логирование исключений — Error(Exception, string)
Сигнатура: void Logger.Error(Exception exception, string message, params object[] args)
Что делает: Логирует исключение вместе с пользовательским сообщением. Автоматически включает стек-трейс и внутренние исключения.
try
{
// опасный код
}
catch (SqlException ex)
{
Logger.Error(ex, "Ошибка SQL при запросе к таблице Users");
}
catch (Exception ex)
{
Logger.Error(ex, "Неизвестная ошибка в методе ProcessOrder");
}
4.5. Форматированное логирование — Info(string, params object[])
Сигнатура: void Logger.Info(string message, params object[] args)
Что делает: Позволяет использовать строковые шаблоны с плейсхолдерами {0}, {1} и т.д. Это быстрее, чем конкатенация строк.
string user = "Alice";
int orderId = 12345;
Logger.Info("Пользователь {0} создал заказ #{1}", user, orderId);
// Вывод: Пользователь Alice создал заказ #12345
4.6. Условное логирование — IsEnabled / Log(LogLevel, ...)
Сигнатура: bool Logger.IsEnabled(LogLevel level) / void Logger.Log(LogLevel level, string message)
Что делает: Позволяет проверить, включён ли определённый уровень, и выполнить логирование с динамическим уровнем. Полезно для дорогих вычислений в сообщениях.
if (Logger.IsEnabled(LogLevel.Debug))
{
var expensiveData = ComputeExpensiveData();
Logger.Debug("Данные: {0}", expensiveData);
}
// Альтернатива с динамическим уровнем
Logger.Log(LogLevel.Warn, "Это динамическое предупреждение");
4.7. MappedDiagnosticsContext (MDC) / NestedDiagnosticsContext (NDC)
Сигнатура: MappedDiagnosticsContext.Set(string key, string value) / NestedDiagnosticsContext.Push(string value)
Что делает: Позволяют добавлять контекстную информацию к логам в рамках одного потока/запроса. MDC — пары ключ-значение, NDC — стек значений. Идеально для логирования ID запроса, имени пользователя и т.д.
// В начале HTTP-запроса
MappedDiagnosticsContext.Set("UserId", "12345");
MappedDiagnosticsContext.Set("RequestId", Guid.NewGuid().ToString());
// В любом месте потока
Logger.Info("Обработка запроса"); // В лог добавится UserId и RequestId
// В конце запроса — очистка
MappedDiagnosticsContext.Remove("UserId");
MappedDiagnosticsContext.Remove("RequestId");
В конфигурации используйте ${mdc:item=UserId} для вывода значения.
4.8. LogManager.Configuration — программная конфигурация
Сигнатура: LogManager.Configuration (свойство типа LoggingConfiguration)
Что делает: Позволяет изменять конфигурацию NLog программно (без XML-файла). Полезно для динамической настройки.
var config = new LoggingConfiguration();
// Цель: файл
var fileTarget = new FileTarget("logfile")
{
FileName = "${basedir}/logs/custom.log",
Layout = "${longdate} ${message}"
};
config.AddTarget(fileTarget);
// Правило: все уровни для всех логгеров
config.AddRuleForAllLevels(fileTarget);
// Применяем конфигурацию
LogManager.Configuration = config;
// Теперь можно использовать логгеры
Logger.Info("Программная конфигурация работает!");
4.9. AsyncWrapper — асинхронная запись
Сигнатура: Используется в конфигурации: <target name="asyncFile" xsi:type="AsyncWrapper" queueLimit="5000" overflowAction="Discard">
Что делает: Оборачивает любой таргет в асинхронный режим. Логи сначала помещаются в очередь, а затем записываются в фоновом потоке. Это повышает производительность, но может привести к потере логов при аварийном завершении.
<targets>
<target name="asyncFile" xsi:type="AsyncWrapper" queueLimit="10000" overflowAction="Grow">
<target name="file" xsi:type="File" fileName="app.log" />
</target>
</targets>
5. Реальный практический пример (100-200 строк кода)
Рассмотрим полноценный пример: веб-сервис для обработки заказов с логированием в файл, консоль и базу данных (SQLite).
Шаг 1: Установите пакеты
dotnet add package NLog
dotnet add package NLog.Database
dotnet add package Microsoft.Data.Sqlite
Шаг 2: Файл nlog.config
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<!-- Консоль с цветами -->
<target name="console" xsi:type="ColoredConsole"
layout="${date:format=HH:mm:ss} ${level} ${message} ${exception:format=ToString}" />
<!-- Файл с ротацией по размеру -->
<target name="file" xsi:type="File"
fileName="${basedir}/logs/order-service.log"
archiveFileName="${basedir}/logs/order-service.{#}.log"
archiveEvery="Day"
archiveNumbering="Rolling"
maxArchiveFiles="7"
layout="${longdate} [${level:uppercase=true}] ${logger} - ${message} ${exception:format=ToString}" />
<!-- База данных SQLite -->
<target name="database" xsi:type="Database"
dbProvider="Microsoft.Data.Sqlite.SqliteConnection, Microsoft.Data.Sqlite"
connectionString="Data Source=logs.db">
<installCommand>
CREATE TABLE IF NOT EXISTS Logs (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
Date TEXT,
Level TEXT,
Logger TEXT,
Message TEXT,
Exception TEXT
)
</installCommand>
<commandText>
INSERT INTO Logs (Date, Level, Logger, Message, Exception)
VALUES (@Date, @Level, @Logger, @Message, @Exception)
</commandText>
<parameter name="@Date" layout="${longdate}" />
<parameter name="@Level" layout="${level}" />
<parameter name="@Logger" layout="${logger}" />
<parameter name="@ Также в библиотеке
HTTP-клиент для JavaScript (Node.js): топ библиотек для работы с API
GraphQL в C++: библиотека cppgraphqlgen для создания API
Работа с ZIP/архивами в C++: библиотека libzip и zlib
Обработка JSON в Go (Golang): encoding/json и альтернативы
Media3 / ExoPlayer для Kotlin: полное руководство с примерами