Знакомство с библиотекой логирования Apache log4cxx

    Чуть ранее мы рассмотрели библиотеку логирования Pantheios. Пришла очередь ознакомится с более известной Apache log4cxx. Библиотека является имплементаций принципов и механизмов из log4j (библиотека логирования Java) на языке C++. Проект выглядит «мертвым», по крайней мере круных изменений в течение последнего года не наблюдается, впрочем это не повод не посмотреть (а может быть и использовать) эту библиотеку.


    Общие замечания


    Я рассматриваю процесс сборки и работы с библиотекой на платформе Windows, используя VisualStudio 2010 SP1. Логи как обычно хочется иметь как на консоли, так и в файле. Особо стоит подчеркнуть что логи могут содержать симолы национальных алфавитов (читай unicode).

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

    Получение библиотеки




    Сборка


    Для начала нам надо скачать зависимости и собственно саму библиотеку. По хорошему, надо бы скачать её с SVN проекта, т.к. судя по коммитам исправлены баги, но я почему-то решил не рисковать и попытать счастья с стабильной версией 0.10.0.

    Итак, поехали!
    Качаем:
    исходники: www.apache.org/dyn/closer.cgi/logging/log4cxx/0.10.0/apache-log4cxx-0.10.0.tar.gz
    APR: apr.apache.org/download.cgi (качать надо APR 1.4.2, APR-util 1.3.10 , APR iconv 1.2.1)
    Sed: sourceforge.net/projects/gnuwin32/files//sed/4.2.1/sed-4.2.1-bin.zip/download

    и зависимости для Sed:
    sourceforge.net/projects/gnuwin32/files/libintl/0.14.4/libintl-0.14.4-bin.zip/download
    sourceforge.net/projects/gnuwin32/files/libiconv/1.9.2-1/libiconv-1.9.2-1-bin.zip/download
    sourceforge.net/projects/gnuwin32/files/regex/2.7/regex-2.7-bin.zip/download

    фуф, самое сложное позади…

    Распаковываем:
    • исходники в C:\temp\log4cxx_test\apache-log4cxx-0.10.0\
    • APR в C:\temp\log4cxx_test\apr\ (переименовать папку архивную не забудьте)
    • APR Util в C:\temp\log4cxx_test\apr-util\ (переименовать папку архивную не забудьте)
    • APR в C:\temp\log4cxx_test\apr-util\ (переименовать папку архивную не забудьте)


    Мне sed на машине не нужен как таковой, но он нужен для скрипта конфигурирования, его надо бы бросить сюда: C:\temp\log4cxx\apache-log4cxx-0.10.0\ и все dll файлы, от которых он зависит рядом положить. Эстеты могут бросить и sed и dll-ки в %SystemRoot%\System32\, если sed им в дальнейшем нужен.

    Далее: запускаем командную строку VS2010 и перейдя в каталог C:\temp\log4cxx\apache-log4cxx-0.10.0\ делаем последовательно:
    >configure
    >configure-aprutil


    Ошибок быть не должно.

    Настала очередь собственно сборки. Тут стоит запустить саму студию (devenv) и открыть в ней c:\temp\log4cxx\apache-log4cxx-0.10.0\projects\log4cxx.dsw. Студия попросит переконвертировать проекты, что нам и надо.

    Нажимаем build, но чай пить не идем. Процесс сборки достаточно быстро завершится ~300 ми ошибками. Ругаться будет на LOG4CXX_LIST_DEF макрос. Все такие макросы надо вынести перед классом (они объявлены внутри класса).

    После убирания этих ощибок будут ошибки, связанные с неизвестностью std::insert_iterator — просто добавьте #include <iterator> вначале файла.

    Далее появится ошибки об неопределенности «KeySet» — на все такие ошибки надо поменять (пример):
    LoggingEvent::KeySet set;
    на
    KeySet set;

    (т.к. мы вынесли макрос, формирующий эти самые KeySet вне классов).

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



    после чего и линковка заработает.

    Кратко об архитектуре


    log4cxx оперирует понятиями appender-ов, layout-ов и target-ами.

    appender — определяет набор параметров для получателя (target) потока сообщений (лог строк по сути), содержит в себе ссылку на layout, который в свою очередь определяет правила форматирования сообщения.

    Подробнее об архитектуре можно прочесть на сайте проекта.

    Тестируем работу


    Я предпочитаю затягивать в свои программы подобные фундаментальные библиотеки через переменные среды (но т.к. работаю с разными версиями библиотек стараюсь не определять их как переменные среды для пользователя). Поэтому запустив коммандную строку VS2010 вбиваем примерно следующее:
    >SET LOG4CXX=C:\temp\log4cxx\apache-log4cxx-0.10.0\src\main\include\
    >SET LOG4CXXLIB=C:\temp\log4cxx\apache-log4cxx-0.10.0\projects\Debug\
    >devnenv

    (я собирал в дебаг режиме, для release понятное дело пути немного иные).

    Далее создадим простой проект C++ Console Application — это и будет наш тестовый проект.
    В нём доопределим пути до общих include файлов и библиотек в настройке проекта, согласно нашим переменным среды:

    и для линковки:




    Пришла очередь добавить нужные нам include-ы:
    //apache log4cxx
    #pragma warning(push)
    #pragma warning(disable: 4231 4250)
    	//warning C4231: nonstandard extension used : 'extern' before template explicit instantiation	c:\libs\apache\apache-log4cxx-0.10.0\src\main\include\log4cxx\rolling\timebasedrollingpolicy.h	221	p2jbTestApp
    	//warning C4250: 'log4cxx::rolling::TimeBasedRollingPolicy' : inherits 'log4cxx::rolling::RollingPolicyBase::log4cxx::rolling::RollingPolicyBase::setOption' via dominance
    	#include <log4cxx/rolling/rollingfileappender.h>
    	#include <log4cxx/logger.h>
    	#include <log4cxx/consoleappender.h>
    	#include <log4cxx/logmanager.h>
    	#include <log4cxx/patternlayout.h>
    	#include <log4cxx/rolling/timebasedrollingpolicy.h>
    	#include <log4cxx/helpers/simpledateformat.h>
    	#include <log4cxx/helpers/stringhelper.h>
    	#include <log4cxx/xml/domconfigurator.h>
    #pragma warning(pop)
    


    Теперь надобно сделать конфигурационный файл. Я сделал его таким:
    <?xml version="1.0" encoding="UTF-8" ?>
    <!-- debug="true" -->
    <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" >
    
      <appender name="ConsoleAppender" class="org.apache.log4j.ConsoleAppender">
        <param name="Target" value="System.out"/>
        <layout class="org.apache.log4j.PatternLayout">
          <param name="ConversionPattern" value="%d{ABSOLUTE} [%t] %level %c{2}#%M %F:%L - %m%n"/>
        </layout>
      </appender>
    
    
      <appender name="DailyRollingFileAppender" class="org.apache.log4j.rolling.DailyRollingFileAppender">
        <layout class="org.apache.log4j.PatternLayout">
          <param name="ConversionPattern" value="%d{ABSOLUTE} [%t] %level %c{2}#%M %F:%L - %m%n"/>
        </layout>
        
        <param name="Encoding" value="UTF-16" />
        <param name="file" value="logfile.log"/>
        <param name="DatePattern" value="'.'yyyy-MM-dd" />
        <param name="append" value="true"/>
      </appender>
    
      <root>
        <priority value="all" />
        <appender-ref ref="DailyRollingFileAppender"/>
        <appender-ref ref="ConsoleAppender"/>
      </root>
    
    </log4j:configuration>
    


    Подробнее можно прочесть в документации к log4j, т.к. форматы файлов «почти совпадают».

    Ну и ниже тестовая программа:
    void foo(void*)
    {
    	log4cxx::LoggerPtr logger = log4cxx::Logger::getRootLogger();
    	for(int i=0;i<10;++i){
    		LOG4CXX_DEBUG((logger),  L"debug" << L"other debug message");
    		LOG4CXX_TRACE((logger),  L"trace");
    		LOG4CXX_INFO((logger),  L"привет, мир!");
    		LOG4CXX_WARN((logger),  L"WARN");
    		LOG4CXX_ERROR((logger),  L"error");
    		LOG4CXX_FATAL((logger),  L"FATAL");
    	}
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	setlocale(LC_ALL, "Russian_Russia.OCP");	//иначе русский не будет нормально работать
    
    	TCHAR selfName[MAX_PATH];
    	HMODULE hModule = GetModuleHandle(NULL);
    	GetModuleFileName(hModule, selfName, _countof(selfName));
    	std::wstring configFile(selfName);
    	configFile.append(L".logconfig");
    	log4cxx::xml::DOMConfigurator::configure(configFile);
    
    	for(int i=0;i<10;++i){
    		_beginthread(foo,0,NULL);
    	}
    
    	std::cin.get();
    
    	return 0;
    }
    


    Замечу «хитрость» использования:
    LOG4CXX_DEBUG((logger),  L"debug" << L"other debug message");
    

    из цикла «как это работает». Дело в том, что второй аргумент макроса передается на вход в stream, и именно поэтому сюда можно писать несколько сообщений (не только текст), используя operator <<.

    Заключение


    Мы посмотрели сборку и базовую настройку log4cxx на простом примере.
    Из плюсов библиотеки стоит выделить настраиваемость через конфигурационный файл, поддержку unicode «из коробки» (включая различные кодировки выходных файлов).

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

    Вне этого топика осталось: advanced конфигурирование, сравнение с другими логгерами, проверка «мифа о течах».

    Приятного логирования!

    Similar posts

    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 17

      +4
      А где же перечисление аппендеров? Описание тонкой настройки сортировки сообщений по источнику и приоритетам?
      Там как минимум, кроме консоли и файлов, есть еще syslog и mysql.
      Использую >2 лет, течей не наблюдал.
        0
        Ну так ведь базовые вещи описаны, типа сборки. Просто многие что пытаются использовать этот проект у себя наткнувшись на первую же проблему при сборке бросают эту затею («сроки горят»)… Быть может потом опишу библиотеку более подробнее, с написанием например своего appender-а.
        0
        До боли напоминает log4cplus… Они часом не родственники?
          +1
          еще есть log4cpp… Они все похожи, т.к. наследуют черты log4j, но родственниками вроде бы не являются… надо бы как-нибудь на досуге сравнить их все. Много хороших отзывов о Pantheios…
          0
          Использую log4perl — тот же аналог log4j но для perl'a.
          Очень удобно например менять appender без изменения кода.
          И MDC (Mapped Diagnostic Context) полезная вещь, с помощю которой можно добавлять дополнительную информацию в логи.
            +1
            Зря вы не упомянули о том, что конфигурировать аппендеры и порог вывода можно в конфиг-файле без пересборки программы. Это, как по мне, очень сильный плюс библиотеки.
              +3
              Чорт, я слепой. Всё-таки это неправильно, что нету Undo send для комментариев, хотя бы в течение минуты с момента отправки :(
              +1
              Для пользователей Qt есть порт: gitorious.org/log4qt
              В данный момент порт скорее жив, чем мертв.
                +1
                log4cxx — мертвый проект. Как очень давно то пытался его использовать. Емнип столкнулся с какими-то проблемами. Переход на log4cplus их решил. Переход на него занял очень мало времени.
                  0
                  Да, схожая ситуация была с XALAN (обработка XSLT). Проект жив, но автор похоже один и обещает следующий релиз уже года 3 (причем не пропадает, пишет иногда в рассылки, но в основном о том, что у него нет времени).

                  Теперь еще это. Не доверяю я апачевским библиотекам.
                  0
                  Эстеты могут бросить и sed и dll-ки в %SystemRoot%\System32\, если sed им в дальнейшем нужен.

                  Уж лучше бросить это в отдельную папку и прописать путь в %PATH%
                    0
                    Походу вся статья — это как сконфигурировать это.
                      0
                      Причем на комменты в предыдущей статье про Pantheios ответить, увы, некому… -> интересовало habrahabr.ru/blogs/cpp/117973/#comment_3844884, есть еще несколько похожих комментариев. Ни одного ответа… автор тупо постит черновики?
                        0
                        Поддерживаю… «рассматриваю процесс сборки и работы с библиотекой на платформе Windows, используя VisualStudio 2010 SP1» по сути только это и присутствует в топике. Напрашивается вопрос — кому это нужно?
                      0
                      > также поговаривают что библиотека течёт и не такая уж и быстрая.

                      log4cxx очень часто (относительно специализированных под приложение «костылей») вызывает printf (измерял callgrind'ом ), так что, порой, проще придумывать свой костыль поверх stringstreams и синглтонов. При запуске тестируемого приложения внутри ssh+screen скорость падает в десяток раз…

                      Плюс, сий логгер отвратителен при деинициализации — даже после тычка в LogManager он все равно выполняет в своих макросах свой код.
                        0
                        Если кому-то, вдруг, надо — отключение логгера в compile time:

                        #define LOG4CPLUS_DISABLE_INFO
                        #define LOG4CPLUS_DISABLE_WARN
                        #define LOG4CPLUS_DISABLE_DEBUG
                          0
                          Wait. Не то нагуглил… походу, для log4cxx надо определять свой макрос, вызывающий LOG4CXX_*, и уже его препроцессором отключать/включать. Иначе этот кошмар из приложения без тонн #ifdef на каждой строке не изгнать.

                      Only users with full accounts can post comments. Log in, please.