当前位置: 首页 > news >正文

使用C++实现日志(1)

一、使用 C++ 实现日志系统

在项目开发过程中,调试器(Debugger)是便捷的调试工具,但日志系统更是最廉价、最便捷的错误定位工具。当项目交付运行后,日志系统成为程序在运行环境中的 “健康监控仪”—— 当程序执行出错或业务逻辑出现问题时,我们将依赖日志快速定位问题根源。

1.1 开发日志系统的目的

开发日志系统主要为了实现以下目标:

  1. 追踪程序执行的过程;
  2. 追踪数据的变化;
  3. 快速定位问题的根源;
  4. 数据统计和性能分析;
  5. 为以后开发其他项目提供支持。

1.2 日志系统的功能需求

1. 日志消息级别

日志消息分为六个级别,按严重程度从高到低依次为:
FATAL(致命错误)ERROR(错误)WARN(警告)INFO(信息)DEBUG(调试)TRACE(跟踪)

2. 日志消息格式示例

2022/09/19 02:07:48 720332Z 234672 INFO Test_Logger.cpp func  20 - func info 
2022/09/19 02:07:48 720344Z 234344 INFO Test_Logger.cpp func  23 - func info 

格式字段说明:
日期 时间 微秒 线程ID 级别 文件名 函数名 行号 正文

3. 日志消息格式要求

  1. 每条日志占一行,便于使用awksedgrep等命令行工具联机分析;
  2. 时间戳精确到微秒;
  3. 始终使用 GMT 时区(标记为Z),避免跨洲分布式系统的时区转换问题,便于追查事件顺序;
  4. 打印线程 ID,用于分析多线程程序时序及检测死锁;
  5. 打印日志级别,在线查错时可优先关注ERROR级日志,加速定位问题;
  6. 打印源文件名、函数名、行号,避免修复 bug 时搞错对象。

4. 记录日志的方式

支持两种输出方式:

  • 终端显示
  • 写入日志文件

5. 滚动日志(rolling log)

日志文件必须支持滚动功能,用于简化日志归档并防止单个文件过大占满硬盘空间。

  • 滚动原理:通过设定规则(最大文件大小、最多保存天数),超过阈值后删除较早记录。
  • 滚动条件
    • 文件大小(如每写满 1GB 切换到新文件);
    • 时间(如每天零点新建日志文件,无论前一个文件是否写满)。

6. 日志级别设置

输出日志时,仅级别高于配置中规定级别的信息会被输出。无需修改代码即可灵活配置不同场景下的日志输出内容,便捷高效。

7. Log 文件名格式

文件名组成规则:
basename + now + hostname + pid + ".log"

  • basename:基础名,由用户指定(通常为应用程序名);
  • now:当前时间,格式为"%Y%m%d-%H%M%S"
  • hostname:主机名;
  • pid:进程号(通过getpid从 OS 获取);
  • 各部分用.连接。

示例(basename 为test_log_mt):
test_log_mt.20220218-134000.ubuntu.12426.log

#include "Logger.hpp"tulun::LogFile* plog = nullptr;void writefile(const string& info)
{plog->append(info);
}void flushfile()
{plog->flush();
}int main()
{tulun::Logger::setOutput(writefile);tulun::Logger::setFlush(flushfile);plog = new tulun::LogFile("yhping", 1024 * 1024 * 1000);for (int i = 0; i < 1000000; ++i){LOG_INFO << "main" << i;}return 0;
}
http://www.dtcms.com/a/312075.html

相关文章:

  • 疏老师-python训练营-Day33 MLP神经网络的训练
  • AbstractExecutorService:Java并发核心模板解析
  • 深入 Go 底层原理(一):Slice 的实现剖析
  • 二叉树链式结构的实现
  • lesson31:Python异常处理完全指南:从基础到高级实践
  • 乌鸫科技前端二面
  • Go语言中的闭包详解
  • OpenCV学习 day3
  • stm32是如何实现电源控制的?
  • 如何防止内存攻击(Buffer Overflow, ROP)
  • 髋臼方向的定义与测量-I
  • u-boot启动过程(NXP6ULL)
  • android studio 安装Flutter
  • WD5208S,12V500MA,应用于小家电电源工业控制领域
  • Kubernetes 构建高可用、高性能 Redis 集群实战指南
  • #C语言——学习攻略:探索字符函数和字符串函数(一)--字符分类函数,字符转换函数,strlen,strcpy,strcat函数的使用和模拟实现
  • 数据库理论
  • 【MATLAB】(五)向量
  • 变量筛选—随机森林特征重要性
  • windows@Path环境变量中同名可执行文件优先级竞争问题@Scoop安装软件命令行启动存在同名竞争问题的解决
  • 解决 InputStream 只能读取一次问题
  • Java语言核心特性全解析:从面向对象到跨平台原理
  • Docker--将非root用户添加docker用户组,解决频繁sudo执行输入密码的问题
  • 【动态规划 | 子序列问题】子序列问题的最优解:动态规划方法详解
  • RK628F HDMI-IN调试:应用接口使用
  • Vulnhub ELECTRICAL靶机复现(附提权)
  • QPainter::CompositionMode解析
  • junit总@mockbaen与@mock的区别与联系
  • flutter分享到支付宝
  • Linux进程控制核心:创建·等待·终止·替换