easylogging++学习记录(二):流式日志

easylogging++日志库流式日志的写入,依赖于el::base::Writer类的析构,以debug日志为例:具体代码如下:

#define LOG(LEVEL) CLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID)
#define CLOG(LEVEL, ...)\
    C##LEVEL(el::base::Writer, el::base::DispatchAction::NormalLog, __VA_ARGS__)
#if ELPP_DEBUG_LOG
#   define CDEBUG(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Debug, dispatchAction, __VA_ARGS__)

#define ELPP_WRITE_LOG(writer, level, dispatchAction, ...) \
    writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)

宏替换之后就是调用了Writer类的一个构造函数和一个construct()成员函数,等同于下面代码:

el::base::Writer(...).construct(...)

单独调用一个构造函数的话,会产生一个临时对象,在语句结束后,这个临时对象会被析构,进而触发析构函数中的日志写入逻辑,可以通过下列代码进行验证:

  1 #include <iostream>
  2 #include <sstream>
  3
  4 class A
  5 {
  6 public:
  7     A() { }
  8
  9     ~A()
 10     {
 11         std::cout << m_ss.str() << std::endl;
 12     }
 13
 14     template<typename T>
 15     A& operator << (const T& t)
 16     {
 17         m_ss << t;
 18         return *this;
 19     }
 20
 21 private:
 22     std::ostringstream m_ss;
 23 };
 24
 25 #define SLOG() LOG(A)
 26
 27 #define LOG(a)  28     a()
 29
 30 class B
 31 {
 32 public:
 33     B() {}
 34     ~B()
 35     {
 36         std::cout << "~B()" << std::endl;
 37     }
 38 };
 39
 40 int main()
 41 {
 42     std::cout << ".........begin........." << std::endl;
 43     SLOG() << "first....";
 44     B();
 45     std::cout << "..........middle......." << std::endl;
 46     B b;
 47     b = B();
 48     std::cout << ".........end.........." << std::endl;
 49     return 0;
 50 }

以上代码编译输出结果如下:

$ g++ macro.cpp -o main
$ ./main
.........begin.........
first....
~B()
..........middle.......
~B()
.........end..........
~B()

begin和middle之间两次单独调用构造函数的地方产生的临时对象,都在语句结束后被析构了,在middle和end之间,47行处,调用了构造函数构造出一个临时变量,然后通过赋值构造函数赋值给变量b,随即临时变量被析构,而变量b直到main函数结束才被析构掉。

总而言之,要对easylogging++做一层封装并保持其流式日志的特性,可以通过同样的方式,在析构函数上做手脚。

原文地址:https://www.cnblogs.com/minglee/p/9157083.html

时间: 2024-08-26 17:07:10

easylogging++学习记录(二):流式日志的相关文章

轻量级流式日志计算分析plog+(zabbix+grafana)

plog是一个用python写的流式计算分析框架,适用于轻量级流式数据的分析场景,大数据场景下大家自然想到使用spark等方案. 拿当前的业务场景看,需要对机器上nginx的流日志进行状态码.响应时间.QPS的实时分析,通过zabbix展现在grafana里,QPS在1000以内.传统方法是用shell脚本来计算各种数据,然后通过主动或被动模式传到zabbix里,此种方法有很大局限性,一是grep或awk过滤日志时,很难控制好过滤的数量,过滤的多了严重影响性能,可能上一个数据都没计算出来,这一次

Windows API 编程学习记录&lt;二&gt;

恩,开始写Windows API编程第二节吧. 上次介绍了几个关于Windows API编程最基本的概念,但是如果只是看这些概念,估计还是对Windows API不是很了解.这节我们就使用Windows API 让大家来了解下Windows API的用法. 第一个介绍的Windows API 当然是最经典的MessageBox,这个API 的作用就是在电脑上显示一个对话框,我们先来看看这个API的定义吧: int WINAPI MessageBox(HWND hWnd, LPCTSTR lpTe

Spring Boot学习记录(二)--thymeleaf模板

Spring Boot学习记录(二)–thymeleaf模板 标签(空格分隔): spring-boot 自从来公司后都没用过jsp当界面渲染了,因为前后端分离不是很好,反而模板引擎用的比较多,thymeleaf最大的优势后缀为html,就是只需要浏览器就可以展现页面了,还有就是thymeleaf可以很好的和spring集成.下面开始学习. 1.引入依赖 maven中直接引入 <dependency> <groupId>org.springframework.boot</gr

Java学习:Stream流式思想

Stream流 Java 8 API添加了一种新的机制——Stream(流).Stream和IO流不是一回事. 流式思想:像生产流水线一样,一个操作接一个操作. 使用Stream流的步骤:数据源→转换成流→操作1→操作2→…… 数据源(source):可以是集合.数组等. Stream操作有两个基础特征: Pipelining(流水线):流操作会返回流对象(新的对象),以便后续继续进行流操作. 内部迭代:不需要像for循环或Iterator一样进行显式的迭代. 遍历及过滤集合中的元素 使用传统方

Tornado学习记录二

Coroutines Coroutines are the recommended way to write asynchronous code in Tornado. Coroutines use the Python yield keyword to suspend and resume execution instead of a chain of callbacks (cooperative lightweight threads as seen in frameworks like g

JAVA NIO学习记录2-非阻塞式网络通信

一.阻塞与非阻塞 传统的IO 流都是阻塞式的.也就是说,当一个线程调用read() 或write() 时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不能执行其他任务.因此,在完成网络通信进行IO 操作时,由于线程会阻塞,所以服务器端必须为每个客户端都提供一个独立的线程进行处理,当服务器端需要处理大量客户端时,性能急剧下降. Java NIO 是非阻塞模式的.当线程从某通道进行读写数据时,若没有数据可用时,该线程可以进行其他任务.线程通常将非阻塞IO 的空闲时间用于在其他通道上执行I

Spring学习记录(二)---容器和属性配置

下载spring包,在eclipse搭建spring环境. 这步我在eclipse中无法导入包,看网上的: http://sishuok.(和谐)com/forum/blogPost/list/2428.html 建一个java project 三个java文件,一个xml文件 1 package com.guigu.spring.beans; 2 3 public class HelloWord { 4 private String name; 5 public String getName(

netty 学习记录二

netty 最新版本是netty-5.0.0.Alpha1,去年10月份发布的,至今没有发新版本,估计这个版本还是比较稳定. 整包下载,里面包含一个 netty-example-5.0.0.Alpha1-sources.jar文件,提供了比较丰富的example例子,多看几遍还是非常有收获的,这里记录下. 先来看下channelHandler的两个不同继承: 方式一:直接从ChannelHandlerAdapter类里继承,读取操作从channelRead方法里执行 @Sharable publ

Mybatis学习记录(二)--Mybatis开发DAO方式

mybatis开发dao的方法通常用两种,一种是传统DAO的方法,一种是基于mapper代理的方法,下面学习这两种开发模式. 写dao之前应该要对SqlSession有一个更加细致的了解 一.mybatis的SqlSession使用范围 SqlSessionFactoryBuilder用于创建SqlSessionFacoty,SqlSessionFacoty一旦创建完成就不需要SqlSessionFactoryBuilder了,因为SqlSession是通过SqlSessionFactory生产