在做设备开发的时候,是否经常存在以下疑问:
1.在开发过程中,程序没有发生崩溃,但在压力测试过程中却发生了崩溃,抓狂崩溃发生在哪?
2.设备为何不按照设想的情景运行,当时的场景已经无法复现,抓狂该如何定位问题所在?
这时候,需要引入日志系统。
而在仪器设备行业,大多数情况,需要日志系统,主要存在两个需求:
1。用于追踪程序崩溃的大致位置
2。用于记录仪器运行过程中数据
(个人认为目前大型设备基本也只有这两个需求)
而仪器的日志特点是:
1。数据量不大,一天1~10个G就很多了
2。存在多个子系统,需要分系统记录
3。能够按日期滚动记录在文件中
4。功能(例如开关)可不断线实时加载
5。小型化,尽可能的小
为了满足上述需求和特点,开发了日志库,源码地址:GL4A_logger。
目的:
用于工业设备问题追踪和分析。
用于在运行和调试过程中,记录崩溃所在的大致位置。
用于在日常运行过程中,监控必要的数据。
特点:
记录时间小于1ms;
实时记录,可用于崩溃追踪;
缓冲记录,可用于记录日常运行数据;
记录文件名和行号,并支持格式化输出;
支持运行过程中实时重加载配置;
可记录在控制台中,自由选择功能开关;
可记录在文件中,自由选择功能开关;
可自由添加组件/模块,分模块记录,模块可自由开关;
可自由配置日志等级。
组成:
组件、日志记录器、等级
组件可由用户增删改,组件可自由开关,如果某个组件关闭,那么所有其挂载的日志记录器均不会对其进行日志记录。
日志记录器分为console控制台日志记录、rolling滚动型日志记录、daily按天日志记录。三种日志记录器均可以自由开关,如果某种日志记录器被关闭,那么所有此类型的日志均不会被记录。
等级分为trace和error,其中,error等级用于追踪崩溃,trace用于日常数据记录。所有error日志均会在trace中备份记录一份,主要用于保持trace数据上下文完整性。
所有配置项均存在config文件夹中的配置文件GL4A_config.cfg中。
结构图:
基本用法:
{
//引用头文件
#include "GL4A_user.h"
// 在程序入口处,根据配置文件路径,初始化日志库
eGL4A_init(GL4A_DEFAULT_CONFIG_DIR);
// 在M0组件函数入口处,记录ERROR,并标识为 IN(用于定位大致崩溃位置)
GL4A_ERROR_LOG("M0", __F__, __L__, "XXX函数,IN!\n");
// 在中间必要时,记录 TRACE,用于日常数据记录
GL4A_TRACE_LOG("M0", __F__, __L__, "记录数据!\n");
// 在M0组件函数入口处,记录ERROR,并标识为 OUT(用于定位大致崩溃位置)
GL4A_ERROR_LOG("M0", __F__, __L__, "XXX函数,OUT!\n");
// 在程序出口处,关闭日志库
GL4A_close();
}
注:当程序发生崩溃时,相应函数入口ERROR IN会被记录,但ERROR OUT不会被记录,那么,根据记录的文件名和行号,即可定位崩溃发生的位置。
在记录ERROR时,同时会在TRACE中备份记录一份,用于保持TRACE记录上下文的完整性。
基本函数
主要包括两个部分:
- 日志库初始化/关闭/重加载,日常输出
GL4A_init——用于初始化日志库
GL4A_reloadConfig——用于实时重加载日志配置文件
GL4A_close——用于关闭日志库
GL4A_TRACE_LOG——用于输出TRACE日志
GL4A_ERROR_LOG——用于输出ERROR日志
- 日志库配置文件修改
loadCfgFileToStruct——用于获取配置文件结构体
saveCfgFileFromStruct——用于将配置结构体保存到配置文件
genConfigDefault——重新按照默认的配置结构体生成配置文件
TotalCfgInfos——配置结构类,其中包含对配置项的基本操作
注:如果对json格式比较了解,可直接对配置文件进行操作
注:具体参见GL4A_user.h中GL4A命名空间,有非常详尽的注释