Logger C++

Написал я логгер на C++ для C++
https://github.com/Fallet666/logger

А еще важная информация, я ищу работу C++ разработчика, пожалуйста напишите мне https://t.me/born_in_void, если можете помочь, я студент в Москве)

9637374f46086fccdafe08148dbfed15.png

Logger Library

Этот проект представляет собой простую и гибкую библиотеку для логирования на C++. Библиотека поддерживает разные уровни логирования, форматирование сообщений и возможность записи логов в разные потоки.

Основные возможности

  • Поддержка различных уровней логирования: DEBUG, INFO, WARN, ERROR.

  • Настраиваемое форматирование логов.

  • Возможность логирования в несколько потоков с защитой от гонок данных.

  • Логирование в разные выходные потоки (std::cout, файлы и т.д.).

  • Возможность использования глобального логгера.

Установка

  1. Склонируйте репозиторий:

    git clone 
    
  2. Перейдите в директорию проекта и соберите его с использованием CMake:

    cd logger
    mkdir build
    cd build
    cmake ..
    make
    

Основные концепции

  • Logger: основной класс для логирования. Создавайте экземпляр этого класса для логирования в определенный поток.

  • Глобальный логгер: Singleton-экземпляр Logger, который можно использовать по умолчанию во всем проекте.

Функции логирования

В проекте доступны несколько функций для записи логов с разными уровнями важности. Эти функции позволяют гибко управлять выводом сообщений в зависимости от их критичности. Логи делятся на четыре уровня:

  • DEBUG — Для отладочной информации.

  • INFO — Для общих информационных сообщений.

  • WARN — Для предупреждений.

  • ERROR — Для ошибок, требующих внимания.

Базовые функции

LOG_MESSAGE (Logger& logger, LogLevel level, const std: string& message)

Записывает сообщение с заданным уровнем. Эта функция является универсальной и может использоваться для логирования сообщений любого уровня.

Пример использования:

Logger::Logger log("Logger");
LOG_MESSAGE(log, Logger::DEBUG, "I'm MESSAGE");

Упрощенные функции для каждого уровня

Эти функции предназначены для упрощения вызова логирования на определённом уровне:

1. logDebug (Logger& logger, const std: string& message)

Логирует сообщение с уровнем DEBUG.

Пример использования:

logDebug(log, "This is a debug message");

2. logInfo (Logger& logger, const std: string& message)

Логирует сообщение с уровнем INFO.

Пример использования:

logInfo(log, "This is an info message");

3. logWarn (Logger& logger, const std: string& message)

Логирует сообщение с уровнем WARN.

Пример использования:

logWarn(log, "This is a warning message");

4. logError (Logger& logger, const std: string& message)

Логирует сообщение с уровнем ERROR.

Пример использования:

logError(log, "This is an error message");

Глобальные функции логирования

Проект также предоставляет глобальные функции логирования, которые используют глобальный логгер (globalLogger). Эти функции позволяют записывать сообщения без необходимости создания и управления собственными экземплярами логгера.

Аналогично базовым функциям существуют следующие глобальные функции логирования:

  • logMessageGlobal(LogLevel level, const std::string& message)

  • logDebugGlobal(const std::string& message)

  • logInfoGlobal(const std::string& message)

  • logWarnGlobal(const std::string& message)

  • logErrorGlobal(const std::string& message)

Уровень логирования

Можно установить уровень логирования через Cmake, тогда будут отображаться логи не ниже заданного уровня. Например, если вы установите уровень Warn, то будут отображаться логи уровня Warn и Error.

Использование в Cmake:

set(DEFAULT_LOG_LEVEL DEBUG)
add_compile_definitions(GLOBAL_LOG_LEVEL=${DEFAULT_LOG_LEVEL})

Примечание

Каждая из функций логирования автоматически добавляет информацию о файле и строке, откуда был вызван лог, используя макросы FILE и LINE. Это позволяет легче отслеживать источник логов в коде.

Форматирование логов

Форматирование по умолчанию:

Строка форматирования:»%L: %T [%N]: %M\n»

Пример вывода:

DEBUG: 12:34:56 [MyLogger]: This is a debug message

Расширенное форматирование

Логи можно кастомизировать с помощью строки форматирования. По умолчанию строка форматирования может содержать следующие компоненты:

  • %L — Уровень логирования (DEBUG, INFO, WARN, ERROR).

  • %T — Время записи лога в формате HH: MM: SS.

  • %N — Имя логгера.

  • %M — Сообщение лога.

  • %t — Идентификатор потока, который записал лог.

  • %S — Имя файла, из которого был вызван лог.

  • %# — Номер строки в файле, откуда был вызван лог.

Эти спецификаторы можно комбинировать и располагать в любом порядке, чтобы настроить формат логов под нужды проекта.

Строка форматирования задается следующим образом:

Logger::Logger log("custom formating");
log.setFormatString("%L: %T [%N]: %M (%S: %#)\n");

Использование цветов в логах

В проекте предусмотрена возможность цветного вывода логов в консоль, чтобы легко различать сообщения разных уровней. Цвета автоматически применяются, если выходной поток логгера настроен на std::cout.

Цветовая схема:

  • DEBUG — Белый (\033[37m).

  • INFO — Зеленый (\033[32m).

  • WARN — Желтый (\033[33m).

  • ERROR — Красный (\033[31m).

Цвета можно увидеть в терминале при выводе логов, что значительно упрощает идентификацию важности сообщений.

Отключение цвета

Цвета автоматически отключаются, если вы используете другой поток вывода (например, запись логов в файл).

Логирование в многопоточных приложениях

В проекте предусмотрена поддержка многопоточного логирования. Это значит, что несколько потоков могут одновременно записывать логи без риска порчи данных или возникновения гонок.

Синхронизация потоков

Для обеспечения потокобезопасности в классе Logger используется мьютекс (std::mutex). Каждый раз, когда вызывается функция логирования или происходит изменение полей логгера, поток блокируется до завершения операции. Это предотвращает одновременный доступ к общим ресурсам (например, к выходному потоку или настройкам логгера), что гарантирует корректность и целостность данных в логах.

Пример многопоточного логирования

Logger::Logger log("MultiThreadLogger");

std::vector threads;
for (int i = 0; i < 10; ++i) {
    threads.emplace_back([&log, i] {
        logInfo(log, "Message from thread " + std::to_string(i));
    });
}

for (auto &t : threads) {
    t.join();
}

В этом примере создается 10 потоков, каждый из которых записывает лог-сообщение с информацией о своем номере. Благодаря использованию мьютекса, все сообщения будут записаны корректно и без смешивания.

Особенности многопоточного логирования

  • Потокобезопасность: Использование мьютекса внутри логгера гарантирует, что одновременно будет выполняться только одна операция — либо запись сообщения, либо изменение полей логгера (например, смена выходного потока или формата лога).

  • Производительность: Несмотря на блокировку, логгер спроектирован так, чтобы минимизировать влияние на производительность. Однако при большом количестве логов или высокой нагрузке на систему возможны задержки.

  • Вывод в разные потоки: Логгер позволяет использовать различные выходные потоки для разных экземпляров, что может быть полезно для разделения логов по категориям или источникам.

Логирование в разные выходные потоки

Проект предоставляет гибкую возможность настройки выходного потока для логгера. Это означает, что вы можете направлять логи в любой поток, поддерживающий интерфейс std::ostream, будь то стандартный вывод (std::cout), файлы, строковые потоки (std::ostringstream) или даже пользовательские потоки.

Установка выходного потока

При создании экземпляра логгера вы можете указать, куда будут записываться логи. По умолчанию, логи направляются в std::cout, но это поведение можно изменить:

Logger::Logger log("FileLogger", std::ofstream("log.txt"));

В этом примере логи будут записываться в файл log.txt.

Смена выходного потока

Вы также можете изменить выходной поток логгера в процессе работы программы с помощью метода setOutStream:

Logger::Logger log("Logger");
log.setOutStream(std::cerr);

Пример использования с различными потоками вывода

std::ofstream file("output.log");
std::ostringstream oss;

Logger::Logger logToFile("FileLogger", file);
Logger::Logger logToStringStream("StringStreamLogger", oss);
Logger::Logger logToConsole("ConsoleLogger");

logInfo(logToFile, "This log goes to a file");
logWarn(logToStringStream, "This log goes to a string stream");
logError(logToConsole, "This log goes to the console");

file.close();

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

© Habrahabr.ru