linux自定义log日志

tech2023-01-22  55

linux自定义log日志

近期调式项目需要,要在设备上加入log功能,网上有了解到Linux下自带syslog,没有具体研究,好像需要配置。然后想自己实现一个log功能,于是开始整理思路:

代码中加入log点能够打印到文件;文件达到一定大小自动切换到另外一个文件,两个文件交替使用;保证实时性

一开始查找到一些把程序运行的打印直接打印到文件方法,如下:

1)假设我的程序是test,运行test

$ test > result.txt

这样printf的输出就存储在result.txt中了。

2)如果既想打印在终端,又想保存在文件,还可以使用tee命令

$ test | tee result.txt

3)还有一个方法就是使用fprintf函数了 以上1)、2)两种方式在普通测试的小程序上可以用,到了大的应用程序不是很方便,无法控制文件大小。方式3)使用的时候,需要重复打开关闭文件,考虑到打印的内容频率较高,遂放弃。


重新寻找方法,使用echo

首先打印到文件,其实就是自定义打印函数,把常用的printf改成自己的打印接口。

#define _PRTLOG #ifdef _PRTLOG #define PRI_LOG(fmt, args...) PrtLog(eLogDebug,"[TEST] [%s: %d] "fmt"", __func__, __LINE__, ##args); #define PRI_ERR_LOG(fmt, args...) PrtLog(eLogError,"\033[1;31m[TEST_ERR] [%s: %s: %d] "fmt" \033[0m\n", __FILE__, __func__, __LINE__, ##args) #define PRI_LOG_FO(fmt, args...) PrtLog(eLogFileOnly,"[TEST] [%s: %d] "fmt"", __func__, __LINE__, ##args); #else #define PRI_LOG(fmt, args...) #define PRI_ERR_LOG(fmt, ...) #define PRI_LOG_FO(fmt, args...)

然后就是实现PrtLog函数,下面代码中的SemTake、SemGive是linux下信号量的获取与释放,这里是重新封装了一下,也可以直接用linux的信号量接口。GetLogTime是获取系统时间,通过gettimeofday函数就可以获取到,这个在之前的文章中有提到。

/* ********************************************************************************** * Name : PrtLog * Description : * Input : * priority :level of log, LOG_ERR, LOG_DEBUG etc. * fmt :format of message to log * ... :args follow by fmt * Output : * Return : * Note : 打印日志信息到文件,单次打印最大字符串长度1024 * **********************************************************************************/ void PrtLog(int priority, char* fmt, ...) { int nlogsize = 0; char abyTime[32] = {0}; char abyCmd[ONE_MSG_MAX+64] = {0}; char priVc[][9] = {"Emerg", "Alert", "Crit", "Error", "Warning", "Notice", "Info", "Debug", "FileOnly"}; SemTake(&g_LogSem);//自定义部分 memset(LogLastMsg, 0, ABOX_ONE_MSG_MAX); GetLogTime(abyTime);//自定义部分 char* priPt = priority < 0 || priority >= sizeof(priVc)/sizeof(priVc[0]) ? "Unknow priority!" : priVc[priority]; va_list argPt; unsigned Ln; va_start(argPt, fmt); //now argPt is point to log's param:... Ln = snprintf(LogLastMsg, sizeof(LogLastMsg), "[%s][%s]: ", abyTime, priPt); Ln += vsnprintf(LogLastMsg + Ln, sizeof(LogLastMsg) - Ln, fmt, argPt); va_end(argPt); //choose the log which should be show on stderr if (priority < LOG_ERR || priority <= Log2Stderr) { fprintf(stderr, "%s\n", LogLastMsg); } //每次打印长度累加 nlogsize = strlen(LogLastMsg); g_LogSize += nlogsize; //此处实现log自动切换 if (0 == g_byCurLogFile) { //当前使用log0,大小超限切换到log1 if (g_LogSize >= ABOX_LOG_MAX) { //清空log1 sprintf(abyCmd, "echo -e \"log1 start\" > %s", LOG_PATH1); system(abyCmd); //写入log1 -e 启用解释反斜杠的转义功能 -n 不尾随换行符 sprintf(abyCmd, "echo -e -n \"%s\" >> %s", LogLastMsg, LOG_PATH1); system(abyCmd); g_LogSize = nlogsize; g_byCurLogFile = 1; } else { //写入log0 sprintf(abyCmd, "echo -e -n \"%s\" >> %s", LogLastMsg, LOG_PATH0); system(abyCmd); } } else { //当前使用log1,大小超限切换到log0 if (g_LogSize >= LOG_MAX) { //清空log0 sprintf(abyCmd, "echo -e \"log0 start\" > %s", LOG_PATH0); system(abyCmd); //写入log1 sprintf(abyCmd, "echo -e -n \"%s\" >> %s", LogLastMsg, LOG_PATH0); system(abyCmd); g_LogSize = nlogsize; g_byCurLogFile = 0; } else { //写入log1 sprintf(abyCmd, "echo -e -n \"%s\" >> %s", LogLastMsg, LOG_PATH1); system(abyCmd); } } if (eLogFileOnly != priority)//头文件定义priority枚举 { //此处打印到终端 printf("%s",LogLastMsg); } SemGive(&g_LogSem);//自定义部分 if (priority <= LOG_ERR) { exit(-1); } return ; }

以上代码通过echo打印到文件,通过一个全局变量统计当前log文件的大小,超过后自动切换到另一个文件。 一开始使用fprintf函数,在初始化时,打开文件,之后一直不再关闭,直到文件大小超限。这种方式出现一个问题,fprintf输出到文件流中,若不关闭文件,每次都要在缓存中满1024个字节后,才会打印到文件,这就使得log日志不再具有实时性。后来又改成了echo的方式,使用这种方式,需要在初始化时,创建好两个log文件。

以上代码加入文件,就可以在自己 的代码中调用 PRI_LOG 打印log到终端和文件 PRI_ERR_LOG 打印出错信息到终端和文件 PRI_LOG_FO 只打印log到文件


欢迎大家补充,使用中有什么问题可以留言一起交流。 2020年9月3日星期四

参考文章:https://blog.csdn.net/aidixi4007/article/details/101152366

最新回复(0)