首页 > 编程语言 >简单日志宏实现(C++)

简单日志宏实现(C++)

时间:2025-01-19 23:31:08浏览次数:3  
标签:__ format time C++ 简单 LINF 日志 级别

意义:
快速定位程序运行逻辑出错的位置。

背景:
项目在运行中可能会遇到各种问题,而出问题是开发过程中不可避免的一部分。关键在于能够有效地找到,并解决问题

解决问题的方式:

  • GDB调试:

    • 适用于:程序崩溃后的定位。
    • 局限性:逐步调试过程繁琐且耗时较长。
  • 系统运行日志分析:

    • 方法:在程序中任何可能存在逻辑错误的地方输出提示信息。
    • 目的:通过日志快速定位**逻辑问题**的具体位置。
    • 优势:相比GDB调试更为高效,能更快地识别和理解问题所在。

1. 宏定义和日志级别

#define LDBG 0
#define LINF 1
#define LERR 2
#define LDEFAULT LINF
  • LDBG (Debug): 调试级别的日志,用于记录详细的调试信息。
  • LINF (Info): 信息级别的日志,用于记录一般性运行信息。
  • LERR (Error): 错误级别的日志,用于记录严重错误信息。
  • LDEFAULT: 定义了默认的日志级别,当前设置为 LINF即仅输出等于或高于 LINF 的日志信息。

通过设置不同的日志级别,可以控制日志的输出粒度。


2. 日志宏实现

#define LOG(level, format, ...) {\
 if (level >= LDEFAULT){\
 time_t t = time(NULL);\
 struct tm *lt = localtime(&t);\
 char time_tmp[32] = {0};\
 strftime(time_tmp, 31, "%m-%d %T", lt);\
 fprintf(stdout, "[%s][%s:%d] " format "\n", time_tmp, __FILE__, \
__LINE__, ##__VA_ARGS__);\
 }\
}
核心功能解析
  1. LOG(level, format, ...)

    • 这是一个可变参数的宏,用于生成带有特定级别的日志。
    • 参数:
      • level:日志级别,决定日志是否输出。
      • format:格式化字符串,与 printf 风格一致。
      • ...可变参数,与 format 匹配。
  2. 日志级别判断

    if (level >= LDEFAULT)
    
    • 只有当日志级别不低于默认级别 LDEFAULT 时,日志才会输出。
    • 例如,如果 LDEFAULTLINF,则只有 LINFLERR 级别的日志会被打印。
  3. 获取当前时间

    time_t t = time(NULL);
    struct tm *lt = localtime(&t);
    char time_tmp[32] = {0};
    strftime(time_tmp, 31, "%m-%d %T", lt);
    
    • 使用 time() 获取当前时间
      在这里插入图片描述

    • 使用 localtime() 将时间转换为本地时间。
      在这里插入图片描述

    • 使用 strftime() 将时间格式化为字符串,格式为 月-日 时:分:秒%m-%d %T)。

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  1. 格式化日志输出
    fprintf(stdout, "[%s][%s:%d] " format "\n", time_tmp, __FILE__, \
    __LINE__, ##__VA_ARGS__);
    
    • 将日志输出到标准输出 stdout
    • 输出格式:
      • [时间]:如 [01-19 14:23:45]
      • [文件名:行号]:使用预定义宏 __FILE____LINE__ 获取当前文件名和行号。
      • format__VA_ARGS__:用户指定的日志内容,支持 printf 风格的格式化。
      • ❗## 处理__VA_ARGS__

3. 简化的日志宏

#define DLOG(format, ...) LOG(LDBG, format, ##__VA_ARGS__);
#define ILOG(format, ...) LOG(LINF, format, ##__VA_ARGS__);
#define ELOG(format, ...) LOG(LERR, format, ##__VA_ARGS__);
  • DLOG: 调试日志,等价于 LOG(LDBG, ...)
  • ILOG: 信息日志,等价于 LOG(LINF, ...)
  • ELOG: 错误日志,等价于 LOG(LERR, ...)

开发者可以直接使用这些宏记录不同级别的日志,就不需要手动指定日志级别啦。


4. 示例代码

#include "log_macro.h"

int main() {
    ILOG("This is an info log.");
    DLOG("This is a debug log.");
    ELOG("This is an error log: %s", "Critical failure!");

    return 0;
}

输出结果(假设 LDEFAULTLINF):

[01-19 14:23:45][main.c:4] This is an info log.
[01-19 14:23:45][main.c:6] This is an error log: Critical failure!
  • DLOG 的日志没有输出,因为 LDBG < LDEFAULT

5. 优点和意义

  1. 快速定位问题

    • 日志输出包括文件名和行号,无需手动查找代码位置。
    • 时间戳记录了日志发生的时间,便于分析问题的时间线。
  2. 简单易用

    • 宏封装了复杂的日志格式和级别控制,开发者只需调用 DLOGILOGELOG 即可。
  3. 灵活性

    • 默认日志级别可以通过修改 LDEFAULT 轻松调整。
    • 支持可变参数,适应各种格式的日志内容。

6. 改进建议

  1. 日志输出到文件

    • 当前日志输出到标准输出,实际应用中可能需要写入日志文件。可以扩展宏,增加输出目的地的选择。
  2. 线程安全

    • 多线程程序中,日志写入可能会产生竞争。可以结合互斥锁或线程安全的 I/O 函数实现线程安全。
  3. 日志级别动态配置

    • 提供运行时修改日志级别的能力,而不是通过编译时宏定义固定。

这种简单的日志系统一般就可以应对大多数小型项目的调试需求啦

标签:__,format,time,C++,简单,LINF,日志,级别
From: https://blog.csdn.net/2301_80171004/article/details/145249134

相关文章

  • C转C++最全指南
    1.了解C与C++的关系C++是C语言的超集,意味着所有C语言代码在C++中都有效,但C++引入了更多的特性。C++是面向对象的编程语言,而C语言是过程化编程语言。2.基本语法与数据类型变量声明与初始化:C:inta=10;C++:支持类和对象的构造函数、重载等特性。inta=10;输入输......
  • 【C++】了解stack和queue
    目录stack介绍栈的结构栈接口的使用栈的基本题目最小栈栈的弹出压入序列二叉树的分层遍历栈的模拟实现stack.h文件队列的介绍队列的结构队列接口的使用队列的模拟实现priority_queue的介绍和使用接口使用优先级队列的题目应用数组中第k大的数字优先级队列的......
  • C++:PTA L1-086 斯德哥尔摩火车上的题
    L1-086斯德哥尔摩火车上的题上图是新浪微博上的一则趣闻,是瑞典斯德哥尔摩火车上的一道题,看上去是段伪代码:s=''a='1112031584'for(i=1;i<length(a);i++){if(a[i]%2==a[i-1]%2){s+=max(a[i],a[i-1])}}goto_url('www.multisoft.se/'+......
  • C++,设计模式,【目录篇】
    文章目录1.简介2.设计模式的分类2.1创建型模式(CreationalPatterns):2.2结构型模式(StructuralPatterns):2.3行为型模式(BehavioralPatterns):3.使用设计模式的好处参考1.简介设计模式(DesignPatterns)是软件工程中针对常见问题的可重用解决方案。它们不是具体的......
  • Lake Counting(c++)
     AC代码:#include<iostream>usingnamespacestd;chara[105][105];intn,m,cnt;intdx[]={-1,-1,-1,0,1,1,1,0},dy[]={-1,0,1,1,1,0,-1,-1};voiddfs(intx,inty){ a[x][y]='.'; for(inti=0;i<8;i++){ inttx=x+dx[i],ty=y+dy[i]; if(......
  • UE学习日志#3 GAS--ASC源码简要分析1
    嘿我跟您说这坑一点也不大,AbilitySystemComponent.h也就两千行,.cpp也就三千多,乐凡事要一点点来,我也就按每天的进度分p了。1类的继承关系和修饰符先看这两行,为了方便看我加了换行UCLASS(ClassGroup=AbilitySystem,hidecategories=(Object,LOD,Lighting,Transform,Sockets......
  • 现代C++软件架构--架构风格
    架构风格有状态风格和无状态风格有状态软件的行为依赖于其内部状态。我们以Web服务为例,如果服务记住了自己的状态,该服务的使用者可以在每个请求中发送更少的数据,因为该服务记住了这些请求的上下文。然而,虽然节省了发送请求大小和带宽数据的开销,但在Web服务方面有一项隐藏......
  • 【C++】一个完整的位姿(Pose)计算系统,主要用于处理三维空间中的坐标系变换
    1.旋转矩阵计算给定旋转角度(RX=ϕRX=\phiRX=ϕ)、(......
  • 《 C++ 点滴漫谈: 二十一 》sizeof 不止是大小:C++ 高效编程背后的核心
    摘要sizeof关键字是C++中的重要工具,用于在编译期确定类型或对象的大小。本文全面解析了sizeof的基本概念、常见用途以及底层实现原理,帮助开发者更好地理解其在内存管理、数据对齐和性能优化中的作用。此外,文章还对sizeof和C++11引入的alignof的关系进行了探讨,并......
  • 【华为OD-E卷 - 第k个排列 100分(python、java、c++、js、c)】
    【华为OD-E卷-第k个排列100分(python、java、c++、js、c)】题目给定参数n,从1到n会有n个整数:1,2,3,…,n,这n个数字共有n!种排列。按大小顺序升序列出所有排列的情况,并一一标记,当n=3时,所有排列如下:“123”“132”“213”“231”“312”“321”给......