C++使用工具进阶(LOG输出、堆栈跟踪、代码结构、code review)

0. 简介
对于C++,无论是大学生还是算法工程师都是非常需要学习并使用的一门语言,而C++不像python、rust一样简单好用。不单单是在嵌套复杂代码后的逻辑还是各种类和堆栈的管理,都是非常头疼的问题。一般来说对于LOG类很多都是使用GLOG、而堆栈跟踪一般是基于GDB。而这里我们将开拓大家眼界,从另一个角度来说一些小而美的东西。这里整合一些网上非常好的博客,并结合自己的一些理解给大家整理一个非常通用的工具,也欢迎各位关注引用文章的博主。

1. RLOG
在现代软件开发中,日志记录系统是不可或缺的一部分。它不仅可以帮助开发人员在应用程序中定位和解决问题,还可以用于监控、性能分析、安全审计等方面。本文将介绍日志记录系统的基本概念、重要性以及如何构建一个高效的日志记录系统。

1.1 构建日志记录系统的关键步骤

  • 日志级别与分类:日志级别包括调试(Debug)、信息(Info)、警告(Warning)、错误(Error)等。不同级别的日志用于不同目的,例如调试时使用调试日志来追踪代码执行,而错误日志用于记录严重的问题。选择合适的日志级别可以避免日志信息过于冗杂或过于稀少。
  • 日志格式与结构:一个良好的日志格式应包括时间戳、日志级别、模块/组件名以及具体的日志消息。统一的格式使得日志易于阅读和分析。例如:[时间戳] [日志级别] [模块名] - 日志消息
  • 异步日志写入:为避免阻塞应用程序的正常执行,可以采用异步日志写入方式。日志消息被缓冲并在适当的时机写入磁盘,从而提高应用程序的性能。
  • 日志存储与滚动:考虑使用滚动策略,定期归档或删除旧的日志文件,以免日志文件无限增大。选择适当的存储方式,如本地文件、数据库或云存储。
  • 上下文信息:除了基本的日志信息外,还可以在日志中添加上下文信息,如用户ID、请求ID、会话ID等。这些信息有助于在复杂的分布式系统中跟踪请求流程。
  • 敏感信息与安全:避免将敏感信息(如密码、API密钥)写入日志。同时,实施权限控制,限制对日志文件的访问,确保敏感信息不被滥用。
  • 日志分析与可视化:利用日志分析工具或平台,对日志进行聚合、搜索和可视化分析。这有助于发现模式、趋势以及潜在问题。

1.2 Rlog组件
Rlog作为一款高性能的纯C语言日志组件,为开发人员提供了一种轻松、灵活且可定制的日志记录解决方案。对于Rlog而言

  • 它支持用户自定义输出端点(例如:串口终端、网络中断、Flash…),输出端点以插件形式自定义扩展。
  • 日志内容可包含日志等级、时间戳、行号,函数信息,文件信息;
  • 支持多种操作系统(RT-Thread、Linux…),也支持裸机平台;
  • 日志输出支持:printf原始格式,日志等级输出,hexdump输出;
├── example│   ├── rlog_linux_adapter.c        /* linux环境下的适配接口 */│   └── rlog_rtt_adapter.c          /* rt-thread环境下的适配接口 */├── include/│   ├── rlog_adapter.h              /* rlog适配描述 */│   └── rlog.h                      /* rlog对外接口 */├── main.c                          /* rlog的测试样例 */├── Makefile                        /* linux环境rlog构建Makefile */├── plug-in                         /* 输出端点插件的存放路径 */├── SConscript                      /* rt-thread环境rlog构建脚本 */└── src    ├── rlog.c                      /* rlog核心代码 */    ├── rlog_def.h                  /* rlog核心代码使用的定义 */    └── rlog_utils.c                /* rlog使用的C库接口 */

1.3 灵活配置与使用
1.3.1 静态配置:

  1. 静态配置采用宏定义的方式,用户可直接修改rlog_adapter.h头文件的宏定义,就可以修正相关配置;
  2. 静态配置的管控权限比动态配置的高,例如:静态配置设置日志输出总开关为关闭,动态配置设置日志输出使能,日志已经无法输出。

配置描述如下:

/* Enable log output */#define RLOG_OUTPUT_ENABLE              1/* Set log output level, rang: from RLOG_LEVEL_ASSERT to RLOG_LEVEL_VERBOSE */#define RLOG_OUTPUT_LEVEL               RLOG_LEVEL_VERBOSE/* Enable log color */#define RLOG_COLOUR_ENABLE              1/* Enable log color */#define RLOG_TIME_ENABLE                1/* Support log include directory */#define RLOG_DIRECTORY_ENABLE           1/* Support log include funtiong name */#define RLOG_FUNCTION_ENABLE            1/* Support log include line number*/#define RLOG_LINE_ENABLE                1/* Buffer size for every line's log */#define RLOG_LINE_BUFF_LEN              128/* Output line number max length */#define RLOG_LINE_NUM_SIZE              5/* Output newline sign */#define RLOG_NEWLINE_SIGN               "\r\n"/* Enable assert check */#define RLOG_ASSERT_ENABLE              1/* Log function. default FDB_PRINT macro is printf() */#define RLOG_PRINT(...)                 printf(__VA_ARGS__)

1.3.2 动态配置:

  1. 动态配置采用接口的方式,用户通过调用rlog.h头文件提供的接口设置;
  2. 动态配置的管控权限比静态配置的低,例如:静态配置设置日志输出总开关为关闭,动态配置设置日志输出使能,日志已经无法输出。
** * RLog output enable *  * @param enable true: enable output, false: disable output  */void rlog_enable(bool enable);/** * RLog output color enable *  * @param enable true: enable output color, false: disable output color */void rlog_color_enable(bool enable);/** * RLog level output format setting *  * @param level  log level * @param format log format */void rlog_level_fmt_set(rlog_lvl_t level, int format);/** * RLog level output format setting *  * @param level  log level * @param format log format *  * @return result true: supported format, false: unsupported format */bool rlog_level_fmt_get(rlog_lvl_t level, int format);/** * RLog filter the content of the log level *  * @param level  log level */void rlog_level_filter_set(rlog_lvl_t level);

1.3.3 Rlog适配
不同平台的适配方式不同,所以为rlog核心层提供了统一的接口,适配接口如下:

static pthread_mutex_t mutex;void rlog_lock(void){    pthread_mutex_lock(&mutex);}void rlog_unlock(void){    pthread_mutex_unlock(&mutex);}char *rlog_get_time(void){#define TIME_STR_SIZE       32    static char time_str[TIME_STR_SIZE] = {0};    time_t tmp;    struct tm *timp;    time(&tmp);       timp = localtime(&tmp);    memset(time_str, 0, TIME_STR_SIZE);    rlog_snprintf(time_str, TIME_STR_SIZE, "%04d-%02d-%02d %02d:%02d:%02d",                                 (1900 + timp->tm_year), (1 + timp->tm_mon), timp->tm_mday,                                timp->tm_hour, timp->tm_min, timp->tm_sec);    return time_str;}void rlog_output(const char *log, uint16_t len){    RLOG_PRINT("%.*s", len, log);}void rlog_adapter_init(void){    pthread_mutex_init(&mutex, NULL);}void rlog_adapter_deinit(void){    pthread_mutex_destroy(&mutex);}

1.3.4 Rlog 使用
日志记录方式

//level:日志级别,log:日志内容  rlog.log(level, log);//自定义日志参数信息const debugObj={        info:'Debug信息',        module:'视图1',        debug:{'cardData':cardData},        codeline:67,        file:'view_overview.jsx'}rlog.log('info',"可以只输入一条文字信息");rlog.info('可以直接按级别输出信息');rlog.log('debug',debugObj);//预设日志方法rlog.getReactDrawTime('视图');   //获取react模块渲染时间rlog.event(e);      //输出一条event日志

2. Backward-cpp

C/C++编程的同学经常会遇到程序出现(Segmentation fault (core dumped))段错误,一般的解决方法就是使用gdb的backtrace来进行检查。而Backward 会将堆栈信息打印出来,并且源码本质上只有backward.hpp文件,集成到自己的程序中非常方便,如果加入backward.cpp文件一起编译,则自己代码中不需要调用Backward-cpp中的函数,非常方便。

2.1 编译Backward-cpp

git clone https://github.com/bombela/backward-cpp.git

我们可以看到主文件就只有backward.hpp和backward.cpp文件,测试文件有下面这些:

.test├── rectrace.cpp├── select_signals.cpp├── stacktrace.cpp├── suicide.cpp├── test.cpp├── test.hpp└── _test_main.cpp

点击C++使用工具进阶(LOG输出、堆栈跟踪、代码结构、code review) - 古月居可查看全文

  • 14
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值