应用扩展2:日志系统log4cpp

一、日志的重要性

  1. 服务器程序:7*24小时,一直在运行——守护进程(后台默默运行)
    · 当服务器崩了或者出问题之后,可以查日志

二、日志系统的构成

  1. 一个日志系统根据他的过程,分为4个模块,并加以抽象
    ①日志来源:内核、虚拟机、邮箱等
    ②系统控制:流转过程(日志是怎样一步一步走动的?)
    ③日志输出:输出到文件?屏幕?
    ④日志存储:单独的系统?写入文件?

三、日志系统的设计思路

  1. 为了设计一个灵活可扩展、可配置的日志库,主要将日志库分为4个部分:
4个部分作用
记录器记录日志的(原始信息、日志等级、时间、位置)
过滤器不需要的日志过滤掉
格式化器给日志设置格式
输出器日志输出到哪里?

四、log4cpp

  1. 什么是log4cpp (log for cpp),记录日志的一种手段
  2. log4cpp的官网
    (1)通过github.com(国外网站)到达log4cpp官网
    (2)log4cpp官网:https://log4cpp.sourceforge.net/
    (3)api:https://log4cpp.sourceforge.net/api/index.html
    (4)class:https://log4cpp.sourceforge.net/api/hierarchy.html

(一)log4cpp的安装

1.下载log4cpp-1.1.1.tar.gz    
         
2. 安装:先将log4cpp-1.1.1.tar.gz拖入用户主目录(~),
   然后再执行以下步骤:
   
   $ tar zxvf log4cpp-1.1.1.tar.gz 

   $ cd ~/log4cpp/
   $ ./configure
   $ make
   $ make check
   $ sudo make install

      这里已经安装成功.
	  
	  默认lib库路径是 : /usr/local/lib/
     
	  默认头文件的位置: /usr/local/include/log4cpp        
      (自己装在了/home/duxiuhan/log4cpp/include/log4cpp)   
3. 使用:
	3.1 编译使用log4cpp库的CPP文件时,要加上库文件,才能顺利的编译通过,如下示例
	
	$ g++ log4test.cpp -llog4cpp -lpthread
	
	3.2 运行时,如若提示缺少log4cpp库文件,表示找不到log4cpp的动态库,需要进行以下设置
	以管理员身份登录终端,然后执行以下操作:

	a. 添加/usr/local/lib到最后一行:$ sudo vim /etc/ld.so.conf
	
	b. 在打开的文件末尾另起一行添加动态库log4cpp的路径(这里是/usr/local/lib),然后保存退出;
	   执行命令ldconfig使设置生效即可。
	c. $ sudo ldconfig   //更新库文件的缓存信息  
	  (可以看到)/etc/ld.so.cache
4. log4cpp学习
	http://blog.csdn.net/liuhong135541/article/category/1496383

sudo ldconfig 更新库文件的缓存信息
在这里插入图片描述

五、log4cpp的使用

(一)日志的格式: Layout

3种方式打印的格式
☆PatterLayout使用类似printf的格式化模式
BasicLayout“以时间戳+优先级+内容”
SimpleLayout“优先级+日志信息”

1. 涉及的头文件:

#include<log4cpp/BasicLayout.hh>
#include<log4cpp/SimpleLayout.hh>
#include<log4cpp/PatternLayout.hh>

2. 三种方式

(1)PatternLayout
构造函数:
log4cpp::PatternLayout::PatternLayout()1)PatterLayout 设置日志格式函数
void log4cpp::PatternLayout::setConversionPattern(const std::string &conversionPattern) throw
(ConfigureFailure)2)使用 PatterLayout 时的格式化参数:
%c category的名字;
%d 日期;可以进一步的设置格式,用花括号包围,如%d{%H:%M:%S,%l}%d{%d %m%Y%H:%M:%S,%l}。
        如果不设置具体日期格式,则如下默认格式被使用“Wed Jan 02 02:03:55 1980”。
  日期的格式符号与 ANSI C 函数 strftime 中的一致。但增加了一个格式符号%l,表示毫秒,占三个十进制位。
%m 消息;
%n 换行符,会根据平台的不同而不同,但对于用户透明;
%p 优先级;
%r 自从 layout 被创建后的毫秒数;
%R 从 1970110 时开始到目前为止的秒数;
%u 进程开始到目前为止的时钟周期数;
%x NDC。
举例:
log4cpp::PatternLayout* pLayout = new log4cpp::PatternLayout();
pLayout->setConversionPattern("%d: [%p] %c %m%n");
                日期%d  优先级[%p] 名字%c 消息(字符串)%m 换行%n
(2)BasicLayout
构造函数:
log4cpp::BasicLayout::BasicLayout()
输出例子格式:
1248337987 ERROR : Hello log4cppin a Error Message!
1248337987 WARN : Hello log4cppin a Warning Message!
(3)SimpleLayout
构造函数:
log4cpp::SimpleLayout::SimpleLayout()

(二)日志的目的地:Appender

1. 涉及头文件

#include <log4cpp/Appender.hh>
#include <log4cpp/OstreamAppender.hh>
#include <log4cpp/StringQueueAppender.hh>
#include <log4cpp/FileAppender.hh>
#include <log4cpp/RollingFileAppender.hh>

2. 四种常用方式

(1)OstreamAppender//输出到一个 ostream 类
(2)StringQueueAppender//内存队列
(3)FileAppender//写到文件中
(4)RollingFileAppender//文件过多之后,可以覆盖老文件
  1. RollingFileAppender回滚文件可以设置文件大小,如 5 * 1024
  2. 文件过多之后,可以覆盖老文件
RollingFileAppender("Appender的名字", "文件名", 文件大小, 几个文件)

(三)日志的记录:Category(负责写入信息)

1. 涉及头文件

#include<log4cpp/Category.hh>

2. 主要的成员函数

(1)设置Category的级别
void log4cpp::Category::setPriority (Priority::Value priority) throw
(2)设置或添加 Appender
void log4cpp::Category::addAppender (Appender *appender ) throw
(3)相应日志级别的记录
(emerg/fatal/alter/crit/error/warn/notice/info/debug/notset)

(四)日志的过滤:Priority (通过优先级实现)

1. 涉及头文件

#include<log4cpp/Priority.hh>

2. 优先级Priority的枚举类型

typedef enum
{
    EMERG=0,
    FATAL=0,
    ALERT=100,
    CRIT=200,
    ERROR=300,
    WARN=400,
    NOTICE=500,
    INFO=600,
    DEBUG=700,
    NOTSET =800
}PriorityLevel;

【注意】日志的优先级 ≥ Category记录的优先级

六、log4cpp应用例子

(一)写到屏幕上(用的OstreamAppender)

    1 #include <iostream>
    2 #include <log4cpp/PatternLayout.hh>
    3 #include <log4cpp/OstreamAppender.hh>
    4 #include <log4cpp/Category.hh>
    5 #include <log4cpp/Priority.hh>
    6 
    7 using std::cout;
    8 using std::endl;
    9 
   10 using namespace log4cpp;//引出log4cpp的命名空间
   11 
   12 void test()
   13 {
   14     //日志的格式
   15     PatternLayout *ppl = new PatternLayout();
   16     ppl->setConversionPattern("%d %c [%p] %m%n");                             
   17                                             
   18     //日志的目的地(会和格式Layout联系)  
   19     OstreamAppender *poa = new OstreamAppender("OstreamAppender123",&cout);
   20     poa->setLayout(ppl);
   21         
   22     //日志的记录器(会和目的地Appender联系)
   23     Category &root = Category::getRoot();
   24     root.addAppender(poa);
   25         
   26     //日志的过滤器
   27     root.setPriority(Priority::ERROR);//ERROR是优先级Priority的枚举类型之一
   28         
   29     //用root调用相应的函数,这些函数都是记录器Category的成员函数
   30     //日志的优先级 ≥ Category记录的优先级
   31     root.emerg("This is an emerg message");
   32     root.fatal("This is an fatal message");
   33     root.alert("This is an alert message");
   34     root.crit("This is an crit message");
   35     root.error("This is an error message");
   36     root.warn("This is an warn message");
   37     root.info("This is an indo message");
   38     root.debug("This is an debug message");
   39    
   40     //空间的回收,使用写好的shutdown
   41     Category::shutdown();
   42 }  
   4344 int main(int argc, char **argv)
   45 {  
   46     test();
   47     return 0;
   48 }  

在这里插入图片描述

(二)写到文件上(用的FileAppender)

    1 #include <iostream>
    2 #include <log4cpp/PatternLayout.hh>
    3 #include <log4cpp/OstreamAppender.hh>
    4 #include <log4cpp/FileAppender.hh>
    5 #include <log4cpp/Category.hh>
    6 #include <log4cpp/Priority.hh>
    7 
    8 using std::cout;
    9 using std::endl;
   10 
   11 using namespace log4cpp;//引出log4cpp的命名空间
   12 
   13 void test()
   14 {
   15     //日志的格式
   16     PatternLayout *ppl = new PatternLayout();
   17     ppl->setConversionPattern("%d %c [%p] %m%n");
   18 
   19     //日志的目的地(会和格式Layout联系)  
   20     OstreamAppender *poa = new OstreamAppender("OstreamAppender123",&cout);
   21     poa->setLayout(ppl);
   22 
   23     FileAppender *pfa = new FileAppender("FileAppender1","wd.log");//Appender>
   24     pfa->setLayout(ppl);
   25 
   26     //日志的记录器(会和目的地Appender联系)
   27     Category &root = Category::getRoot();
   28     root.addAppender(poa);
   29     root.addAppender(pfa);                                                    
   30                     
   31     //日志的过滤器  
   32     root.setPriority(Priority::ERROR);//ERROR是优先级Priority的枚举类型之一
   33                     
   34     //用root调用相应的函数,这些函数都是记录器Category的成员函数
   35     //日志的优先级 ≥ Category记录的优先级
   36     root.emerg("This is an emerg message");
   37     root.fatal("This is an fatal message");
   38     root.alert("This is an alert message");
   39     root.crit("This is an crit message");
   40     root.error("This is an error message");
   41     root.warn("This is an warn message");
   42     root.info("This is an indo message");
   43     root.debug("This is an debug message");
   44                     
   45     //空间的回收,使用写好的shutdown
   46     Category::shutdown();
   47 }                   
   4849 int main(int argc, char **argv)
   50 {                   
   51     test();         
   52     return 0;       
   53 }                 

在这里插入图片描述

在这里插入图片描述
bug】因为输出到屏幕和文件中了,所以其他地方没有问题,有问题的地方是空间回收shutdown
(1)错误原因:1个Layout对应了2个输出,回收的时候会double free
(2)改进:每1个Layout对应1个Appender

   15     //日志的格式
   16     PatternLayout *ppl1 = new PatternLayout();
   17     ppl1->setConversionPattern("%d %c [%p] %m%n");
   18  
   20     PatternLayout *ppl2 = new PatternLayout();
   21     ppl2->setConversionPattern("%d %c [%p] %m%n");
   22 
   23     //日志的目的地(会和格式Layout联系)  
   24     OstreamAppender *poa = new OstreamAppender("OstreamAppender123",&cout);
   25     poa->setLayout(ppl1);
   26 
   27     FileAppender *pfa = new FileAppender("FileAppender1","wd.log");//Appender>
   28     pfa->setLayout(ppl2);                                                   

在这里插入图片描述
且发现了这种输出到文件的方式,是追加
在这里插入图片描述

(三)FileAppender的改进型RollingFileAppender

    1 #include <iostream>                                                                      
    2 #include <log4cpp/PatternLayout.hh>
    3 #include <log4cpp/OstreamAppender.hh>
    4 #include <log4cpp/RollingFileAppender.hh>
    5 #include <log4cpp/Category.hh>
    6 #include <log4cpp/Priority.hh>
    7 
    8 using std::cout;
    9 using std::endl;
   10 
   11 using namespace log4cpp;//引出log4cpp的命名空间
   12 
   13 void test()
   14 {
   15     //日志的格式
   16     PatternLayout *ppl1 = new PatternLayout();
   17     ppl1->setConversionPattern("%d %c [%p] %m%n");
   18         
   19         
   20     PatternLayout *ppl2 = new PatternLayout();
   21     ppl2->setConversionPattern("%d %c [%p] %m%n");
   22         
   23     //日志的目的地(会和格式Layout联系)  
   24     OstreamAppender *poa = new OstreamAppender("OstreamAppender123",&cout);
   25     poa->setLayout(ppl1);
   26         
   27     RollingFileAppender *prfa = new RollingFileAppender("RollingFileAppender1",
   28                                                         "wd.log",
   29                                                         5 * 1024,
   30                                                         3);
   31         
   32         
   33     prfa->setLayout(ppl2);
   34         
   35     //日志的记录器(会和目的地Appender联系)
   36     Category &root = Category::getRoot();
   37     root.addAppender(poa);
   38     root.addAppender(prfa);
   39         
   40     //日志的过滤器
   41     root.setPriority(Priority::ERROR);//ERROR是优先级Priority的枚举类型之一
   42         
   43     //用root调用相应的函数,这些函数都是记录器Category的成员函数
   44     //日志的优先级 ≥ Category记录的优先级
   45     //∵内容不够多,可以循环输出,这样可以用到设置过的3个日志
   46     size_t idx = 0;
   47     while(idx < 100)
   48     {   
   49          root.emerg("This is an emerg message");
   50          root.fatal("This is an fatal message");
   51          root.alert("This is an alert message");
   52          root.crit("This is an crit message");
   53          root.error("This is an error message");
   54          root.warn("This is an warn message");
   55          root.info("This is an indo message");
   56          root.debug("This is an debug message");
   57         
   58         ++idx;
   59     }
   60     //空间的回收,使用写好的shutdown
   61     Category::shutdown();
   62 }
   6364 int main(int argc, char **argv)
   65 {
   66     test();
   67     return 0;
   68 }

在这里插入图片描述

注意事项

  1. 用root调用相应的函数时,…代表可变参数
root.emerg(const char *format, ...);//...代表可变参数
//可变参数:参数的个数不确定,参数的类型不确定
如使用:printf("hello\n");
	  printf("%d\n", 10);
      printf("%s  %d  %p\n", "hello", 10, &"hello");
  1. 编译的时候,注意:g++ xxx.cc -llog4cpp -lpthread
    ∵要依赖线程库

    ∴有-lpthread
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值