cpp-doc-log4cpp使用

介绍

Log4cpp是一个开源的C++类库,它提供了C++程序中使用日志和跟踪调试的功能,它的优点如下:

  • 提供应用程序运行上下文,方便跟踪调试;
  • 可扩展的、多种方式记录日志,包括命令行、文件、回卷文件、内存、syslog服务器、Win事件日志等;
  • 可以动态控制日志记录级别,在效率和功能中进行调整;
  • 所有配置可以通过配置文件进行动态调整;
  • 多语言支持,包括Java(log4j),C++(log4cpp、log4cplus),C(log4c),python(log4p)等;

原理

Log4cpp有三个主要的组件:日志类别(Category)、输出源(Appender)和布局(Layout)。这三种类型的组件一起工作使得系统可以根据信息的类型和级别记录它们,并且在运行时控制这些信息的输出格式和位置。

Category和Appender的关系是:多个Appender可以附加到一个Category上,这样一个日志消息可以同时输出到多个设备上。
Appender和Layout的关系是:Layout附加在Appender上,appender调用layout处理完日志消息后,记录到某个设备上。

Category

日志类别(Category)含义是:如果配置文件中设置的级别是DEBUG,则任意的log都能打印出来;

日志的级别总共有:NOTSET < DEBUG < INFO < NOTICE < WARN < ERROR < CRIT < ALERT < FATAL = EMERG。日志级别的意思是低于该级别的日志不会被记录。

Appender

输出源(Appender)用来输出日志(被layout格式化后)到一些设备上,比如文件、命令行、内存等。也可以定义自己的appender输出日志信息到别的设备上。log4cpp提供的appender如下:

  • Log4cpp::ConsoleAppender // 输出到控制台
  • log4cpp::FileAppender // 输出到文件
  • log4cpp::RollingFileAppender // 输出到回卷文件,即当文件到达某个大小后回
  • log4cpp::OstreamAppender // 输出到一个ostream类
  • log4cpp::RemoteSyslogAppender // 输出到远程syslog服务器
  • log4cpp::StringQueueAppender // 内存队列
  • log4cpp::SyslogAppender // 本地syslog
  • log4cpp::Win32DebugAppender // 发送到缺省系统调试器
  • log4cpp::NTEventLogAppender // 发送到win 事件日志
  • log4cpp::DailyRollingFileAppender // 按日输出文件

有一个很恶心的设定,rootCategory总是会被执行。

Layout

布局(Layout):显示样式

  • PatternLayout:让用户根据类似于C语言printf函数的转换模式来指定输出格式
  • BasicLayout:不做任何修饰

日志输出格式

1
2
3
4
5
6
7
8
9
10
11
12
// By default, ConversionPattern for PatternLayout is set to "%m%n".
%% - a single percent sign
%c - the category
%d - the date\n Date format: The date format character may be followed by a date format specifier enclosed between braces. For example, %d{%\H:%M:%S,%l} or %d{%\d %m %Y %H:%\M:%S,%l}. If no date format specifier is given then the following format is used: "Wed Jan 02 02:03:55 1980". The date format specifier admits the same syntax as the ANSI C function strftime, with 1 addition. The addition is the specifier %l for milliseconds, padded with zeros to make 3 digits.
%m - the message
%n - the platform specific line separator
%p - the priority
%r - milliseconds since this layout was created.
%R - seconds since Jan 1, 1970
%u - clock ticks since process start
%x - the NDC
%t - thread name

安装log4cpp

log4cpp的sourceforge地址:http://log4cpp.sourceforge.net/

api文档:http://docs.ros.org/en/lunar/api/log4cpp/html/namespacelog4cpp.html

1
2
3
4
5
6
wget https://nchc.dl.sourceforge.net/project/log4cpp/log4cpp-1.1.x%20%28new%29/log4cpp-1.1/log4cpp-1.1.3.tar.gz
tar xzvf log4cpp-1.1.3.tar.gz
cd log4cpp-1.1.3
./configure --with-pthreads
make
make install

配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# log4cpp.properties

log4cpp.rootCategory=DEBUG, rootAppender
log4cpp.category.sub1=DEBUG, A1, A2
log4cpp.category.sub1.sub2=DEBUG, A3

log4cpp.appender.rootAppender=ConsoleAppender
log4cpp.appender.rootAppender.layout=PatternLayout
log4cpp.appender.rootAppender.layout.ConversionPattern=%d [%p] %m%n

log4cpp.appender.A1=FileAppender
log4cpp.appender.A1.fileName=A1.log
log4cpp.appender.A1.layout=BasicLayout

log4cpp.appender.A2=FileAppender
log4cpp.appender.A2.threshold=WARN
log4cpp.appender.A2.fileName=A2.log
log4cpp.appender.A2.layout=PatternLayout
log4cpp.appender.A2.layout.ConversionPattern=%d [%p] %m%n

log4cpp.appender.A3=RollingFileAppender
log4cpp.appender.A3.fileName=A3.log
log4cpp.appender.A3.maxFileSize=200
log4cpp.appender.A3.maxBackupIndex=1
log4cpp.appender.A3.layout=PatternLayout
log4cpp.appender.A3.layout.ConversionPattern=%d [%p] %m%n

编程使用

包含头文件

1
2
3
4
#include <log4cpp/Category.hh>
#include <log4cpp/FileAppender.hh>
#include <log4cpp/PatternLayout.hh>
#include <log4cpp/OstreamAppender.hh>

初始化日子输出的目的地

1
2
3
4
// 输出到std::cout
log4cpp::Appender *appender = new log4cpp::OstreamAppender("root", &std::cout);
// 输出到log文件
//log4cpp::Appender *appender = new log4cpp::FileAppender("root", "test.log");

设置日子输出的格式

1
2
3
log4cpp::PatternLayout *patternLayout = new log4cpp::PatternLayout();
patternLayout->setConversionPattern("%d [%p] - %m%n");
appender->setLayout(patternLayout);

设置类别输出的(category)和日志优先级(priority)

1
2
3
log4cpp::Category &root = log4cpp::Category::getRoot();
root.setPriority(log4cpp::Priority::NOTICE);
root.addAppender(appender);

定义一个宏简便使用

1
#define LOG(__level) log4cpp::Category::getRoot() << log4cpp::Priority::__level << __FILE__ << " " << __LINE__ << ": "
1
2
3
4
5
LOG(DEBUG) << "i am happy.";
LOG(INFO) << "oh, you happy, we happy.";
LOG(NOTICE)<< "please do not contact me. ";
LOG(WARN) << "i am very busy now.";
LOG(ERROR) << "oh, what happed?";

定义一个单利简便使用

1
// todo

例子:简单使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <log4cpp/Category.hh>
#include <log4cpp/OstreamAppender.hh>
#include <log4cpp/Priority.hh>
#include <log4cpp/PatternLayout.hh>

using namespace std;

void testlog()
{
log4cpp::OstreamAppender* osAppender = new log4cpp::OstreamAppender("osAppender", &cout);

log4cpp::PatternLayout* pLayout = new log4cpp::PatternLayout();
pLayout->setConversionPattern("%d: %p %c %x: %m%n");
osAppender->setLayout(pLayout);

log4cpp::Category& root = log4cpp::Category::getRoot();
log4cpp::Category& infoCategory = root.getInstance("infoCategory");
infoCategory.addAppender(osAppender);
infoCategory.setPriority(log4cpp::Priority::INFO);

infoCategory.info("system is running");
infoCategory.warn("system has a warning");
infoCategory.error("system has a error, can't find a file");
infoCategory.fatal("system has a fatal error,must be shutdown");
infoCategory.info("system shutdown,you can find some information in system log");

log4cpp::Category::shutdown();
}

例子:使用配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <log4cpp/Category.hh>
#include <log4cpp/PropertyConfigurator.hh>

int main(int argc, char* argv[])
{
std::string initFileName = "log4cpp.properties";
log4cpp::PropertyConfigurator::configure(initFileName);

log4cpp::Category& root = log4cpp::Category::getRoot();

log4cpp::Category& sub1 =
log4cpp::Category::getInstance(std::string("sub1"));

log4cpp::Category& sub2 =
log4cpp::Category::getInstance(std::string("sub1.sub2"));

root.warn("Storm is coming");

sub1.debug("Received storm warning");
sub1.info("Closing all hatches");

sub2.debug("Hiding solar panels");
sub2.error("Solar panels are blocked");
sub2.debug("Applying protective shield");
sub2.warn("Unfolding protective shield");
sub2.info("Solar panels are shielded");

sub1.info("All hatches closed");

root.info("Ready for storm.");

log4cpp::Category::shutdown();

return 0;
}