NLog для C# (.NET): полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

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="@                    

Рекомендаций