вторник, 29 сентября 2009 г.

log4cpp или как правильно вести логи в C++



Что должна уметь делать любая программа? Помимо того, что просто хорошо работать, она должна сообщать где и какие у неё проблемы или наоборот где у неё всё хорошо, вообщем, вести логи.

Существует тысячи способов ведения логов, несложно написать и свой, но зачем изобретать велосипед, когда всё уже готово?

Я хочу рассказать о log4cpp.

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

Дальше будет код, с подробным описанием каждой функции.



/*
 * log.cpp
 *
 *  Created on: Sep 29, 2009
 *      Author: nol1ght (nol1ght.mail@gmail.com)
 */
#include  <log4cpp category.hh>
#include  <log4cpp fileappender.hh>
#include  <log4cpp basiclayout.hh>

int main(int argc, char**argv)
{
 //Создаём объект Appender(Добавитель - незаю как его ещё по русски назвать...), который будет вести лог.
 log4cpp::Appender* m_log_app = new log4cpp::FileAppender("FileAppender","log.log");
 
 //Создаём объект раскладки, он определяет формат лога
 //Существует несколько стандартных типов раслкадки:
 // - BasicLayout
 // - PatternLayout
 // - SimpleLayout
 //А также, вы можете создавать свои собственные раскладки при помощи log4cpp::Layout
 log4cpp::Layout* m_log_layout = new log4cpp::BasicLayout();
 
 //Присваем нашему Appender`у нужную нам раскладку.
 m_log_app->setLayout(m_log_layout);
 
 //Создаём объект категории 
 log4cpp::Category *m_log_main= &log4cpp::Category::getInstance("Main");

 //Когда Appender добавлен в категорию, он становится дополнительным выводом для информации, пока Additivity(аддитивность) не выключена, если её выключить то Appendr начнёт замещать все предыдущие Appender'ы.
 m_log_main->setAdditivity(false);
 //Appender становится единственным
 m_log_main->setAppender(m_log_app);
 //Устанавливаем приоритет для категории
 m_log_main->setPriority(log4cpp::Priority::DEBUG);

 //Существует несколько способов вести логи: 
 //1. на прямую через функцию приоритета
 m_log_main->alert("1. This is alert"); 
 m_log_main->warn("1. This is warn"); 
 m_log_main->info("1. This is info");
 m_log_main->error("1. This is error");
 m_log_main->notice("1. This is notice");
 m_log_main->debug("1. This is debug");
 m_log_main->crit("1. This is crit");
 //2. через функцию лог с указанием приоритета
 m_log_main->log(log4cpp::Priority::ALERT,"2. This is alert"); 
 m_log_main->log(log4cpp::Priority::WARN,"2. This is warn"); 
 m_log_main->log(log4cpp::Priority::INFO,"2. This is info");
 m_log_main->log(log4cpp::Priority::ERROR,"2. This is error");
 m_log_main->log(log4cpp::Priority::NOTICE,"2. This is notice");
 m_log_main->log(log4cpp::Priority::DEBUG,"2. This is debug");
 m_log_main->log(log4cpp::Priority::CRIT,"2. This is debug");
 //3. в поток через функцию потока приоритета.
 m_log_main->alertStream() << "3. This is alert" << log4cpp::eol;
 m_log_main->warnStream()  << "3. This is warn" << log4cpp::eol;
 m_log_main->infoStream()  << "3. This is info" << log4cpp::eol;
 m_log_main->errorStream() << "3. This is error" << log4cpp::eol;
 m_log_main->noticeStream()  << "3. This is notice" << log4cpp::eol;
 m_log_main->debugStream()  << "3. This is debug" << log4cpp::eol;
 m_log_main->critStream()  << "3. This is crit" << log4cpp::eol;
 //4. в поток с указанием приоритета
 *m_log_main << log4cpp::Priority::ALERT  << "4. This is alert" << log4cpp::eol;
 *m_log_main << log4cpp::Priority::WARN   << "4. This is warn" << log4cpp::eol;
 *m_log_main << log4cpp::Priority::INFO   << "4. This is info" << log4cpp::eol;
 *m_log_main << log4cpp::Priority::ERROR  << "4. This is error" << log4cpp::eol;
 *m_log_main << log4cpp::Priority::NOTICE << "4. This is notice" << log4cpp::eol;
 *m_log_main << log4cpp::Priority::DEBUG  << "4. This is debug" << log4cpp::eol;
 *m_log_main << log4cpp::Priority::CRIT  << "4. This is crit" << log4cpp::eol;
 
 //Очистка всех Appender'ов
 log4cpp::Category::shutdown();
   return 1;
 /*
 Если на данном программу запустить в такой конфигурации она выдаст следующее:
  1256740795 ALERT Main : 4. This is alert
  1256740795 WARN Main : 4. This is warn
  1256740795 INFO Main : 4. This is info
  1256740795 ERROR Main : 4. This is error
  1256740795 NOTICE Main : 4. This is notice
  1256740795 CRIT Main : 4. This is crit
 Как мы видим по выводу у нас присутвуют все сообщения, кроме тех которые идут с приоритетом DEBUG. 
 Если мы поставим приоритет для категории DEBUG, то тогда мы увидим все сообщения.
 */

};


Вся прелесть log4cpp в Appender'ах - помимо того что Вы можете выводить в файл, Вам доступны следующие виды "добавителя":
  1. FileAppender - добавляет в файл, ну его мы уже не считаем...
  2. IdsaAppender - посылает сообщения на IDS/A регистратор и контольный монитор
  3. NTEventLogAppender - посылает сообщения в Windows event log
  4. OstreamAppender - добавляет сообщения в ostreams
  5. RemoteSyslogAppender - отправляет сообщения на удалённую систему в syslog
  6. RollingFileAppender - добавляет сообщения в файл, если размер файла достигает лимита, начинает стирать старые логи
  7. StringQueueAppender - кладёт сообщения в очередь памяти
  8. SyslogAppender - посылает сообщения в syslog на локальной машине
  9. Win32DebugAppender - отсылает сообщения в debugger системы по умолчанию на Win32

Помимо того, что уже есть готовые и встроенные Appender'ы, вы можете создать свой для Ваших нужд, используя:
  1. Appender - для создания своего собственного вывода сообщений.
  2. AppenderSkeleton - это вспомогательный класс упрощающий встраивание Appender'ов, он берёт на себя заботы по обработке порогов и фильтров.

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

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

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