动手捣鼓一个log打印调试模块

平时写代码时,总是需要用到打印调试输出,之前每次都是直接使用 printf 函数直接打印的,但是越来越发现很不方便。比如有时我想屏蔽打印调试信息时,总不能回去一点点的把原来的打印代码删除了吧。有时我需要分级别打印时,直接使用 printf 函数打印也不好操作。

在网上我发现了一个打印调试的日志库 EasyLogger ,这个 log 库的功能非常强大,可以满足各种需求了。到时我写文章记录下使用心得。

但是,我其实又不用这么强大的功能,虽然 EasyLogger 移植使用起来也不难,但自己所需要的功能也不用那么多。于是就自己捣鼓一下 log 的调试输出代码。

log打印调试代码

我大概需要的功能就是:

  • 可以打开、关闭调试输出信息
  • 输出信息有过滤机制,比如只打印报错、警告信息,过滤掉一些打印调试信息。输出过滤机制可以使用分级打印,这种方法很常用的,比如 linux 内核的打印信息也是有分级打印的。
  • 做的漂亮点,可以根据输出信息级别,打印信息显示的颜色不一样。

我自己参考了 RT-Thread 写了这部分代码。

其中核心代码就是这部分分级打印代码:

在这里插入图片描述

dbg_log_line 宏定义如下:

在这里插入图片描述

这个宏的第一行代码就是首先打印输出 log 信息的前缀以及设置打印信息的显示颜色,打印的前缀我们可以根据需要自己设置,一般都是设置打印出文件名、行数等等。接着就是打印我们真正的 log 信息,最后一行接着打印换行。

完整的代码如下:

#ifndef __LOG_H__
#define __LOG_H__

#ifdef __cplusplus
extern "C" {
#endif

#include <stdio.h>

/* 日志输出总开关 */
#define DBG_ENABLE

/* 颜色输出开关 */
#define DBG_COLOR

/* 日志打印级别 */
#define DBG_ERROR           0
#define DBG_WARNING         1
#define DBG_INFO            2
#define DBG_LOG             3

/* 设置日志打印级别,级别越高输出的日志信息越多 */
#define DBG_LEVEL         DBG_LOG


#ifdef DBG_ENABLE

/*
 * The color for terminal (foreground)
 * BLACK    30
 * RED      31
 * GREEN    32
 * YELLOW   33
 * BLUE     34
 * PURPLE   35
 * CYAN     36
 * WHITE    37
 */
#ifdef DBG_COLOR
#define _DBG_COLOR(n)        printf("\033["#n"m")
#define _DBG_LOG_HDR(lvl_name, color_n)                    \
    printf("\033["#color_n"m[" lvl_name "/" "<%s:%d>" "] ", __FILE__, __LINE__)
#define _DBG_LOG_X_END                                     \
    printf("\033[0m\n")
#else
#define _DBG_COLOR(n)
#define _DBG_LOG_HDR(lvl_name, color_n)                    \
    printf("[" lvl_name "/" "%s:%d" "] ", __FILE__, __LINE__)
#define _DBG_LOG_X_END                                     \
    printf("\n")
#endif /* DBG_COLOR */


#define dbg_log_line(lvl, color_n, fmt, ...)                \
    do                                                      \
    {                                                       \
        _DBG_LOG_HDR(lvl, color_n);                         \
        printf(fmt, ##__VA_ARGS__);                     	\
        _DBG_LOG_X_END;                                     \
    }                                                       \
    while (0)

#else
#define dbg_log_line(lvl, color_n, fmt, ...)
#endif /* DBG_ENABLE */


/* debug */
#if (DBG_LEVEL >= DBG_LOG)
#define LOG_D(fmt, ...)      dbg_log_line("D", 0, fmt, ##__VA_ARGS__)
#else
#define LOG_D(...)
#endif

/* info */
#if (DBG_LEVEL >= DBG_INFO)
#define LOG_I(fmt, ...)      dbg_log_line("I", 32, fmt, ##__VA_ARGS__)
#else
#define LOG_I(...)
#endif

/* warn */
#if (DBG_LEVEL >= DBG_WARNING)
#define LOG_W(fmt, ...)      dbg_log_line("W", 33, fmt, ##__VA_ARGS__)
#else
#define LOG_W(...)
#endif

/* error */
#if (DBG_LEVEL >= DBG_ERROR)
#define LOG_E(fmt, ...)      dbg_log_line("E", 31, fmt, ##__VA_ARGS__)
#else
#define LOG_E(...)
#endif


#ifdef __cplusplus
}
#endif

#endif /* __LOG_H__ */

在 ubuntu 下测试 log 打印

由于输出的信息颜色,有些终端可能不支持,所以在 ubuntu 下测试。

测试代码其实很简单,就是直接打印信息就行。

#include <stdio.h>
#include "log.h"

int main(void)
{
	LOG_D("***********************log test start***********************");

	LOG_D("hello world...");
	LOG_I("hello world...");
	LOG_W("hello world...");
	LOG_E("hello world...");
	
	LOG_D("***********************log test end***********************");

	return 0;
}

打印输出效果如下:

在这里插入图片描述

可以看到有不同的颜色效果。而且,如果是不支持颜色显示的话,可以关闭颜色显示功能。

在 STM32 上测试 log 打印

重定向 printf

在 MCU 上测试的话,需要有串口的支持。我使用的测试开发板是 STM32F407ZGT6 芯片,关于串口的初始化相关的代码,我直接使用 STM32CubeMX 生成了,这里不多讲。如果你使用的是其他芯片,自己添加初始化串口相关的代码。

初始化完串口之后,我们要想使用 printf 打印函数,需要重定向这个函数是向串口打印输出信息的。

我们只要在工程代码中,重新实现 fputc 这个函数即可。我使用 HAL 库编写的代码如下:

int fputc(int ch, FILE* f)
{
	char a = '\r';
	
    __HAL_UNLOCK(&huart1);
	
	if (ch == '\n')
	{
		HAL_UART_Transmit(&huart1, (uint8_t *)&a, 1, 1);
	}
	HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 1);
	
	return ch;
}

在 MDK 中配合使用 MicroLIB 库

重新实现了 fputc 函数之后,我们还需要配合使用 MDK 提供的 MicroLIB ,这个库其实就是标准的 C 库高度优化而来的,占用资源更少。

在配置串口配置如下:

在这里插入图片描述

在配置框中勾上 Use MicroLib 。一定要选择这个,不选择的话,会导致输出不成功的。

不勾选 MicroLIB 库的方法

如果我们不勾选 Use MicroLib 也想正常打印输出调试信息的话,那就要我们多添加一些代码了。

因为 printf 函数使用了半主机模式,所以直接使用这个函数会导致程序无法运行的,我们需要提前高速编译器不要使用半主机模式。

不勾选 Use MicroLib 库需要添加的完整代码如下:

#if 1
/* 告知连接器不从C库链接使用半主机的函数 */
#pragma import(__use_no_semihosting)

/* 标准库需要的支持数据类型 */
struct __FILE
{
    int handle;
};
 
FILE __stdout;

/**
 * @brief 定义_sys_exit()以避免使用半主机模式
 * @param void
 * @return  void
 */
void _sys_exit(int x)
{
    x = x;
}

int fputc(int ch, FILE* f)
{
	char a = '\r';
	
    __HAL_UNLOCK(&huart1);
	
	if (ch == '\n')
	{
		HAL_UART_Transmit(&huart1, (uint8_t *)&a, 1, 1);
	}
	HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 1);
	
	return ch;
}
#endif

这样添加了上述代码之后,我们就算不够选 Use MicroLib 库也可以正常打印输出日志信息了。

log模块打印测试效果

在 main 函数中,我们添加在 ubuntu 下测试的那几行打印测试代码,然后打开 MobaXterm 终端软件,可以看到如下打印效果:

在这里插入图片描述

可以看到有不同颜色的打印效果,如果不想打印某些信息的级别,修改打印日志输出级别的宏定义就行。

注意:如果是使用常用的串口助手测试工具的话,可能不支持输出信息带颜色的,而且反而会看到一些不需要的颜色编码,这个时候我们可以把颜色输出的宏定义关闭就可以不用输出颜色了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值