4 日志系统 -- 学习笔记

第四章 日志系统

  1. /var/log/下查看VMware中Ubuntu的日志

  2. cpp学习必备:gitee上面搜awesome -cpp

  3. 日志系统构成

    日志来源

    系统控制

    日志输出

    日志存储

  4. 日志系统设计

    记录器

    过滤器

    格式化器

    输出器

  5. 一条日志的生命周期

    1. 产生。info(“log information.”);

    2. 经过记录器。记录器去获取日志发生的时间,位置,线程信息等等信息,会有一个数据结构去存储你需要的信息(例如:msg:”log information.”,time:2018- 3-20 10:00:00,level:info,location:main.rs:3 lines)

    3. 经过过滤器。决定是否记录(例如,过滤条件设为info级以下的过滤掉,这条日志信息等级是info,满足条件,继续。)

    4. 经过格式化器。假设我们想输出为“2018-3-22 10:00:00 [info] log information.”

    5. 到输出器。例如输出到文件中,我们就将这条信息写到文件上 ;

    6. 这条日志信息生命结束了。

  6. 使用日志系统log4cpp

    1. 日志的格式

      涉及头文件:

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

      BasicLayout:“以时间戳 + 优先级 + 内容”

      //构造函数:
      log4cpp::BasicLayout::BasicLayout()
      //输出例子格式:
      1248337987 ERROR : Hello log4cppin a Error Message!
      1248337987 WARN : Hello log4cppin a Warning Message!
      

      SimpleLayout:“优先级 + 日志信息”

      //构造函数:
      log4cpp::SimpleLayout::SimpleLayout()
      

      PatterLayout:“使用类似printf的格式化模式”

      //构造函数:
      log4cpp::PatternLayout::PatternLayout();
          
      //PatterLayout 设置日志格式函数
      void log4cpp::PatternLayout::setConversionPattern(const std::string &conversionPattern);
          
      //使用 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 %x: %m%n");
      
    2. 日志的目的地

      涉及头文件:

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

      OstreamAppender:输出到一个ostream类

      //构造函数:
      log4cpp::OstreamAppender::OstreamAppender(const std::string &name,
      std::ostream stream);
      
      //参数:
      //name:the name of the Appender
      //stream:the name of the ostream
      log4cpp::OstreamAppender osAppender = new log4cpp::OstreamAppender("osAppender",
      &cout);
      

      StringQueueAppender:内存队列

      //构造函数:
      log4cpp::StringQueueAppender::StringQueueAppender(const std::string &name);
      
      //举例:
      log4cpp::StringQueueAppender* strQAppender = new log4cpp::StringQueueAppender("strQAppender");
      

      FileAppender:输出到文件

      //构造函数:
      log4cpp::FileAppender::FileAppender (const std::string &name, int fd);
          
      /*参数:
      name:he name of the Appender.
      fd:the file descriptor to which the Appender has to log.
      */
          
      //构造函数
      log4cpp::FileAppender::FileAppender (const std::string &name, const std::string &fileName, bool append = true, mode_t mode = 00644);
      
      /*参数:
      name:the name of the Appender.
      fileName:the name of the file to which the Appender has to log.
      append:whether the Appender has to truncate the file or just append to it if it
      already exists. Defaults to 'true'.
      mode:file mode to open the logfile with. Defaults to 00644.
      */
      
      //举例:
      log4cpp::FileAppender* fileAppender = new log4cpp::FileAppender("fileAppender","wxb.log");
      
      fileAppender->setLayout(pLayout1);
      

      Appender 有个成员函数(方法):

      virtual void log4cpp::Appender::setLayout(Layout *layout)
      //函数用作:设置 appender 格式
      

      RoollingFileAppender:滚动式输出到文件

      //构造函数
      log4cpp::RollingFileAppender::RollingFileAppender(const std::string &name,
      const std::string &fileName, size_t maxFileSize = 10 *1024 *1024, unsigned int maxBackupIndex = 1, bool append = true, mode_t mode = 00644);
      
      /*
      参数:
      前两个参数与普通文件的类似
      第三个参数 maxFileSize:指出了回滚文件的最大值
      第四个参数 maxBackupIndex:指出了回滚文件所用的备份文件的最大个数。所谓备份文件,是用来保存回滚文件中因为空间不足未能记录的日志,备份文件的大小仅比回滚文件的最大值大 1kb。所以如果 maxBackupIndex 取值为 3,则回滚文件(假设其名称是 rollwxb.log,大小为 100kb)会有三个备份文件,其名称分别是 rollwxb.log.1,rollwxb.log.2 和 rollwxb.log.3,大小为 101kb。另外要注意:如果 maxBackupIndex 取值为 0 或者小于 0,则回滚文件功能会失效,其表现如同 FileAppender 一样,不会有大小的限制。这也许是一个bug。
      第五第六参数同上。
      */
      
      //举例:
      log4cpp::RollingFileAppender* rollfileAppender =
      new log4cpp::RollingFileAppender( "rollfileAppender","rollwxb.log",5*1024,3);
      
      rollfileAppender->setLayout(pLayout2);
      
    3. Category日志的种类

      涉及头文件

      #include<log4cpp/Category.hh>
      

      Log4cpp 中有一个总是可用并实例化好的 Category,即根 Category。使用log4cpp::Category::getRoot()可以得到根 Category。

      在大多数情况下,一个应用程序只需要一个日志种类(Category),但是有时也会用到多个 Category,此时可以使用根 Category 的 getInstance 方法来得到子 Category。不同的子 Category 用于不同的场合。

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

      主要的成员函数:

      //设置category的级别
      void log4cpp::Category::setPriority (Priority::Value priority);
      //设置或添加appender
      void log4cpp::Category::addAppender (Appender *appender );
      void log4cpp::Category::setAppender (Appender *appender );
      //相应日志级别的记录
      //emerg/fatal/alter/crit/error/warn/notice/info/debug/notset
      void log4cpp::Category::warn(const std::string &message);
      void log4cpp::Category::warn(const char * stringFormat,... );
      void log4cpp::Category::error(const std::string &message);
      void log4cpp::Category::error(const char *stringFormat,... );
      
    4. 日志的优先级(当日志的优先级比category的优先级低的时候,日志就会被过滤)

      涉及头文件:

      #include<log4cpp/Priority.hh>
      

      ​ 每个Category都有一个优先级,该优先级可以由setPriority方法设置,或者从其父 Category 中继承而来。每条日志也有一个优先级,当 Category 记录该条日志时,若日志优先级高于 Category 的优先级时,该日志被记录,否则被忽略。

    5. 程序员在使用 log4cpp时应该遵循以下几个使用原则:

    ​    1)不要手动释放 Category、Appender 和 Layout;

    ​    2)同一个 Appender 不要加入多个 Category,否则它会被释放多次从而导致程序崩溃;

    ​    3)同一个 Layout 不要附着到多个 Appender 上,否则也会被释放多次导致程序崩溃;

    1. log4cpp::Category::shutdown():在不使用 log4cpp 时可调用 log4cpp::Category::shutdown(),其功能如同 HierarchyMaintainer 的内存清理。但如果不手动调用,在程序结束时 HierarchyMaintainer 会调用 Category 的析构函数来释放所有 Appender。

    2. 使用举例

      void test()
      {
          //日志的格式
          PatternLayout *ppl1 = new PatternLayout();
          ppl1->setConversionPattern("%d %c [%p] %m%n");
      
          PatternLayout *ppl2 = new PatternLayout();
          ppl2->setConversionPattern("%d %c [%p] %m%n");
          //日志的目的地
          OstreamAppender *pos = new OstreamAppender("OstreamAppender", &cout);
          pos->setLayout(ppl1);
      
          RollingFileAppender *pfa = 
              new RollingFileAppender("RollingFileAppender1234", "wd.log", 3 * 1024, 3);
          pfa->setLayout(ppl2);
          //日志的种类
          Category &root = Category::getRoot().getInstance("mycat");
          root.addAppender(pfa);
          root.addAppender(pos);
          root.setPriority(Priority::ERROR);//日志的优先级
          //当日志的优先级比category的优先级低的时候,日志就会被过滤
          size_t idx = 0;
          while(idx < 100)
          {
              root.emerg("this is an emerg");
              root.fatal("this is an fatal");
              root.error("this is a error");
              root.warn("this is a warn ");
              root.debug("this is a debug");
              ++idx;
          }
          //回收资源
          Category::shutdown();
      }
      
    3. Log4cpp的封装[单例模式,可变参数]。

      //Mylogger.hpp
      #ifndef __WD_MYLOGGER_H__
      #define __WD_MYLOGGER_H__
      #include <log4cpp/Category.hh>
      #include <string>
      using std::string;
      
      namespace wd
      {
      class Mylogger
      {
      public:
      	enum Priority {
      		ERROR = 300,
      		WARN,
      		INFO,
      		DEBUG
      	};
          
      	static Mylogger * getInstance();
      	static void destroy();
          
      	template <class... Args>
      	void warn(const char * msg, Args... args)
      	{	_mycat.warn(msg, args...);	}
      
      	template <class... Args>
      	void error(const char * msg, Args... args)
      	{	_mycat.error(msg, args...);	}
      
      	template <class... Args>
      	void info(const char * msg, Args... args)
      	{	_mycat.info(msg, args...);	}
      
      	template <class... Args>
      	void debug(const char * msg, Args... args)
      	{	_mycat.debug(msg, args...);	}
      
      	void warn(const char * msg);
      	void error(const char * msg);
      	void info(const char * msg);
      	void debug(const char * msg);
      
      	void setPriority(Priority p);
      private:
      	Mylogger();
      	~Mylogger();
      private:
      	log4cpp::Category & _mycat;
      
      	static Mylogger * _pInstance;
      };
      
      #define prefix(msg) string("[")\
      	.append(__FILE__).append(":")\
      	.append(__FUNCTION__).append(":")\
      	.append(std::to_string(__LINE__)).append("] ")\
      	.append(msg).c_str()
      
      #define LogError(msg, ...) Mylogger::getInstance()->error(prefix(msg), ##__VA_ARGS__)
      #define LogWarn(msg, ...)  Mylogger::getInstance()->warn(prefix(msg), ##__VA_ARGS__)
      #define LogInfo(msg, ...)  Mylogger::getInstance()->info(prefix(msg), ##__VA_ARGS__)
      #define LogDebug(msg, ...) Mylogger::getInstance()->debug(prefix(msg), ##__VA_ARGS__)
      
      }//end of namespace wd
      #endif
      
      
      //Mylogger.cc
      #include "Mylogger.hpp"
      #include <log4cpp/PatternLayout.hh>
      #include <log4cpp/Priority.hh>
      #include <log4cpp/OstreamAppender.hh>
      #include <log4cpp/FileAppender.hh>
      #include <iostream>
      using std::cout;
      using std::endl;
      namespace wd
      {
      
      Mylogger * Mylogger::_pInstance = nullptr;
      Mylogger * Mylogger::getInstance() 
      {
      	if(nullptr == _pInstance) {
      		_pInstance = new Mylogger();
      	}
      	return _pInstance;
      }
      
      void Mylogger::destroy()
      {
      	if(_pInstance) {
      		delete _pInstance;
      	}
      }
      
      Mylogger::Mylogger()
      : _mycat(log4cpp::Category::getRoot().getInstance("MyCategory"))
      {
      	using namespace log4cpp;
      	PatternLayout * ptn1 = new PatternLayout();
      	ptn1->setConversionPattern("%d %c [%p] %m%n");
      
      	PatternLayout * ptn2 = new PatternLayout();
      	ptn2->setConversionPattern("%d %c [%p] %m%n");
      
      	OstreamAppender * ostreamAppender = new OstreamAppender("OstreamAppender", &cout);
      	ostreamAppender->setLayout(ptn1);
      
      	FileAppender * fileAppender = new FileAppender("FileAppender", "wd.log");
      	fileAppender->setLayout(ptn2);
      
      	_mycat.addAppender(ostreamAppender);
      	_mycat.addAppender(fileAppender);
      	_mycat.setPriority(log4cpp::Priority::DEBUG);
      	cout << "Mylogger()" << endl;
      }
      
      Mylogger::~Mylogger() 
      {
      	cout << "~Mylogger()" << endl;
      	log4cpp::Category::shutdown();
      }
      void Mylogger::warn(const char * msg)
      {
      	_mycat.warn(msg);
      }
      void Mylogger::error(const char * msg)
      {
      	_mycat.error(msg);
      }
      void Mylogger::info(const char * msg)
      {
      	_mycat.info(msg);
      }
      void Mylogger::debug(const char * msg)
      {
      	_mycat.debug(msg);
      }
      void Mylogger::setPriority(Priority p)
      {
      	switch(p)
      	{
      	case WARN:
      		_mycat.setPriority(log4cpp::Priority::WARN);
      		break;
      	case ERROR:
      		_mycat.setPriority(log4cpp::Priority::ERROR);
      		break;
      	case INFO:
      		_mycat.setPriority(log4cpp::Priority::INFO);
      		break;
      	case DEBUG:
      		_mycat.setPriority(log4cpp::Priority::DEBUG);
      		break;
      	}
      }
      }//end of namespace wd
      
      
      //TestMylogger.cc
      #include "Mylogger.hpp"
      #include <iostream>
      #include <string>
      using std::cout;
      using std::endl;
      using std::string;
      using namespace wd;
      void test0()
      {
      	Mylogger::getInstance()->error(prefix("this is an error message!"));
      	Mylogger::getInstance()->warn("this is a warn message!");
      	Mylogger::getInstance()->info("this is an info message!");
      	Mylogger::getInstance()->debug("this is a debug message!");
      	cout << "Mylogger::Priority::WARN = " << Mylogger::Priority::WARN << endl;
      	cout << "Mylogger::Priority::ERROR = " << Mylogger::Priority::ERROR << endl;
      	cout << "Mylogger::Priority::INFO = " << Mylogger::Priority::INFO << endl;
      	cout << "Mylogger::Priority::DEBUG = " << Mylogger::Priority::DEBUG << endl;
      
      	Mylogger::getInstance()->setPriority(Mylogger::Priority::WARN);
      }
      
      void test1()
      {
      	cout << __FILE__ << " " << __LINE__ << " " << __FUNCTION__ << endl;
      }
      
      void test2()
      {
      	LogError("this is a error message! ");
      	LogWarn("this is a error message!");
      	LogInfo("this is a error message!");
      	LogDebug("this is a error message!");
      }
       
      void test3()
      {
      	int number = 10;
      	const char * pstr = "hello,world";
      	Mylogger::getInstance()->debug(prefix("this is a error message! number = %d, str = %s"), number, pstr);
      
      	LogError("this is a error message! number = %d, str = %s", number, pstr);
      	LogWarn("this is a warn message!");
      	LogInfo("this is a info message!");
      	LogDebug("this is a error message!");
      }
      int main(void)
      {
      	//test0();
      	//test1();
      	//test2();
      	test3();
      	return 0;
      }
      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值