...

среда, 26 октября 2016 г.

[Из песочницы] Сравнение библиотек логирования

В сети огромное количество площадок формата Q&A где задаются вопросы из разряда:

  • Предложите С++ логгер? (C++ logging framework suggestions)
  • Какой наиболее эффективный потоко-безопасный С++ логгер? (What is the most efficient thread-safe C++ logger)
  • Библиотека логирования для игр (Logging library for c games)
  • Асинхронный потоко-безопасный С++ логгер? (Asynchronous thread-safe logging in C++)

Люди делятся своим опытом и знаниями, но формат таких площадок позволяет лишь показать личные предпочтения отвечающего. К примеру, одним из самых производительных логгеров чаще всего называют Pantheios, который даже по тестам производителя тратит больше 100 секунд на запись 1M строк лога, на современном железе это около 30 секунд, быстро ли это?

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

Мотивация


Почти в каждом известном мне проекте рано или поздно появлялось логирование и инженеры спрашивали себя «а как решить эту задачу?», кто-то рылся на площадках Q&A и получал ответы «Мне подошел логгер X, вроде полет нормальный» (1), кто-то писал свой логгер (2), а кто-то запасался терпением и штудировал целый пучок логгеров на предмет своих интересов и спустя неделю другую делал свой выбор (3).

Эта статья для всех 3х групп:

  1. Для первой группы эта статья даст более обширное сравнение логгеров, чем рекомендация «логгер Х для меня лучший»
  2. Для второй группы статья даст представление о текущем уровне технологий и возможно склонит чашу весов в сторону «проще использовать готовый» или «ого, работы много, но я смогу лучше» и кто знает, может через год другой мы увидим прорыв в этой области.
  3. Для третьей и самой педантичной группы я надеюсь, эта статья сохранит как минимум одну из 2х недель изысканий, в масштабах всей индустрии это может быть внушительное количество человеко-часов

N.B. Статья достаточно объемная, поэтому если решитесь на чтение, пожалуйста, запаситесь терпением!

логгеры и их основные параметры


Выбор логгеров для сравнения дело хлопотное и не простое, в любом случае возникнут вопросы «А почему логгер Х не был рассмотрен?» Что тут можно сказать, логика была проста – взять 3 известных логгера и 4 сравнительно юных и «голодных».

Но даже сравнение этих 7 кандидатов заняло более 2х недель выкуривания доков, issues, чтения форумов, написания тестов и сбора результатов.

Так или иначе, если какой-то очень важный логгер был пропущен (boost к примеру) – статью можно обновить. В обзор попали:

  1. Pantheios
  2. Glog
  3. log4cpp
  4. P7
  5. G3log
  6. Spdlog
  7. Easylogging

Общие характеристики выбранных логгеров
Лиц. Языки Обнов. Платф. Комп.
Pantheios BSD C++ 2010 Windows, *nix, OS-X VC++, GCC, Intel, Borland, Comeau,Digital Mars,Metrowerks
Glog Неизвестна С++ 2016 Windows, *nix, QNX VC++, GCC, clang, intel
log4cpp LGPL С++ 2016 Windows, *nix, Solaris VC++, GCC, Sun CC, OpenVMS
P7 LGPL С++, С, C#, Python 2016 Windows, *nix VC++, GCC, clang
G3log Public Domain C++11 2016 Windows, *nix VC++, GCC, clang
Spdlog MIT C++11 2016 Windows, Linux, Solaris, OS-X, Android VC++, GCC, Clang
Easylogging MIT C++11 2016 Windows, Linux, Solaris, OS-X, Android, RaspberryPi VC++, GCC, Clang, Intel

Документация и зависимости


Трудно оспаривать важность документации для сложных проектов, современные логгеры простыми проектами назвать можно с большой натяжкой и наличие хорошей документации порой существенно ускоряет внедрение и исправление ошибок:
Документация Зависимости
Pantheios Полная (API + использование) STLSoft
Glog Рудиментарная, почти отсутствует Google gflags, слабая зависимость (1)
log4cpp Генерируемая (Doxygen) (API только) Boost, слабая зависимость (1)
P7 Полная (API + использование) Нет
G3log Базовая (общие методы использования) Нет
Spdlog Базовая (общие методы использования) Нет, только заголовочный файл (2)
Easylogging Базовая (общие методы использования) Нет, только заголовочный файл (2)

  1. Слабая зависимость – часть кода зависит от сторонних решений, но не препятствует компиляции, а лишь частично ограничивает функционал.
  2. Только заголовочный файл – библиотека распространяется в виде одного или нескольких заголовочных файлов, которые необходимо включать в каждый исходный файл Вашей программы, в случае Easylogging существенно снижается скорость компиляции. Но из этой ситуации есть выход – компилировать эти проекты в виде библиотеки и подключать уже ее, правда это потребует дополнительного времени на создание проекта.

Тип логгера, контроль потребления памяти и потокобезопасность


На данный момент широко распространены 2 подхода в логировании:
  • Синхронный – вызов Log(..) функции и запись в файл происходят синхронно из одного потока
  • Асинхронный – вызов Log(..) функции лишь обновляет очередь сообщений, а другой поток занимается записью, таким образом, уменьшая время вызова Log(..) функции из пользовательского потока, и как следствие достигается максимальная производительность пользовательского потока и минимизируются задержки на вызов Log(..) функции.

Правда есть нюансы понимания асинхронности разными производителями библиотек логирования.
  1. Тип №1: Одни считают, что вызов Log(..) функции должен быть атомарным и таким образом порядок лог сообщений в файле будет последовательным во времени 00:00 → 00:01 → 00:02 и тд.
  2. Тип №2: Другие считают, что в целях достижения максимальной производительности можно пожертвовать атомарностью вызова Log(..) функции и смириться с тем, что лог сообщения в файле будут перемежающимися, например вот так 00:00 –> 00:05 -> 00:01.

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

Другим важным аспектом асинхронного логирования является контроль за выделением памяти, так как, чтоб ваш логгер был асинхронен — вы должны сохранять данные в буфера, а писать уже из другого потока. И вот тут кроется важная мелочь — какой размер буферов будет оптимален и может ли пользователь влиять на этот параметр? Вопрос совсем не праздный, так как некоторые из протестированных логгеров выделяли сотни мегабайт под их нужды.

Тип Контроль памяти Потоко-безопасность
Pantheios Синхонный нет да
Glog Синхонный нет да
log4cpp Синхонный нет да
P7 Асинхронный, тип 1 (2) точное (с шагом 1Kb) да
G3log Асинхронный, тип 2 (3) нет (5) да
Spdlog Асинхронный, тип 2 (3) частичное (6) да
Easylogging Синхонный (1) нет нет (4)

  1. Асинхронный режим находится в экспериментальном состоянии
  2. Временные метки и сообщения не перемешаны
  3. Временные метки и сообщения могут быть перемешаны
  4. По умолчанию не доступно, необходимо активировать макросом ELPP_THREAD_SAFE
  5. Неконтролируемое выделение памяти, при высоких нагрузках может выделять сотни мегабайт, комментарий автора: http://ift.tt/2eLRBxI
    In the case of g2log or g3log a std::queue is used, internally that is a std::deque. It’s unbounded but much more memory tolerant than a std::vector. Internally the queue is wrapped inside the shared_queue.hpp.

  6. Можно задавать длину очереди в элементах, размер элемента в начальном виде – 88 байт + текстовое сообщение (30-160 байт). Автор рекомендует задавать размер очереди в 1 миллион сообщений для оптимальной производительности, что выливается в расходы памяти от 120 мегабайт до 250 мегабайт только на библиотеку логирования.

Обработка сбоев процесса


Правильная обработка сбоев процесса (crash handling) в первую очередь важна для асинхронных логгеров, т.к. часть данных хранится в буферах и если их вовремя не сохранить, то возможно самые ценные данные прямо перед сбоем будут потеряны.

Распространены 3 подхода в перехвате падений:

  • Автоматический, библиотека сама настраивает все векторы и сделает все сама, большим минусом такого решения является скудность перехватываемых сигналов, а так же помехи для приложения, которое возможно хотело бы само обрабатывать падение в целях сохранения crash dump файла или сброса буферов.
  • Ручной – библиотека предоставляет примитивы для перехвата падений и сброса буферов, а приложение уже само решает, когда и как установить перехватчик и что делать в случае падения.
  • Пусть падает, дело житейское

Pantheios Нет
Glog автоматический, только под Linux (1)
log4cpp Нет
P7 ручной (2)
G3log автоматический, только под Linux (3)
Spdlog Нет (4)
Easylogging автоматический, только под Linux (5)

  1. Перехватывается следующие сигналы: SIGSEGV, SIGILL, SIGFPE, SIGABRT, SIGBUS, SIGTERM.
  2. Перехватывается следующие сигналы: SIGSEGV, SIGILL, SIGFPE, SIGINT, SIGABRT, SIGBUS, SIGTERM, SIGBUS, PureVirtualCall, VectoredException, Newhandler, InvalidParameterHandler, status_access_, exception_array_bounds_exceeded, exception_datatype_misalignment, exception_flt_divide_by_zero, exception_flt_stack_check, exception_illegal_instruction, exception_int_divide_by_zero, exception_noncontinuable_exception, exception_priv_instruction, exception_stack_overflow
  3. Перехватывается следующие сигналы: SIGSEGV, SIGILL, SIGFPE, SIGABRT, SIGBUS, SIGTERM, Div by zero, illegal printf, out of bounds, access violation, std::future_error
  4. http://ift.tt/2eLRKRG — Дефект был «закрыт» в 2015, т.е. работ не предвидится по этому направлению.
  5. Перехватывается следующие сигналы: SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGINT

Стиль логирования и вывод (sink)


Основная масса библиотек поддерживает 2 хорошо зарекомендовавших себя стиля логирования:
  • Функции со списком переменных аргументов (prinf стиль)
  • Перегрузка оператора “<<”

Стиль Вывод (Sink)
Pantheios Template + перегруженные функции
F(A), F(A,A), F(A,A,A), … F(A, <-64->, A)
Printf
File, syslog, console, speech, ACE, COMerror, WinEventLog
Glog Log() << Message File, syslog, console
log4cpp Printf, Log() << Message File, syslog, console, NT log, IDS/A, OsStream, StringQueue, Win32Debug
P7 Printf File, network (собств. протокол и сервер(2)), null
G3log Printf, Log() << Message File (3)
Spdlog Printf File, syslog, console
Easylogging Printf (1), Log() << Message File, syslog, console

  1. В случае использования «Printf» генерировал exception, вероятно это временная проблема.
  2. Свой сервер, используется для достижения максимальной производительности. Сервер бесплатен, но к сожалению поддерживает только Windows, судя по всему основан на Qt, запрос об поддержке Linux был направлен автору. Скорость отправки логов по сети в тестовой конфигурации была около 3.5 миллионов в секунду при загрузке CPU – 13%. Подробно тесты производительности обсуждаются в следующих главах.
  3. В официальную поставку не входит Sink с поддержкой ротации файлов и консоль, но эти расширения можно скачать http://ift.tt/2eLRClg

Инициализация логгера


Инициализация или передача параметров достаточно важный пункт т.к. добавляет гибкости логгеру и избавляет от необходимости перекомпиляции, если Вы решили изменить уровень логирования к примеру.
Pantheios Ручная (только в коде)
Glog Командная строка, ручная, переменные среды окружения
log4cpp Конфигурационный файл (1), ручная
P7 Командная строка (2), ручная
G3log Ручная (только в коде)
Spdlog Ручная (только в коде)
Easylogging Конфигурационный файл, командная строка, ручная

  1. Подробная и хорошо организованная настройка параметров логгера, пожалуй, самая развернутая из всех.
  2. Во всех остальных логгерах для того чтоб параметры командной строки были обработаны – вы должны передать их в логгер руками из int main(int argc, char* argv[]) функции. В данном логгере эти параметры могут быть перехвачены автоматически из любой части программы/модуля (dll,so).

Настройка фильтрации


Самая распространенная методика фильтрации – по уровням логирования, скажем если фильтр установлен на ERROR уровень — то все что меньше ERROR (TRACE, DEBUG, INFO, WARNING …) в лог попадать не будет. Этот метод очень удобен для отсеивания большого количества ненужной в данный момент информации и сохранения CPU и места на диске.
Pantheios Нет (1)
Glog Командная строка, ручная, переменные среды окружения
log4cpp Конфигурационный файл (4), ручная
P7 Командная строка, удаленно по сети в режиме реального времени (2) (3), ручная
G3log Нет (5)
Spdlog Ручная
Easylogging Ручная (6)

  1. Для организации фильтрации нужно разработать свой FrontEnd
  2. Поддерживается только если данные высылаются по сети, в случае записи в локальный файл сервер не имеет доступа к Verbosity level
  3. В дополнение к глобальному уровню можно устанавливать уровни для каждого модуля.
  4. Иерархические логирование и установка уровней индивидуально для каждого логгера
  5. По умолнчанию отключена, включается макросом G3_DYNAMIC_LOGGING, после этого можно в ручном режиме задать уровень на все логгеры. Существенно снижает производительность.
  6. Поддержка заявлена производителем, но заставить ее работать не удалось, во время использования сложилось впечатление, что функция находится в стадии разработки или заброшена.

Поддержка юникода


Эта часть тестирования была одной из самых грустных, в 2016 году поддержка юникода в таких известных библиотеках все еще находится на уровне «not officially».

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

Pantheios Utf-16 (1)(4), Utf-8
Glog Нет
log4cpp Нет
P7 Windows — Utf-16, *nix — Utf-8
G3log Нет
Spdlog Нет
Easylogging Windows Utf-16 (2), Utf-8 (3)

  1. Почти идеально, за исключением того что итоговый лог файл не имеет маркера юникода и кодировку в программе просмотра нужно будет выбирать самому.
  2. Поддержка заявлена, но не реализована, символы юникода в лог файл не попадают.
  3. Макрос START_EASYLOGGINGPP не поддерживает юникод
  4. В одном сообщении нельзя совместить ANSI строку скажем с UTF-16

Доступ к логгеру


В современных библиотеках вопрос «кто владеет логгером» остается за кадром, чаще всего можно написать LOG(ERROR) << “My message” и библиотека позаботиться обо всем сама. Такая простота достигается с помощью глобальных переменных. Этичность использования глобальных переменных я оставлю за кадром, все таки это особый случай, но простота использования глобальной переменной в случае простого приложения оборачивается против разработчика сложного приложения состоящего из многих динамических или статических модулей.

Другой вариант получения доступа к логгеру это самостоятельно создать объект и контролировать его жизненный цикл.

И последний вариант – гибридный, объекты логгера создаются в ручном режиме, а затем используется глобальные переменные (registry) или разделяемая память, общая для всего процесса включая динамические модули.

Pantheios Глобальные переменные, автоматическая инициализация
Glog Глобальные переменные, автоматическая инициализация
log4cpp Глобальные переменные, автоматическая и ручная инициализация
P7 Общая память, ручная инициализация
G3log Глобальные переменные, автоматическая и ручная инициализация
Spdlog Глобальные переменные, ручная инициализация
Easylogging Глобальные переменные, автоматическая инициализация

Ротация файлов


Pantheios Нет
Glog Размер
log4cpp Размер (2)
P7 Время, размер (1) (2)
G3log Размер, по умолчанию не доступен (1)
Spdlog Размер, время(дневной) (1)
Easylogging Размер

  1. Каждый файл в названии содержит дату и время
  2. Поддерживается опция «макс. кол-во файлов» позволяющая хранить только N последних файлов

Точность времени


Многие из рассматриваемых в данной статье логгеров разрабатывались с прицелом на высокую производительность, с потенциалом в миллионы сообщений в секунду. Но помимо высоких скоростей нужны точные временные метки высокого разрешения, т.к. если у вас в лог файле есть пара десятков или даже сотен сообщений с одинаковой временной меткой – это означает, что часть информации о времени исполнения уже утеряна.
Pantheios Windows: 10ms, custom back-end может помочь увеличить точность
Linux: теор. минимальное значение 1ns, зависит от аппаратной части
Glog Windows: 10ms
Linux: теор. минимальное значение 1ns, зависит от аппаратной части
log4cpp Windows: 10ms
Linux: теор. минимальное значение 1ns, зависит от аппаратной части
P7 Windows: 100ns
Linux: теор. минимальное значение 1ns, зависит от аппаратной части
G3log Windows: 1ms
Linux: 1us
Spdlog Windows: 1ms
Linux: теор. минимальное значение 1ns, зависит от аппаратной части
Easylogging Windows: 1ms
Linux: 1us

Производительность


Очень многие логгеры из приведенного в данной статье списка заявляют, что одним из главных приоритетов для них является производительность.

Я отнесся к этому заявлению более чем серьезно и провел ряд тестов:

  • в конфигурации по умолчанию
  • в условиях равного использования памяти
  • в режиме одного потока
  • в режиме много-поточности

Для каждого теста делается замер времени и CPU потраченного логгером на сохранение 1 миллиона сообщений в файл. Проводятся 3 замера и вычисляются средние показатели.

Так же проводились тесты в debug (оптимизация отключена) и release (оптимизация O2) сборке. Для тестов использовалась следующая конфигурация:

  • Window 7x64 (6.1.7601 Service Pack 1 Build 7601)
  • Visual studio 2015, update 2
  • RAM: 16Gb (DDR3-1600 / PC3-12800)
  • CPU: Intel Core i7-870
  • HDD: Samsung EVO SSD 850 256GB (SATA3)

В целях приблизить тесты к реальному использованию следующая информация сохранялась для каждого лог сообщения:
  • Имя исходного файла
  • Номер строки кода
  • Имя исходной функции
  • Имя логгера/модуля
  • Уровень (error, warning, …)
  • Время
  • ID текущего потока (thread Id)
  • Номер ядра CPU
  • Текстовое сообщение

Код который исполнялся для каждого логгера (для компиляции требуется поддержка С++11):
Исходный текст
#include <stdio.h>
#include <atomic>
#include <thread>
#include <vector>

//Include specific logger headers
#include "Logger headers ..."
 
 
using namespace std;
using namespace std::chrono;
 
//Use this macro to switch on multi-threading mode
//#define MULTI_THREAD
 
 
int main(int argc, char* argv[])
{
    //Logger initialization
    //..
  
    unsigned int thread_count = 4;
    unsigned int howmany      = 1'000'000;
    vector<thread> threads;
    auto start = system_clock::now();
 
 
#if !defined(MULTI_THREAD)
    for(unsigned int i=0; i < howmany; i++)
    {
        //Has to be customized for every logger
        LOG(INFO) << " Message + all required information, #" << i;
    }
#else
    howmany /= thread_count;
    for (int t = 0; t < thread_count; ++t)
    {
        threads.push_back(std::thread([&]
        {
            for(unsigned int i=0; i < howmany; i++)
            {
                //Has to be customized for every logger
                LOG(INFO) << " Message + all required information, #" << i;
            }
        }));
    }
 
 
    for(auto &t:threads)
    {
        t.join();
    };
 
    howmany *= thread_count;

#endif
 
    auto delta = system_clock::now() - start;
    auto delta_d = duration_cast<duration<double>> (delta).count();
 
    LOG(INFO) << "Time = " << (double)howmany / delta_d << " per second, total time = "  << delta_d;

    //Logger uninitialization if necessary 
 
    return 0;
}



Один поток


Один поток должен сохранить 1 миллион сообщений в файл, фильтрация отключена, ротация файлов отключена. Измеряется время исполнения и среднее использование CPU.
Debug
Time (ms)
Debug
CPU (%)
Release
Time (ms)
Release
CPU (%)
Pantheios 140 300 13% 28 400 13%
Glog 52 500 13% 8 270 13%
log4cpp 130 570 13% 13 806 13%
P7 (1)(2) 520 14% 100 14%
G3log (1) (3) 102 990 38% 3 660 37%
Spdlog (1) (4) 64 250 13% 869 13%
Spdlog (1) (5) 65 660 13% 885 13%
Easylogging 271 060 13% 9 100 13%

  1. Асинхонное логирование
  2. Скомпилирован с опцией «/P7.Pool=1024» — общий объем доступной памяти 1 мегабайт.
  3. Замеры можно считать синтетическими, так как большую часть времени логгер складывает данные в буфера, а запись происходит по выходу из приложения и эта работа занимает время превышающее время логирования на порядок, 1 секунда логирования и 10 секунд сохранения данных.
  4. Логирование в условиях рекомендованных производителем «spdlog::set_async_mode(1048576)» при этом логгер потребляет около 250 мегабайт памяти
  5. Логирование в условиях равного потребления памяти «spdlog::set_async_mode(4096)» — в этом случае у логгера выделен буфер из 4k элементов, каждый элемент занимает около 250 байт что в итоге дает потребление памяти около 1 мегабайта.

4 потока


4 потока должны суммарно сохранить 1 миллион сообщений в файл, фильтрация отключена, ротация файлов отключена.

Измеряется время исполнения и среднее использование CPU.

Debug
Time (ms)
Debug
CPU (%)
Release
Time (ms)
Release
CPU (%)
Pantheios 10 600 48% 9 500 48%
Glog 30 200 93% 5 900 93%
log4cpp 149 600 18% 16 900 19%
P7 (1)(2) 790 19% 230 19%
G3log (1)(3) 39 700 75% 2 300 75%
Spdlog (1)(4) 11 510 13% 270 25%
Spdlog (1)(5) 73 240 25% 4 653 25%
Easylogging 328 230 19% 8 575 25%

  1. Асинхонное логирование
  2. Скомпилирован с опцией «/P7.Pool=1024» — общий объем доступной памяти 1 мегабайт.
  3. Замеры можно считать синтетическими, так как большую часть времени логгер складывает данные в буфера, а запись происходит по выходу из приложения и эта работа занимает время превышающее время логирования на порядок, 1 секунда логирования и 10 секунд сохранения данных.
  4. Логирование в условиях рекомендованных производителем «spdlog::set_async_mode(1048576)» при этом логгер потребляет около 250 мегабайт памяти
  5. Логирование в условиях равного потребления памяти «spdlog::set_async_mode(4096)» — в этом случае у логгера выделен буфер из 4k элементов, каждый элемент занимает около 250 байт что в итоге дает потребление памяти около 1 мегабайта.

Фильтрация


логгер должен обработать 1 миллион сообщений и отфильтровать их, т.е. в итоговый файл не попадет ни 1 сообщения.

Измеряется время исполнения.

Debug
1 thread, time (ms)
Debug
4 threads, time (ms)
Release
1 thread, time (ms)
Release
4 threads, time (ms)
Pantheios (1) - - - -
Glog 55 520 28 240 6 840 4 790
log4cpp 200 70 80 45
P7 84 102 23 42
G3log 5 530 1950 24 9
Spdlog 269 134 6 32
Easylogging (2) - - - -

  1. Фильтрация не доступна по умолчанию
  2. Не получилось заставить работать фильтрацию

Обзор производительности


Производительность многих логгеров оказалась на очень хорошем уровне.
К сожалению, почти у всех логгеров кроме P7 наблюдается колоссальный разрыв производительности между debug и release сборкой, порой коэффициент достигает 74 (Spdlog: 65660 / 885). Это может усложнить отладку проектов в силу возросших задержек при логировании.

Произведенные тесты в определенном смысле можно назвать синтетическими, так как ни 1 разработчик, внедряющий в свое приложение библиотеку логирования, не желает, чтоб та выделяла под свои нужды 250 мегабайт памяти или потребляла 75% CPU или больше.

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

Поэтому я сделал пересчет лучших показателей каждого логгера (тесты с равным потреблением памяти) с целью определить, сколько может быть записано лог сообщений, используя только 1% CPU и разумный, но все еще большой объем памяти равный 1mb

Формула расчёта:

((1 000 ms / время теста в ms) * 1 000 000 сообщений) / использование СPU в тесте

Количество сообщений в сек при использовании 1% CPU
P7 714 285 сообщений (1000000 * (1000 / 100 ms) / 14%)
Spdlog 148 148 сообщений (1000000 * (1000 / 270 ms) / 25%)
Glog 9 301 сообщений (1000000 * (1000 / 8270 ms) / 13%)
Easylogging 8 453 сообщений (1000000 * (1000 / 9100 ms) / 13%)
G3log 7 384 сообщений (1000000 * (1000 / 3660 ms) / 37%)
log4cpp 5 571 сообщений (1000000 * (1000 / 13806 ms) / 13%)
Pantheios 2 708 сообщений (1000000 * (1000 / 28400 ms) / 13%)

Выводы


Pantheios


Эта библиотека произвела достаточно смешанные впечатления, с одной стороны к проекту автор подошел основательно и вдумчиво, хорошие обзоры функционала, документация, с другой стороны низкая производительность (хотя автор отмечает обратное (1)), отсутствие ротации файлов и прочих мелочей сильно портят общее впечатление.

Итак, плюсы библиотеки:

  • Type-safe вызовы основанные на шаблонах
  • Хорошая и полная документация
  • Один из немногих логгеров, что поддерживает юникод, правда с небольшими ограничениями
  • Низкое потребление памяти
  • Большое количество поддерживаемых Sink
  • Большое количество поддерживаемых компиляторов

Минусы:
  • Разработка судя по всему остановлена
  • Статическое связывание на этапе компиляции логгера и sink (file, network, etc.)
  • Невероятно долгая компиляция даже на мощных компьютерах и как опосредованный результат – размер бинарных файлов
  • Самая низкая производительность из всех рассмотренных логгеров
  • Конфигурация логгера только в коде (нет поддержки конфигурационных файлов, командной строки …)
  • Нет поддержки ротации файлов
  • Синхронное исполнение, т.е. все задержки Sink (запись в файл например) отразятся на скорости исполнения Вашего кода.
  • Нет возможности комбинировать юникод и ANSI строки внутри одного сообщения
  • Высокий порог вхождения (достаточно сложна в изучении и запутанна)

  1. It's incredibly efficient, and is faster than all other serious C++ diagnostic logging libraries by a huge margin (up to two orders of magnitude) http://ift.tt/2eLTVVf

N.B.: Библиотека одна из самых больших и сложных из всех сравниваемых, поэтому высока вероятность, что многие ее возможности не были рассмотрены.

Glog


Несмотря на то, что библиотека достаточно бедна функционалом и не блещет производительностью, зато эта библиотека вдохновила ряд других проектов, которые переросли своего «отца» считай на голову. Только это уже является жирным плюсом в карму авторам.

Плюсы библиотеки:

  • Простая в понимании и обслуживании библиотека
  • Поддержка условного логирования (макросы)
  • Поддержка сбоев процесса
  • Возможность конфигурации через командную строку
  • Приемлемая производительность
  • Низкое потребление памяти

Минусы:
  • Очень слабая документация
  • Слабая поддержка сбоев процесса – ограниченное количество сигналов, только Linux
  • Высокие накладные расходы при фильтрации сообщений
  • Многократный разрыв (до 9 раз) в производительности Debug и Release кода
  • Синхронное исполнение, т.е. все задержки Sink (запись в файл например) отразятся на скорости исполнения Вашего кода.
  • Активная разработка приостановлена
  • Нет поддержки юникода
  • Не известна лицензия проекта
  • Точность временных меток недостаточна
  • Высочайшее потребление CPU в тестах на много поточность при очень скромном выигрыше в производительности логгера по сравнению с 1 потоком

log4cpp


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

Плюсы библиотеки:

  • Генерируемая документация
  • Большое количество поддерживаемых Sink
  • Низкое потребление памяти
  • Поддержка конфигурационных файлов
  • Хорошая эффективность фильтрации сообщений

Минусы:
  • Синхронное исполнение, т.е. все задержки Sink (запись в файл например) отразятся на скорости исполнения Вашего кода.
  • Нет поддержки юникода
  • Многократный разрыв (до 10 раз) в производительности Debug и Release кода
  • Низкая производительность (предпоследнее место)
  • Размер строки не должен превышать 1024 символа – иначе ассерт
  • Если путь к лог файлам не существует – генерируется exception

P7


Один из самых необычных логгеров среди рассмотренных в данной статье, в комплект поставки входит не только логгер, но и сервер для приема сообщений по сети, просмотра лог файлов, фильтрации и экспорта. Как и в случае со SpdLog прицел был на производительность и возможность использовать на встраиваемых устройствах, так как проект заточен на сеть и точное управление памятью.
Стоит отметить, что проект использует в качестве лог файлов бинарный формат и для просмотра/конвертации требуется бесплатный софт.
Такой
image

Плюсы библиотеки:
  • Полная документация
  • Высокая производительность + высокая точность временных меток, большой отрыв от ближайшего конкурента SpdLog
  • Поддержка юникода
  • Полный контроль над потреблением памяти
  • Асинхронный – вызов Log функции независим от записи данных, таким образом нивелируются задержки на вызов функции.
  • Использование Shared memory (вместо «глобальных» переменных) для доступа к логгерам и Sink
  • В комплект входят обертки для C, C#, Python
  • Помимо логов библиотека поддерживает запись и мониторинг в реальном времени телеметрии.
    Так
    image
  • Возможность управлять удаленно (по сети) уровнем логирования на каждом устройстве, процессе или модуле, включать/выключать счетчики телеметрии
  • Не требователен к процессору
  • Доступен для нескольких языков и если разные части приложения написаны на C#, C++, C все они могут использовать один логгер

Минусы:
  • Сложность в написании custom Sink
  • Высоко интенсивное использование логгера из нескольких потоков снижает (в 2.3 раза) производительность логгера (плата за последовательность лог сообщений и временных меток)
  • Лог файл имеет бинарный формат, требуется специальный софт для просмотра или конвертации в текстовую форму (формат файла открытый)
  • Нет поддержки SysLog, на замену ему предлагается другой сетевой протокол с возможностью обратной связи
  • Нет автоматической обработки сбоев процесса – оставлено на интегратора, есть функция по сбросу буферов

G3log


Наследник G2Log который в свою очередь был результатом переосмысления Glog. Автор преследовал в первую очередь производительность и ведет достаточно активную просветительскую работу на этот счет (1)(2).

Плюсы библиотеки:

  • Хорошая скорость фильтрации
  • Обработка сбоев процесса (генерация stack trace при наличии информации)
  • В целом удовлетворительная документация
  • Асинхронный – вызов Log функции независим от записи данных, таким образом нивелируются задержки на вызов функции.

Минусы:
  • Нет поддержки юникода
  • Слабая производительность, при этом высокое потребление ресурсов CPU
  • Замеры производительности можно считать синтетическими, так как большую часть времени логгер складывает данные в буфера, а запись происходит по выходу из приложения и эта работа занимает время превышающее время логирования на порядок
  • Полная асинхронность – временные метки и сообщения могут быть перемешаны группами или по одному при интенсивном логировании
  • Неконтролируемое выделение памяти достигающие сотен мегабайт иногда гигабайт при интенсивном логировании
  • Конфигурация логгера только посредством кода
  • Точность временных меток недостаточна
  • Многократный разрыв (до 30 раз) в производительности Debug и Release кода
  • Высокое потребление CPU
  • Компиляторы с поддержкой С++11 или выше

  1. http://ift.tt/2eLRBxI
  2. http://ift.tt/2eLVoLd

Spdlog


Еще один логгер написанный с прицелом на производительность и можно сказать, что автор в этом преуспел, единственный минус — потребление памяти. Функционал стандартен для многих других логгеров, основной упор – скорость.

Плюсы библиотеки:

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

Минусы:
  • Нет обработки сбоев процесса
  • Полная асинхронность – временные метки и сообщения могут быть перемешаны группами или по одному при интенсивном логировании в итоговом файле
  • Для достижения оптимальной производительности потребляет около 250-300 мегабайт оперативной памяти, при уменьшении объема памяти производительность снижается почти в 18 раз.
  • Нет поддержки юникода
  • Только заголовочные файлы, что я отношу к минусу, так как включение этих файлов в каждый файл Вашего проекта существенно замедляет компиляцию
  • Конфигурация логгера только в коде
  • Точность временных меток недостаточна, особенно в свете достигаемой производительности (3.7 миллиона сообщений в секунду при разрешении временных меток в 1ms)
  • Компиляторы с поддержкой С++11 или выше
  • Многократный разрыв (до 74 раз) в производительности Debug и Release кода

Easylogging


Логгер с прицелом на “light-weight”, единственный заголовочный файл (около 6700 строк кода). Функционал стандартен для многих других логгеров.

Плюсы библиотеки:

  • В целом удовлетворительная документация
  • Не требователен к процессору
  • Умеренное потребления памяти
  • Хороший набор вспомогательных макросов
  • Поддержка конфигурационных файлов, командной строки
  • Заявлен большое количество поддерживаемых платформ

Минусы:
  • Синхронное исполнение, т.е. все задержки Sink (запись в файл например) отразятся на скорости исполнения Вашего кода.
  • Низкая производительность
  • Не получилось завести фильтрацию, возможно опция находится в процессе разработки
  • Заявлена поддержка юникода, но по факту символы юникода не достигают файла и теряются по дороге
  • Только заголовочный файл, что я отношу к минусу, так как включение этого файла в каждый файл Вашего проекта существенно замедляет компиляцию
  • Точность временных меток недостаточна
  • Компиляторы с поддержкой С++11 или выше
  • Многократный разрыв (до 40 раз) в производительности Debug и Release кода
  • Необходимо включать потоко-безопасность специальным макросом (ELPP_THREAD_SAFE), по умолчанию отключено

Итог


Внимание!
Субъективное мнение автора.
  • Если Вам нужен заслуженный логгер без повышенных требований к производительности, но гибкий, с иерархической системой фильтрации – выбирайте «log4cpp» — это рабочая лошадка многих проектов
  • Если Вам нужна экстремальная производительность, точный контроль памяти, удаленное управление – выбирайте P7, у Вас будет мощный инструмент мониторинга вашего софта даже на очень скромном железе, по принципу – пишем все, а разберемся потом
  • Синтетические тесты производителей G3Log, SpdLog совершенно не позволяют мне их рекомендовать, особенно в свете потребления памяти и процессора, возникает вопрос – где еще меня пытались очаровать рекламными заявлениями которые верны только если читать мелкий шрифт
  • Easylogging произвел впечатление развивающегося проекта в котором многие функции еще недостаточно отполированы, может в будущем это будет прекрасный логгер
  • Glog — проект имел очень хороший старт, но к сожалению так и не вышел на марафонскую дистанцию, зато дал заряд идей и бодрости другим проектам
  • Pantheios — добротный логгер, правда с некоторыми упущениями в функционале. Из-за очень низкой производительности применение ограничено


Спасибо большое за внимание и Ваше время, надеюсь эта статья помогла Вам в составлении общего представления о реалиях современных логгеров.

Комментарии (0)

    Let's block ads! (Why?)

    Комментариев нет:

    Отправить комментарий