Логирование в C++: лучшие практики для начинающих

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

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

Начать курс

Логирование в C++ приложениях: лучшие практики для начинающих

Логирование (журналирование) — это процесс записи событий, происходящих во время работы программы. Для начинающего C++ разработчика умение правильно организовать логирование — это не просто «хороший тон», а критически важный навык. Оно помогает отлаживать код, отслеживать ошибки в продакшене и анализировать поведение системы. В этой статье мы разберем лучшие практики логирования в C++, от простейших способов до использования современных библиотек, с конкретными примерами кода.

Почему простое использование std::cout — это плохая практика?

Многие новички начинают с вывода отладочных сообщений через std::cout или printf. Это быстро и просто, но у такого подхода есть серьезные недостатки:

  • Отсутствие уровней важности. Нельзя отделить сообщения об ошибках от информационных уведомлений.
  • Сложность фильтрации. В продакшене вы не хотите видеть тонны отладочных сообщений, а при отладке они нужны.
  • Нет ротации файлов. Лог-файл будет расти бесконечно, пока не заполнит весь диск.
  • Проблемы с многопоточностью. Вывод из разных потоков может перемешаться.

Вместо этого следует использовать специализированные инструменты. Рассмотрим три основных подхода: от простого к сложному.

1. Простая макросная обертка для начинающих

Если вы пишете небольшую учебную программу или не хотите подключать сторонние библиотеки, можно создать простую обертку на макросах. Это уже лучше, чем голый cout.

#include <iostream>
#include <fstream>
#include <ctime>
#include <string>

enum LogLevel {
    DEBUG,
    INFO,
    WARNING,
    ERROR
};

std::string getCurrentTime() {
    std::time_t now = std::time(nullptr);
    char buf[20];
    std::strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", std::localtime(&now));
    return std::string(buf);
}

#define LOG(level, msg) \
    do { \
        std::ofstream logFile("app.log", std::ios::app); \
        logFile << "[" << getCurrentTime() << "] " \
                << "[" << #level << "] " \
                << msg << std::endl; \
    } while(0)

int main() {
    LOG(INFO, "Программа запущена");
    int x = 42;
    LOG(DEBUG, "Значение x: " << x);
    // ...
    LOG(ERROR, "Произошла ошибка деления на ноль");
    return 0;
}

Плюсы: простота, не требует внешних зависимостей.

Минусы: нет ротации, медленная работа (открытие/закрытие файла на каждое сообщение), проблемы с потоками.

2. Использование библиотеки spdlog (рекомендуется для начинающих)

spdlog — это самая популярная библиотека для логирования в C++ (более 23 000 звезд на GitHub). Она очень быстрая, простая в использовании и header-only (только заголовочные файлы).

Установка: просто скачайте файлы из репозитория или используйте vcpkg/conan.

#include <spdlog/spdlog.h>
#include <spdlog/sinks/basic_file_sink.h>
#include <spdlog/sinks/stdout_color_sinks.h>

int main() {
    // Создаем консольный логгер с цветным выводом
    auto console = spdlog::stdout_color_mt("console");
    
    // Создаем файловый логгер
    auto file_logger = spdlog::basic_logger_mt("file_logger", "logs/app.log");
    
    // Устанавливаем уровень логирования
    spdlog::set_level(spdlog::level::debug); // Логировать все от DEBUG и выше
    
    // Примеры сообщений разных уровней
    console->trace("Это trace сообщение (самый низкий уровень)");
    console->debug("Отладочное сообщение: переменная x = {}", 42);
    console->info("Программа успешно запущена");
    console->warn("Предупреждение: память почти закончилась");
    console->error("Ошибка: не удалось открыть файл {}", "data.txt");
    
    // Логирование в файл
    file_logger->info("Запись в файл: операция завершена");
    
    // Изменение формата вывода
    spdlog::set_pattern("[%Y-%m-%d %H:%M:%S] [%^%l%$] [%n] %v");
    console->info("Теперь формат с цветом и именем логгера");
    
    return 0;
}

Ключевые возможности spdlog:

  • Уровни логирования: trace, debug, info, warn, error, critical
  • Цветной вывод в консоль (поддерживает Windows и Linux)
  • Ротация файлов по размеру и времени
  • Асинхронное логирование для высокой производительности
  • Форматирование в стиле fmtlib (как Python f-strings)

3. Продвинутые практики: асинхронное логирование и ротация

Для серьезных приложений нужно настроить ротацию логов и асинхронную запись. spdlog делает это очень просто.

#include <spdlog/spdlog.h>
#include <spdlog/sinks/rotating_file_sink.h>
#include <spdlog/async.h> // Для асинхронного режима

int main() {
    // Асинхронный логгер с ротацией файлов
    // Максимальный размер файла: 5 МБ, хранить 3 файла
    auto logger = spdlog::rotating_logger_mt(
        "rotating_logger", 
        "logs/rotation.log", 
        5 * 1024 * 1024,  // 5 MB
        3                  // хранить 3 файла
    );
    
    // Устанавливаем уровень
    logger->set_level(spdlog::level::info);
    
    // Формат с микросекундами
    logger->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] %v");
    
    // Пример циклической записи (для теста ротации)
    for (int i = 0; i <                

Блоги

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