【资料图】
扫描关注一起学嵌入式,一起学习,一起成长
在产品研发的过程中,经常需要借助打印信息来帮助调试和后期维护。所以拥有一个完善的日志模块是至关重要的。
如下是从经手的项目中整理出来的日志模块及使用示例,以备后续项目开发时使用。(备注:Linux环境下)
log.c
#include #include #include#include#include#include #include #include #include #include #include"log.h"/*存储日志的文件名*/staticunsignedcharg_ucLogFileName[MAX_LOG_FILE_NUM][STR_COMM_SIZE]={{0}};/*指明是g_ucLogFileName中的哪个文件*/staticunsignedcharg_ucLogFileNo=0;/*输出日志位置标记,0-输出到终端,1-输出到日志文件*/unsignedlongg_ulPrintLogPlaceFlag=0;/*是否打印调试日志标记,0-不打印调试日志,1-打印调试日志*/unsignedlongg_ulPrintDebugLogFlag=0;/*日志文件大小*/staticunsignedlongg_ulLogFileSize=0;/*日志文件句柄*/staticFILE*pFile=NULL;/*日志存储互斥锁*/staticpthread_mutex_tg_stSaveLogMutexLock;/*日志模块初始化标记*/staticunsignedlongg_ulLogInitFlag=0;voidLOG_SetPrintLogPlaceFlag(unsignedlongflag){g_ulPrintLogPlaceFlag=flag;}voidLOG_SetPrintDebugLogFlag(unsignedlongflag){g_ulPrintDebugLogFlag=flag;}/*******************************************************************函数名:get_file_size**输入:char*path**输出:**功能描述:获取指令文件大小**返回值:long****************************************************************/staticlongget_file_size(constchar*path){longfilesize=-1;structstatstatbuff;if(stat(path,&statbuff)<0){returnfilesize;}else{filesize=statbuff.st_size;}returnfilesize;}/*******************************************************************函数名:unsignedlongLOG_PrintLogTime**输入:unsignedlongulBufLen存储时间的空间长度**输出:unsignedchar*ucTime存储时间**功能描述:日志输出**返回值:unsignedlong****************************************************************/unsignedlongLOG_PrintLogTime(unsignedchar*ucTime,unsignedlongulBufLen){structtm*pstTmSec;structtimevalstTmMsec;if(NULL==ucTime){return-1;}gettimeofday(&stTmMsec,NULL);pstTmSec=localtime(&stTmMsec.tv_sec);snprintf((char*)ucTime,ulBufLen-1,"%04d-%02d-%02d%02d:%02d:%02d%03ldms",pstTmSec->tm_year+1900,pstTmSec->tm_mon+1,pstTmSec->tm_mday,pstTmSec->tm_hour,pstTmSec->tm_min,pstTmSec->tm_sec,stTmMsec.tv_usec/1000);return0;}/*******************************************************************函数名:unsignedchar*LOG_LogTypeToStr**输入:unsignedcharucType日志类型unsignedlongulBufLen存储日志类型字符串空间的长度**输出:unsignedchar*pucTypeString根据日志类型将其转换成相应的字符串**功能描述:根据日志类型转换成相应的字符串**返回值:unsignedlong****************************************************************/unsignedlongLOG_LogTypeToStr(unsignedcharucType,unsignedchar*pucTypeString,unsignedlongulBufLen){if(NULL==pucTypeString){return-1;}/*防止发生越界*/ulBufLen-=1;switch(ucType){caseLOG_DEBUG:{strncpy((char*)pucTypeString,"DEBUG",ulBufLen);break;}caseLOG_ERROR:{strncpy((char*)pucTypeString,"ERROR",ulBufLen);break;}caseLOG_WARNING:{strncpy((char*)pucTypeString,"WARNING",ulBufLen);break;}caseLOG_ACTION:{strncpy((char*)pucTypeString,"ACTION",ulBufLen);break;}caseLOG_SYSTEM:{strncpy((char*)pucTypeString,"SYSTEM",ulBufLen);break;}default:{strncpy((char*)pucTypeString,"UNKNOWN",ulBufLen);break;}}return0;}/*******************************************************************函数名:unsignedlongLOG_OpenLogFile**输入:void**输出:void**功能描述:打开日志文件**返回值:unsignedlong****************************************************************/unsignedlongLOG_OpenLogFile(void){char*path=(char*)g_ucLogFileName[g_ucLogFileNo];char*flag=NULL;intlen=0;/*判断文件是否已经打开*/if(NULL!=pFile){LOG_PRINT("[ACTION]fileopened!");return0;}/*判断文件名是否有定义*/if(NULL==path){LOG_PRINT("[ERROR]filenameisNULL.");return-1;}/*判断文件是否存在*/if(!access(path,0)){/*获取文件大小*/if(0>(len=get_file_size(path))){LOG_PRINT("[ERROR]getfilesizefailed!");return-1;}}flag=(len>0&&len=g_ulLogFileSize){fclose(pFile);pFile=NULL;g_ucLogFileNo=(g_ucLogFileNo+1)%MAX_LOG_FILE_NUM;}}pthread_mutex_unlock(&g_stSaveLogMutexLock);return0;}/*******************************************************************函数名:LOG_Init**输入:constunsignedchar*ucLogFileName用来保存日志的文件名unsignedlongulFileSize存储日志的文件大小**输出:void**功能描述:日志打印初始化**返回值:unsignedlong****************************************************************/unsignedlongLOG_Init(constunsignedchar*ucLogFileName,unsignedlongulFileSize){unsignedinti=0;/*判断参数的合法性*/if((NULL==ucLogFileName)||!(ulFileSize>0)){return-1;}/*判断是否将日志输出到日志文件*/if((PRINT_LOG_TO_FILE!=g_ulPrintLogPlaceFlag)||(0!=g_ulLogInitFlag)){printf("g_ulPrintLogPlaceFlag=%ldg_ulLogInitFlag=%ld\n",g_ulPrintLogPlaceFlag,g_ulLogInitFlag);LOG_PRINT("printlogtotermination!!");return0;}/*记录日志模块已经被初始化(防止改模块被重复初始化)*/g_ulLogInitFlag=1;/*生成存储日志的文件名*/for(i=0;i
log.h
#ifndef_LOG_H_#define_LOG_H_#include /*通用字符串存储大小定义*/#defineSTR_COMM_SIZE128#defineSTR_MAX_SIZE1024#defineMAX_LOG_FILE_NUM(3)#defineNUMBER(type)sizeof(type)/sizeof(type[0])#define__FILENAME__(strrchr(__FILE__,"/")?(strrchr(__FILE__,"/")+1):__FILE__)/*日志类型*/enum{LOG_DEBUG=0,/*调试日志*/LOG_ERROR,/*错误日志*/LOG_WARNING,/*告警日志*/LOG_ACTION,/*运行日志*/LOG_SYSTEM,/*系统日志*/BUTTOM};/*将日志输出到终端*/#definePRINT_LOG_TO_TERM(0)/*将日志输出到文件中*/#definePRINT_LOG_TO_FILE(1)/*调试日志宏定义*/#defineDEBUG_PRINT0#defineLOG_PRINT(fmt,...)do{\if(DEBUG_PRINT)\{\printf(fmt"[line:%d][%s]\n",##__VA_ARGS__,__LINE__,__FUNCTION__);\}\}while(0);/*错误日志打印(在日志打印模块还未启动时使用)*/#defineLOG_ERR(fmt,...)do{\printf("[ERROR]"fmt"[line:%d][%s]\n",##__VA_ARGS__,__LINE__,__FUNCTION__);\}while(0);/*存储日志标记.0-不存储日志,1-存储日志*/externunsignedlongg_ulPrintLogPlaceFlag;/*是否打印调试日志标记,0-不打印调试日志,1-打印调试日志*/externunsignedlongg_ulPrintDebugLogFlag;unsignedlongLOG_PrintLog(unsignedcharucType,unsignedchar*pucLogInfo);/*日志打印宏定义*/#defineLOG_INFO(type,fmt,...)do{\if(PRINT_LOG_TO_TERM==g_ulPrintLogPlaceFlag)\{\if((0==g_ulPrintDebugLogFlag)&&(LOG_DEBUG==type))\{\break;\}\unsignedcharucLogInfo[STR_MAX_SIZE]={0};\snprintf((char*)ucLogInfo,sizeof(ucLogInfo)-1,fmt"[%s][line:%d][%s]\n",##__VA_ARGS__,__FILENAME__,__LINE__,__FUNCTION__);\LOG_PrintLog(type,ucLogInfo);\}\else\{\unsignedcharucLogInfo[STR_MAX_SIZE]={0};\snprintf((char*)ucLogInfo,sizeof(ucLogInfo)-1,fmt"[%s][line:%d][%s]\n",##__VA_ARGS__,__FILENAME__,__LINE__,__FUNCTION__);\LOG_PrintLog(type,ucLogInfo);\}\}while(0)/*是否打印调试日志标记,0-不打印调试日志,1-打印调试日志*/externvoidLOG_SetPrintDebugLogFlag(unsignedlongflag);/*存储日志标记.0-不存储日志,1-存储日志*/externvoidLOG_SetPrintLogPlaceFlag(unsignedlongflag);externunsignedlongLOG_Init(constunsignedchar*ucLogFileName,unsignedlongulFileSize);externvoidLOG_Destroy(void);#endif//_LOG_H_
main.c
#include #include"log.h"inttest_func1(){LOG_INFO(LOG_DEBUG,"%s","helloworld!!");return0;}intmain(intargc,char*argv[]){LOG_SetPrintDebugLogFlag(1);//打印调试信息//LOG_SetPrintLogPlaceFlag(1);//保存打印信息到文件LOG_Init("info",8000);LOG_INFO(LOG_DEBUG,"%s","Initlog!!");test_func1();LOG_INFO(LOG_DEBUG,"%s","Destroylog!!");LOG_Destroy();}
执行结果:
由执行结果可以看出一条打印信息包含了时间、日志类型、内容、文件名、行号、函数名等信息,这样就能够方便快速的定位问题,其使用方法也与printf函数类似,简单方便。
其次该日志模块还支持将日志存至文件,可以自行定义文件的大小及个数,日志循环覆盖。
觉得文章不错,点击“分享”、“赞”、“在看” 呗!
关键词:
-
关注:分享一个小巧的LinuxC日志模块(附代码)
扫描关注一起学嵌入式,一起学习,一起成长在产品研发的过程中,经常需
-
加盟勇士后想要实现的目标?保罗:很明显 就是总冠军!
加盟勇士后想要实现的目标?保罗:很明显就是总冠军!,保罗,奇才,勇士
-
云南本土烘焙品牌有哪些_国内知名的烘焙品牌有哪些_全球热点评
1、好利来:行业龙头企业,十大糕点品牌之一,最大的现代化无菌食品工
-
每日动态!中国可以养的大型猫科动物_大型猫科动物
1、四种大型猫科动物包括老虎、狮子、美洲虎和美洲豹。2、 猫科是食
-
世界观点:新郑轩辕湖湿地文化园_关于新郑轩辕湖湿地文化园简介
1、新郑轩辕湖湿地文化园位于新郑市黄水河轩辕湖水库至郑风苑之间2 56
-
物理学和应用物理学哪个好就业_物理学和应用物理学有哪些区别_全球快播报
1、物理学:比较侧重理论研究,所学内容涵盖高中物理的大部分,并有较
-
每日热讯!托纳利=7000万欧+10%二次转会分成,米兰亏还是赚&该怎么补强?
托纳利=7000万欧+10%二次转会分成,米兰亏还是赚&该怎么补强?,纽卡,托
-
diversion_diver
1、diver含义为潜水者是一个可数名词。2、diver3、潜水员常见释义4、英
-
中国传统植物染的传承与创新
2023年6月14日,2023中国工艺美术科普教育周活动“手艺·守艺——坚定
-
杜甫(df) 天天信息
来为大家解答以上问题,杜甫,df很多人还不知道,现在让我们一起来看看
-
港股CXO板块成“惊弓之鸟”,昭衍新药(06127)是否还有长期逻辑?-当前热议
最近段时间以来,我国CXO市场面临内部竞争加剧和外部宏观因素扰动的挑
-
台各界期盼重启两岸服贸谈判
据台湾《中国时报》6月22日报道,5月台湾外销订单金额连9黑,同比减少1
-
德国民调:德国极右翼政党支持率超过执政联盟
据德国国家电视一台当地时间23日公布的民意调查结果,德国极右翼政党德
-
生活成本飙升 超过100万名英国儿童接受食品救济 视焦点讯
据管理全英上千家“食品银行”的大型慈善机构特拉塞尔基金会今年4月底
-
天天资讯:国家气象中心:预计27日至30日 华北、黄淮等地还将出现高温天气
6月23日电,国家气象中心首席预报员张芳华介绍,预计23日至24日,华北
-
今日热门!二氯乙酸甲酯商品报价动态(2023-06-23)
交易商品牌 产地交货地最新报价二氯乙酸甲酯 含量:99 5%山东宏洋化学
-
焦点滚动:离贵州最近的海滩(离苏州最近的海滩)
来为大家解答以下的问题,贵州最近的海滩,离苏州最近的海滩这个很多人
-
焦点播报:2023年吉林省高考一分一段表
2023年吉林高考一分一段表(含照顾分)一分段表到底咋用?所谓“一分一段
-
为户外劳动者撑起“遮阳伞”_环球热点
近日,全国迎来持久高温“烤验”,许多人选择“宅”在家中点外卖,外卖
-
中国气象局启动高温四级应急响应 世界快讯
来自中国气象局应急办消息,6月22日,北京、天津、河北、山东等多个国