一个简单的c++日志库

  1. 目录
  2. 为什么写
  3. 实现
    1. 特点
    2. 架构图
    3. 优化
    4. 使用示例
    5. 测试
  4. 参考

目录

为什么写

现在已经有很多的开源成熟日志库(spdlog,log4cpp,boost.log等),为什么我还要重复造轮子?

  • 最主要的一点我是想充实一下我的业余时间,而且日志与业务和领域都没有关系,只要是写c++的都可以使用。
  • 开源的库代码量大,功能也很强大,给我一种比较“重”的感觉,我想写一个简单一点的。
  • 使用统一的格式和日志接口(spdlog提供了很多可以写日志的入口,而且可以自定义日志格式,对我这种选择困难症来说很难做出决定)
  • 写代码是件好玩的事儿,我为了玩。

实现

代码仓库

特点

  • 使用简单(可以看下面使用示例)
  • 速度很快
  • 输出
    • 控制台输出(不同等级日志输出颜色不同,可以选择开关)
    • 文件输出(日志文件按天和文件大小分割)
    • 不同输出可以设置不同的等级
  • 日志级别可在运行时修改
  • 使用fmt库进行格式化
  • 支持异步模式(可选择)

架构图

dflog

优化

  • 格式化
    • 格式化方式

      格式化是一件比较费时的步骤,开始我采用的是sprintf进行格式化,后来改为了fmt库进行格式化,不过我在测试中发现速度并没有得到提升。

    • 时间格式化

      每次都对时间进行格式化会增加不少时间消耗,我把在同一秒内对日志时间格式给缓存下来,如果接下来需要格式化对日志时间还在该秒内,就省去了秒级对时间格式化操作。这确实提升了不少的性能。

  • 输出

    fflush频率控制,可以设置缓存刷新等级(比如当是warn等级日志或缓存满了才刷新到文件),来减少io操作。有明显的速度提升
    这样可能会在程序突然崩溃时丢掉日志记录,不过丢掉的是等级低的日志,影响可能不大

  • 异步

    写入和格式化都比较费时,于是我把这两个步骤和日志调用分离,采用异步格式化写入,日志调用时把日志记录push到日志队列里面,写入线程不断的取日志队列记录进行格式化和写入。
    测试的时候我发现这并不能提升速度,反而速度更慢了。而且当日志量很大的时候,日志队列会爆掉而丢弃数据(可以把队列设置的尽可能大,但这并不是一个解决办法)。

使用示例

#include <dflog/dflog.h>

void exampleLOG()
{
    /* 日志, 使用类似于print输出 */
    LOG(INFO, "* * * * * * * * * LOG example * * * * * * * * * *");
    LOG(TRACE, "i am trace log ({}), ({:.2})", 123, 2.3);
    LOG(DEBUG, "i am debug  log ({}), ({})", 123, 3.3123);
    LOG(INFO, "i am debug  log ({:05}), ({:.3})", 123, 3.3123);
    LOG(INFO, "i am info log ({})", static_cast<long int>(123));
    LOG(WARN, "i am warn log [{:#5}]", 100);
    LOG(ERROR, "i am error log {}", "hello wrold");
    LOG(CRITICAL, "i am critical log ");
    LOG(INFO, "* * * * * * * * * * * * * * * * * * * * * * * * *");
}

void exampleLOGF()
{
    /* 日志, 使用类似于print输出 */
    LOGF(INFO, "* * * * * * * * LOGF example * * * * * * * * * * *");
    LOGF(TRACE, "i am trace log (%d), (%.2f)", 123, 2.3);
    LOGF(DEBUG, "i am debug  log (%d), (%f)", 123, 3.3123);
    LOGF(INFO, "i am info log (%ld)", static_cast<long int>(123));
    LOGF(WARN, "i am warn log %d", 100);
    LOGF(ERROR, "i am error log %s", "hello wrold");
    LOGF(CRITICAL, "i am critical log ");
    LOGF(INFO, "* * * * * * * * * * * * * * * * * * * * * * * * *");
}

void init()
{
    /* 
     * 初始化日志
     * 1. 可以添加不同的定向log输出
     * 2. 可以设置异步或同步模式
     * */
    dflog::InitLog("./example.log", dflog::loggerOption::FILELOG | dflog::loggerOption::CONSOLE,dflog::Method::SYNC);
    dflog::SetLevel(TRACE); /* default DEBUG */
    /* 不同的log输出, 可以控制不同的日志等级 */
    // dflog::SetLevel(DEBUG, dflog::loggerOption::FILELOG | dflog::loggerOption::CONSOLE); /* 默认所有日志等级改动 */;

    // dflog::SetFlushLevel(WARN) /* 默认每次刷新(TRACE) */;
}


int main(void)
{
    init();
    exampleLOG();
    exampleLOGF();

    return 0;
}

输出格式

[2020-08-04 20:00:48.530] [INFO] [12859] [example.cpp](17): i am info log

测试

测试用例写在代码仓库里面,可以进入代码仓库查看tests文件夹。

速度上的测试用例我只测试了一部分情况,只输出如下内容

[2020-08-04 20:00:48.530] [INFO] [12859] [example.cpp](17): hello wrold (1)

hello world 后面括号里为一个整型数值。
每秒写入200k多的日志记录,与spdlog输出相同内容的速度不相上下。

测试机配置

2  Intel(R) Xeon(R) Platinum 8163 CPU @ 2.50GHz

参考


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 245292011@qq.com

文章标题:一个简单的c++日志库

字数:1.2k

本文作者:常丁方

发布时间:2020-08-04, 19:38:21

最后更新:2021-08-25, 18:31:45

原始链接:http://changdingfang.com/2020/08/04/study/dflog/
×

喜欢就点赞,疼爱就打赏

资源