22 April 2011

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

C++
Чуть ранее мы рассмотрели библиотеку логирования 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 конфигурирование, сравнение с другими логгерами, проверка «мифа о течах».

Приятного логирования!
Tags:log4cxxapachelogger
Hubs: C++
+9
6.1k 23
Comments 17
Popular right now
C++ Developer. Professional
December 28, 202060,000 ₽OTUS
Программирование на языке C (Си)
December 14, 202022,990 ₽Специалист.ру
Apache Spark для дата инженеров
February 16, 202165,000 ₽New Professions Lab
C++ Junior Developer
March 3, 202123,990 ₽Level UP
SEO-специалист
December 7, 202064,900 ₽Нетология