- PVSM.RU - https://www.pvsm.ru -
В сети огромное количество площадок формата Q&A где задаются вопросы из разряда:
Люди делятся своим опытом и знаниями, но формат таких площадок позволяет лишь показать личные предпочтения отвечающего. К примеру, одним из самых производительных логгеров чаще всего называют Pantheios, который даже по тестам производителя тратит больше 100 секунд на запись 1M строк лога, на современном железе это около 30 секунд, быстро ли это?
В этой статье я сравню наиболее известные и заслуженные логгеры последних лет и несколько относительно молодых логгеров по более чем 25 критериям.
Почти в каждом известном мне проекте рано или поздно появлялось логирование и инженеры спрашивали себя «а как решить эту задачу?», кто-то рылся на площадках Q&A и получал ответы «Мне подошел логгер X, вроде полет нормальный» (1), кто-то писал свой логгер (2), а кто-то запасался терпением и штудировал целый пучок логгеров на предмет своих интересов и спустя неделю другую делал свой выбор (3).
Эта статья для всех 3х групп:
N.B. Статья достаточно объемная, поэтому если решитесь на чтение, пожалуйста, запаситесь терпением!
Выбор логгеров для сравнения дело хлопотное и не простое, в любом случае возникнут вопросы «А почему логгер Х не был рассмотрен?» Что тут можно сказать, логика была проста – взять 3 известных логгера и 4 сравнительно юных и «голодных».
Но даже сравнение этих 7 кандидатов заняло более 2х недель выкуривания доков, issues, чтения форумов, написания тестов и сбора результатов.
Так или иначе, если какой-то очень важный логгер был пропущен (boost к примеру) – статью можно обновить. В обзор попали:
Общие характеристики выбранных логгеров
Лиц. | Языки | Обнов. | Платф. | Комп. | |
---|---|---|---|---|---|
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) |
На данный момент широко распространены 2 подхода в логировании:
Правда есть нюансы понимания асинхронности разными производителями библиотек логирования.
Лично я придерживаюсь точки зрения первой группы на асинхронное логирование, так как анализ перемешанных логов приятным назвать нельзя, особенно если это большой лог файл и перемешаны не единичные логи а группы логов по несколько сотен или тысяч элементов.
Другим важным аспектом асинхронного логирования является контроль за выделением памяти, так как, чтоб ваш логгер был асинхронен — вы должны сохранять данные в буфера, а писать уже из другого потока. И вот тут кроется важная мелочь — какой размер буферов будет оптимален и может ли пользователь влиять на этот параметр? Вопрос совсем не праздный, так как некоторые из протестированных логгеров выделяли сотни мегабайт под их нужды.
Тип | Контроль памяти | Потоко-безопасность | |
---|---|---|---|
Pantheios | Синхонный | нет | да |
Glog | Синхонный | нет | да |
log4cpp | Синхонный | нет | да |
P7 | Асинхронный, тип 1 (2) | точное (с шагом 1Kb) | да |
G3log | Асинхронный, тип 2 (3) | нет (5) | да |
Spdlog | Асинхронный, тип 2 (3) | частичное (6) | да |
Easylogging | Синхонный (1) | нет | нет (4) |
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.
Правильная обработка сбоев процесса (crash handling) в первую очередь важна для асинхронных логгеров, т.к. часть данных хранится в буферах и если их вовремя не сохранить, то возможно самые ценные данные прямо перед сбоем будут потеряны.
Распространены 3 подхода в перехвате падений:
Pantheios | Нет |
---|---|
Glog | автоматический, только под Linux (1) |
log4cpp | Нет |
P7 | ручной (2) |
G3log | автоматический, только под Linux (3) |
Spdlog | Нет (4) |
Easylogging | автоматический, только под Linux (5) |
Основная масса библиотек поддерживает 2 хорошо зарекомендовавших себя стиля логирования:
Стиль | Вывод (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 |
Инициализация или передача параметров достаточно важный пункт т.к. добавляет гибкости логгеру и избавляет от необходимости перекомпиляции, если Вы решили изменить уровень логирования к примеру.
Pantheios | Ручная (только в коде) |
---|---|
Glog | Командная строка, ручная, переменные среды окружения |
log4cpp | Конфигурационный файл (1), ручная |
P7 | Командная строка (2), ручная |
G3log | Ручная (только в коде) |
Spdlog | Ручная (только в коде) |
Easylogging | Конфигурационный файл, командная строка, ручная |
Самая распространенная методика фильтрации – по уровням логирования, скажем если фильтр установлен на ERROR уровень — то все что меньше ERROR (TRACE, DEBUG, INFO, WARNING …) в лог попадать не будет. Этот метод очень удобен для отсеивания большого количества ненужной в данный момент информации и сохранения CPU и места на диске.
Pantheios | Нет (1) |
---|---|
Glog | Командная строка, ручная, переменные среды окружения |
log4cpp | Конфигурационный файл (4), ручная |
P7 | Командная строка, удаленно по сети в режиме реального времени (2) (3), ручная |
G3log | Нет (5) |
Spdlog | Ручная |
Easylogging | Ручная (6) |
Эта часть тестирования была одной из самых грустных, в 2016 году поддержка юникода в таких известных библиотеках все еще находится на уровне «not officially [11]».
Библиотека нужна для того что сохранить важные данные приложения (фамилия пользователя, путь файла, имя домена), а большинство из существующих просто не позволят Вам это сделать если данные не укладываются в тривиальный 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) |
В современных библиотеках вопрос «кто владеет логгером» остается за кадром, чаще всего можно написать LOG(ERROR) << “My message” и библиотека позаботиться обо всем сама. Такая простота достигается с помощью глобальных переменных. Этичность использования глобальных переменных я оставлю за кадром, все таки это особый случай, но простота использования глобальной переменной в случае простого приложения оборачивается против разработчика сложного приложения состоящего из многих динамических или статических модулей.
Другой вариант получения доступа к логгеру это самостоятельно создать объект и контролировать его жизненный цикл.
И последний вариант – гибридный, объекты логгера создаются в ручном режиме, а затем используется глобальные переменные (registry) или разделяемая память, общая для всего процесса включая динамические модули.
Pantheios | Глобальные переменные, автоматическая инициализация |
---|---|
Glog | Глобальные переменные, автоматическая инициализация |
log4cpp | Глобальные переменные, автоматическая и ручная инициализация |
P7 | Общая память, ручная инициализация |
G3log | Глобальные переменные, автоматическая и ручная инициализация |
Spdlog | Глобальные переменные, ручная инициализация |
Easylogging | Глобальные переменные, автоматическая инициализация |
Pantheios | Нет |
---|---|
Glog | Размер |
log4cpp | Размер (2) |
P7 | Время, размер (1) (2) |
G3log | Размер, по умолчанию не доступен (1) |
Spdlog | Размер, время(дневной) (1) |
Easylogging | Размер |
Многие из рассматриваемых в данной статье логгеров разрабатывались с прицелом на высокую производительность, с потенциалом в миллионы сообщений в секунду. Но помимо высоких скоростей нужны точные временные метки высокого разрешения, т.к. если у вас в лог файле есть пара десятков или даже сотен сообщений с одинаковой временной меткой – это означает, что часть информации о времени исполнения уже утеряна.
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) сборке. Для тестов использовалась следующая конфигурация:
В целях приблизить тесты к реальному использованию следующая информация сохранялась для каждого лог сообщения:
Код который исполнялся для каждого логгера (для компиляции требуется поддержка С++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% |
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 миллион сообщений и отфильтровать их, т.е. в итоговый файл не попадет ни 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) | - | - | - | - |
Производительность многих логгеров оказалась на очень хорошем уровне.
К сожалению, почти у всех логгеров кроме 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%) |
Эта библиотека произвела достаточно смешанные впечатления, с одной стороны к проекту автор подошел основательно и вдумчиво, хорошие обзоры функционала, документация, с другой стороны низкая производительность (хотя автор отмечает обратное (1)), отсутствие ротации файлов и прочих мелочей сильно портят общее впечатление.
Итак, плюсы библиотеки:
Минусы:
N.B.: Библиотека одна из самых больших и сложных из всех сравниваемых, поэтому высока вероятность, что многие ее возможности не были рассмотрены.
Несмотря на то, что библиотека достаточно бедна функционалом и не блещет производительностью, зато эта библиотека вдохновила ряд других проектов, которые переросли своего «отца» считай на голову. Только это уже является жирным плюсом в карму авторам.
Плюсы библиотеки:
Минусы:
Еще один заслуженный логгер, произвел достаточно хорошее впечатление, никаких больших разочарований, никаких громких рекламных акций, никаких невыполненных обещаний.
Плюсы библиотеки:
Минусы:
Один из самых необычных логгеров среди рассмотренных в данной статье, в комплект поставки входит не только логгер, но и сервер для приема сообщений по сети, просмотра лог файлов, фильтрации и экспорта. Как и в случае со SpdLog прицел был на производительность и возможность использовать на встраиваемых устройствах, так как проект заточен на сеть и точное управление памятью.
Стоит отметить, что проект использует в качестве лог файлов бинарный формат и для просмотра/конвертации требуется бесплатный софт.
Плюсы библиотеки:
Минусы:
Наследник G2Log который в свою очередь был результатом переосмысления Glog. Автор преследовал в первую очередь производительность и ведет достаточно активную просветительскую работу на этот счет (1)(2).
Плюсы библиотеки:
Минусы:
Еще один логгер написанный с прицелом на производительность и можно сказать, что автор в этом преуспел, единственный минус — потребление памяти. Функционал стандартен для многих других логгеров, основной упор – скорость.
Плюсы библиотеки:
Минусы:
Логгер с прицелом на “light-weight”, единственный заголовочный файл (около 6700 строк кода). Функционал стандартен для многих других логгеров.
Плюсы библиотеки:
Минусы:
Внимание!
Спасибо большое за внимание и Ваше время, надеюсь эта статья помогла Вам в составлении общего представления о реалиях современных логгеров.
Автор: ostryh
Источник [14]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/c-3/203167
Ссылки в тексте:
[1] Pantheios: http://www.pantheios.org/
[2] Glog: https://github.com/google/glog
[3] log4cpp: http://log4cpp.sourceforge.net/
[4] P7: http://baical.net/p7.html
[5] G3log: https://github.com/KjellKod/g3log
[6] Spdlog: https://github.com/gabime/spdlog
[7] Easylogging: https://github.com/easylogging/easyloggingpp
[8] kjellkod.wordpress.com/2014/08/16/presenting-g3log-the-next-version-of-the-next-generation-of-loggers: https://kjellkod.wordpress.com/2014/08/16/presenting-g3log-the-next-version-of-the-next-generation-of-loggers/
[9] github.com/gabime/spdlog/issues/55: https://github.com/gabime/spdlog/issues/55
[10] github.com/KjellKod/g3sinks: https://github.com/KjellKod/g3sinks
[11] not officially: https://github.com/gabime/spdlog/issues/100
[12] www.pantheios.org/essentials.html: http://www.pantheios.org/essentials.html
[13] kjellkod.wordpress.com/2015/06/30/the-worlds-fastest-logger-vs-g3log: https://kjellkod.wordpress.com/2015/06/30/the-worlds-fastest-logger-vs-g3log/
[14] Источник: https://habrahabr.ru/post/313686/?utm_source=habrahabr&utm_medium=rss&utm_campaign=sandbox
Нажмите здесь для печати.