【CC++开源库】单片机嵌入式中的C语言日志库
日志系统在系统开发和调整过程中的重要性,大家应该都清楚,特别是项目出问题之后,却没有日志可以帮忙定位问题,就非常令人痛苦。
因为我们不可能一直通过调试器去单步调试程序,所以设备的运行日志显得尤为重要。
通常我们对日志有这些要求:
- 不同的日志级别(
Debug
,Warning
,Info,
Error
,Fatal
); - 日志打印要和
printf
一样简单易用; - 能够设置日志级别;
- 占用空间小;
- 可配置,甚至可以禁用日志;
- 基于不同日志级别,支持颜色高亮;
- 可以自定义配置,时间戳;
- 支持RTOS;
以上是比较基本的功能,但是在嵌入式设备中,有的时候我们希望可以保存设备的运行日志,我们需要以下的一些功能;
- 支持多种访问方式,比如串口终端,保存到嵌入式文件系统中;
- 支持shell命令行通过串口终端进行访问;
以上这些需求不一定会全部实现。
除了常用的log4c
,log4cpp
,下面给大家推荐3个非常不错的开源日志库,比较适合用在单片机的项目中。从开始的轻量,到后面的功能丰富,最后一个很强大,所以请耐心看到最后。
我们平时开发中,log打印必不可少,仅仅使用printf,则log信息不好定位。一些开源稳定、成熟的log模块功能往往比较强大,而我们可能又不需要那么多功能。
这里简单分享一个我自己用的一个极简的log模块:log颜色可设置、带时间戳、文件、行号、函数。
这个log模块仅包含log.h与log.c两个文件。
log模块代码
log.h:
#ifndef LOG_H
#define LOG_H#ifdef __cplusplus
extern "C" {
#endif#define LOG_BUF_SIZE 1024typedef long long (*get_sys_time_ms_def)(void);enum log_color
{COLOR_NULL = 0,RED = 1,GREEN = 2,YELLOW = 3,BLUE = 4
};void log_print(enum log_color color, const char *file, int line, const char *func, const char* fmt, ...);
void log_time_register(get_sys_time_ms_def p_get_sys_time_ms);#define LOG_D(...) log_print(BLUE, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__)#ifdef __cplusplus
}
#endif
#endif
log.c:
#include <stdio.h>
#include <stdarg.h>
#include "log.h"static long long default_get_sys_time_ms(void)
{return (long long)0;
}static get_sys_time_ms_def s_get_sys_time_ms = default_get_sys_time_ms;void log_time_register(get_sys_time_ms_def p_get_sys_time_ms)
{s_get_sys_time_ms = p_get_sys_time_ms;
}void log_print(enum log_color color, const char *file, int line, const char *func, const char* fmt, ...)
{va_list ap;char buf[LOG_BUF_SIZE] = {0};long long time = s_get_sys_time_ms();va_start(ap, fmt);vsnprintf(buf, sizeof(buf), fmt, ap);va_end(ap);switch(color){case COLOR_NULL:printf("<%lld ms>[%s:%d %s] %s ", time, file, line, func, buf);break;case RED:printf("[31m<%lld ms>[%s:%d %s] %s[0m", time, file, line, func, buf);break;case GREEN:printf("[32m<%lld ms>[%s:%d %s] %s[0m", time, file, line, func, buf);break;case YELLOW:printf("[33m<%lld ms>[%s:%d %s] %s[0m", time, file, line, func, buf);break;case BLUE:printf("[34m<%lld ms>[%s:%d %s] %s[0m", time, file, line, func, buf);break;default:break;}
}
其中,默认打印ms级的系统时间。因为不同的平台(Linux、Windows、STM32等),获取系统时间的方式都不一样。
使用时,再根据不同的平台自己定义一个获取系统时间的函数,以注册的方式进行绑定。不注册获取时间函数也不影响使用,时间戳打印为0。
log模块测试
1、Linux平台
log_test.c:
#include <stdio.h>
#include <sys/time.h>
#include "log.h"static long long linux_get_sys_time_ms(void)
{long long time_ms = 0;struct timeval tv;gettimeofday(&tv, NULL);time_ms = (long long)tv.tv_sec * 1000 + tv.tv_usec / 1000;return (long long)time_ms;
}int main(void)
{log_time_register(linux_get_sys_time_ms);char ch = 'a';char str[10] = "ZhengN";float float_val = 10.10;int num = 88;double double_val = 10.123456;LOG_D("字符为 %c
", ch);LOG_D("字符串为 %s
" , str);LOG_D("浮点数为 %f
", float_val);LOG_D("整数为 %d
" , num);LOG_D("双精度值为 %lf
", double_val);LOG_D("八进制值为 %o
", num);LOG_D("十六进制值为 %x
", num);return 0;
}
编译,运行:
第18行屏蔽掉:
2、Windows平台
log_test.c:
#include <stdio.h>
#include <windows.h>
#include "log.h"static long long win_get_sys_time_ms(void)
{long long time_ms = 0;time_ms = GetTickCount();return time_ms;
}void test(void)
{LOG_D("Hello world
");
}int main(void)
{log_time_register(win_get_sys_time_ms);char ch = 'a';char str[10] = "ZhengN";float float_val = 10.10;int num = 88;double double_val = 10.123456;LOG_D("字符为 %c
", ch);LOG_D("字符串为 %s
" , str);LOG_D("浮点数为 %f
", float_val);LOG_D("整数为 %d
" , num);LOG_D("双精度值为 %lf
", double_val);LOG_D("八进制值为 %o
", num);LOG_D("十六进制值为 %x
", num);test();return 0;
}
编译,运行:
rxi_log
项目地址:https://github.com/rxi/log.c
基于 C99 实现的简单日志库,具体输出如下所示;
image-20211204142024466
具体用法
将源码中的log.c
和log.h
集成到你的项目中即可,需要打印日志的话,调用下面的API即可,如下所示;
log_trace(const char *fmt, ...);
log_debug(const char *fmt, ...);
log_info(const char *fmt, ...);
log_warn(const char *fmt, ...);
log_error(const char *fmt, ...);
log_fatal(const char *fmt, ...);
除了这些API,还有log_set_quiet
,log_set_lock
,LOG_USE_COLOR
等等,详情请看原项目。
ulog
项目地址:https://github.com/rdpoor/ulog
uLog 为嵌入式微控制器或任何资源有限的系统提供结构化的日志记录机制。它继承了流行的 Log4c
和 Log4j
平台背后的一些概念,但开销更低。
uLog 的一些特点:
- uLog 易于集成到几乎任何环境中,由一个头文件和一个源文件组成,并且是用纯 C 编写的。
- uLog 提供熟悉的严重级别(CRITICAL、ERROR、WARNING、INFO、DEBUG、TRACE)。
- uLog 支持多个用户定义的输出(控制台、日志文件、内存缓冲区等),每个输出都有自己的报告阈值级别。
- uLog 是具有最小依赖性的“积极独立”,仅需要 stdio.h、string.h 和 stdarg.h。
- 当您不使用 uLog 时,它不会妨碍您:如果 ULOG_ENABLED 在编译时未定义,则不会生成日志记录代码。
- uLog 已经过很好的测试。有关详细信息,请参阅随附的 ulog_test.c 文件。
color coding
EasyLogger
项目地址:https://github.com/armink/EasyLogger
TextColor
这个项目我用了很长时间,强烈推荐,是RT-Thread大佬的作品,已经集成到RTOS的内部了,支持的功能非常丰富,基本满足各种开发的需求。
特点如下:
- 轻量,ROM<1.6K, RAM<0.3K;
- 支持多种访问模式(例如:终端、文件、数据库、串口、485、Flash…);
- 日志内容可包含级别、时间戳、线程信息、进程信息等;
- 线程安全,并支持 异步输出 及 缓冲输出 模式;
- 支持多种操作系统(RT-Thread、UCOS、Linux、Windows…),也支持裸机平台;
- 日志支持 RAW格式 ,支持 hexdump ;
- 支持按 标签 、 级别 、 关键词 进行动态过滤;
- 各级别日志支持不同颜色显示;
- 扩展性强,支持以插件形式扩展新功能。
以上只是这个项目的其中一部分,具体可以参考项目地址。
总结
在单片机/嵌入式上使用的C语言日志库,一般来说,要求该日志库不能依赖出C语言标准库之外的库,因此这也决定了在嵌入式领域的C语言日志库不可能有非常丰富的功能。
如果只是想有一个比printf功能更强大的打印,那么可以考虑用 rxi_log。
如果想将打印输出到串口,或者嵌入式文件系统中,那么建议适配 EasyLogger。
一般在单片机/嵌入式领域,都是裸机或者RTOS,如果是嵌入式Linux操作系统,那就可以使用一些更加强大的日志系统,比如zlog日志系统模块基础、C语言实现一个日志模块、zlog日志模块基础。
【CC++开源库】单片机嵌入式中的C语言日志库相关推荐
- 【C/C++开源库】单片机/嵌入式中的C语言日志库
日志系统在系统开发和调整过程中的重要性,大家应该都清楚,特别是项目出问题之后,却没有日志可以帮忙定位问题,就非常令人痛苦. 因为我们不可能一直通过调试器去单步调试程序,所以设备的运行日志显得尤为重要. ...
- 【Android NDK 开发】NDK 交叉编译 ( Ubuntu 中交叉编译动态库 | Android Studio 中配置使用第三方动态库 )
文章目录 I . 动态库 与 静态库 II . 编译动态库 III. Android Studio 使用第三方动态库 IV . Android Studio 关键代码 V . 博客资源 I . 动态库 ...
- 小结两种在Python中导入C语言扩展库的方法
小结两种在Python中导入C语言扩展库的方法 分类: Pythoner2009-08-18 20:44 2563人阅读 评论(1) 收藏 举报 python扩展c语言importstring 一种是 ...
- Go语言日志库zerolog
Go语言日志库zerolog 在开发大型项目时,将日志进行结构化以提高可读性.可查询性和速度是非常重要的. 为什么你选择不使用其他结构化日志库,如logrus或zap? Zerolog 是一款高性能且 ...
- Linux-C 简单的C语言日志库
Linux-C 简单的C语言日志库 一.简述 记--C语言实现的简单的日志库,可循环覆盖滚动记录日志文件,达到限制就另记一个日志文件,可控制日志文件个数,可控制日志文件大小. 打包下载 ...
- WLog日志库:c++ 高拓展、高性能日志库
日志库实现 该日志库是我借鉴sylar和muduo网络库所研究出来的具有高扩展性和高性能的跨平台的日志库.该日志库使用流式输出,只支持日志输出到文件,原因是网络io很不稳定,基本没有见过利用网络传输进 ...
- 2015计算机二级c语言题库,2015年计算机二级C语言题库找题目录
2015年计算机二级C语言题库找题目录 找题目录 第01套:int fun(___1___ *std) 第02套:void WriteText(FILE ___1___) 第03套: fprintf( ...
- c语言百科园题库及答案,百科园C语言试题库.doc
... 第一章 1.以下叙述中错误的是( )B.C语言编写的每个函数都可以进行独立编译并执行 2. 计算机高级语言程序的运行方法有编译执行和解释执行两种,以下叙述中正确的是( ) A.C语言程序仅可以 ...
- python好用的内置库_第42p,time库,Python中优秀的内置库
大家好,我是杨数Tos,这是<从零基础到大神>系列课程的第42篇文章,第二阶段的课程:Python基础知识:Python内置库之time. 一.时间的三种格式 time是Python的内置 ...
最新文章
- linux 库函数拦截,如何使用net_dev_add()API过滤和拦截Linux数据包?
- mysql 8.0.21 安装配置方法图文教程
- perform build_lc_system_stat
- 关于Android错误 View requires API level 14 (current...
- hive2 mysql_架构hive2mysql流程
- python实现单链表快速排序升序linkedqueue_数据结构回顾
- Hadoop HA 部署
- cmt obm odm 代工模式oem_OEM、ODM、OBM、OPM概念,作用与区别
- 100层楼和两个玻璃球的问题
- allegro 04_B class和subclass介绍
- pads2007版本pcb导出的dxf在cad中打不开,提示“DXF 输入无效或不完整 -- 图形被放弃”
- git常用命令及Commit message规则
- 学习 《电路》(尼尔森著,第十版)第一章笔记(电流)
- 我要的仅此而已:伤感QQ心情日志
- APISpace 让你快速获取名言警句
- 数据挖掘进行数据分析常用的方法
- 欧盟数据保护通用条例》(General Data Protection Regulation,简称GDPR)。
- 共同学习Java源代码-多线程与并发-FutureTask类(三)
- 微信公众号链接小测试题js逻辑
- 论文阅读:HAD-Net: A Hierarchical Adversarial Knowledge Distillation Network for Improved Enhanced Tumour
热门文章
- 主流分布式文件系统对比
- 谷歌第四代TPU性能实测来了!每秒10万万亿次运算,今年将向谷歌云用户提供服务...
- 大三学生——要不要上研究生
- 最新版wps,设置粘贴默认为无格式文本粘贴,不起作用
- 游戏数据安全----一个关于数据加密的简单代码实现
- 如何清除服务器的缓存文件,服务器清理内存怎么清理缓存
- Tableau去除重复值
- python os.environ.setdefault,OS.ENVIRON()详解
- 金九银十!2022年最新32W字的Java程序员面试题,大厂面试有它足矣!
- python 中文转拼音原理_【Python】 汉字转化汉语拼音pinyin