网络编程的日志系统

前言

本文是我用来学习之用,有错麻烦提一下,感谢

为什么用日志系统

平常我们写代码调试可能直接print或者打断点,但是在实际生产过程中,大多数情况不可能用这两个,比如一些无法还原现场的小概率的错误,只能在业务逻辑处写下日志,往后查询日志来排查错误,更多参照参考资料[1]

高性能日志系统的设计

  • 日志的格式,即每条日志的内容,为了方便调试可以加入线程号,调用栈,时间,文件名,代码行数,调用的函数等,更多见参考资料[1]和[2],有些格式化内容可能可以通过编译器计算出来,比如字符串大小,以保证运行时开销,更多TODO
  • 日志的级别设计,见参考资料[1]
  • 日志打印位置:一般是文件,最好不要往网络中打印,这个文章只谈往文件写
  • 日志的类别:保证持久性的write ahead log如数据库的日志;用来排查错误的diagnostic logging,这里只谈后者

日志是被业务线程(被称为前端)使用的,即业务线程需要调用日志模块来写入日志,有以下选择问题

  1. 同步写和异步写,同步即线程调用LOG<<"日志信息"的同时调用往磁盘中写入,同步,写入磁盘等待耗时大,造成调用的业务线程阻塞,所以应该采用异步方案,异步方案即需要多线程的处理,和前后端分离
  2. 前后端分离的必要性:异步要求前后端分离,前端负责内容的格式化与相关数据(线程、时间、调用栈)的收集,后端负责持久化日志。最直观的做法就是一个stringstream做前端,一个ostream(fstream/cout)做后端,后端作为一个线程执行阻塞的日志写入磁盘操作;并且前后端分离还有一个好处:模块化,只要保证接口格式,前端的输入格式修改不会影响到后端的修改,方便以后替换前端模块;
  3. 一个服务端程序往多个文件写和一个文件写 : 多日志文件不利于排查,故选用全局一个文件(来自陈硕的书),又因为日志作用域:程序中每个线程应该都能使用到,所以要采用单例模式来实现这个日志模块,单例模式看我另一篇:https://blog.csdn.net/ptgood/article/details/108053603

整体实现

为了实现异步写(前端非阻塞写),在日志模块中增加一个缓冲,所有线程把日志往这个模块的缓冲写,模块异步写buffer到一个总文件;即下图,这样写入磁盘的时间就由日志模块承担,前端就实现了非阻塞写入日志(说的是磁盘写入的阻塞,不是锁争用的阻塞)

这里就像一个生产者消费者模型,多个生产者(业务线程)生产日志,日志线程负责把日志写入文件中

且刚才提到,日志模块需要是全局能使用的(每个业务线程都能使用到),且是唯一的(只写入一个文件),这就要用到设计模式的单例模式了,这里略过

接着还有个问题,异步缓冲写多线程会争用锁,毕竟只有日志一个缓冲,这样也会又性能消耗,所以延伸出个无锁异步缓冲的方案是参考资料[4]中的,让每个业务线程都单独写一个buffer,而后端日志线程负责去拉取消费,这种方案的详细实现见参考资料[4],或者是陈硕书中提到的java的concurrentHashMap那样用多个桶

代码实现

最简单版见参考资料[1]

参考资料[3]里给出了代码,上面提到的第一种方案的变种,也就是用加缓冲的日志模块,模仿了muduo,它这的缓冲利用了STL的list来实现,也是个单例模式的例子

muduo的实现

muduo的日志系统采用了有锁的异步缓冲的方案,而buffer采用了双buffer,这样前端就不用等后端把buffer写完才能继续消费了,而buffer的类型采用了固定大小的std::vector<char>,注意这里的buffer要和muduo的用来读写的buffer类和这个日志的buffer区分开,关于muduo的具体日志模块的实现,可以看下参考资料[5]和[6]的解释

更多

  1. 无锁队列(FIFO)也值得考虑
  2. 异步后端如果太慢可能会积压数据,可以考虑ring buffer。
  3. Logger要设计多种level,对level做筛选是要放在前端还是后端……
  4. 有一些功能不需要加入日志库里,直接写脚本处理就可以,比如日志保留时间

参考资料

  1. [1](https://zhuanlan.zhihu.com/p/100082717)
  2. [2](https://blog.csdn.net/u011228842/article/details/84000269)
  3. [3](https://mp.weixin.qq.com/s?__biz=MzU2MTkwMTE4Nw==&mid=2247486888&amp;idx=1&amp;sn=cd321d522175d99033aefade3d29c1f3)
  4. [4](https://blog.csdn.net/yusiguyuan/article/details/15081295)上面的图都是这里来的,还提到了主动fetch的方法
  5. [5](https://blog.csdn.net/luotuo44/article/details/19252535)
  6. [6](https://blog.csdn.net/luotuo44/article/details/19254157)
  7. [7](陈硕的书)
  8. 关于muduo多线程日志的疑惑? - 陈硕的回答 - 知乎 https://www.zhihu.com/question/60491168/answer/177571929
  9. C++如何写一个简单Logger? - XZiar的回答 - 知乎 https://www.zhihu.com/question/293863155/answer/488053591

TODO

  1. cpp设计日志系统https://zhuanlan.zhihu.com/p/100082717
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值