通过打印日志定位排查问题,是嵌入式linux c常用的方法。常见的打印日志方式有: printf打印到前台、fprintf到文件中、打印到syslog(网上介绍文章较多,不再赘述)中。这里介绍一种我在项目中将三者结合起来使用的方式,请大家提供宝贵意见。
参见文章:https://blog.csdn.net/z_dream_st/article/details/77418073;
:https://bbs.csdn.net/topics/390841785
谢谢 Z_Dream_ST 、alofm 的分享!!!
printf是程序在前台运行时,常用的方法,适用于前期调试阶段;syslog有分机打印的机制,并且打印到循环队列中方便程序后台运行时通过logread -f 查看,也可以开启保存到日志文件功能。本来syslog的功能已经很完美了,但在项目使用过程中发现syslog有时会漏掉打印消息,尤其是打印的数据特别大的时候,最容易打印不全或漏打数据。因能力有限,没有看syslog的源码定位问题,于是想到了将少量的但非常重要的信息通过fprintf打印到文件中。就产生了文章开头所说将三者结合起来使用的方式,闲言少叙,示例代码如下:
#include
#include
#include
#include
#include
#include
#include
/*syslog 等级
* LOG_EMERG 0 紧急状态
* LOG_ALERT 1 必须立即修复状态
* LOG_CRIT 2 严重状态
* LOG_ERR 3 出错状态
* LOG_WARNING 4 警告状态
* LOG_NOTICE 5 正常,但重要的状态
* LOG_INFO 6 信息性消息
* LOG_DEBUG 7 调试消息
*/
// 主要是因为使用到了 vprintf 、vfprintf、vsyslog等函数,在x86的ubuntu14.04中,不能连续使用,需要拷贝一份 va_list 参数
// vfprintf 连续使用时,需要复制一份, 本文主要是 vprintf、vfprintf的连续使用
// 参见 :https://bbs.csdn.net/topics/390841785 中2楼所说 ,感谢 alofm 博主
// 本人使用的嵌入式平台是 TI-am3354
#define x86 1
#define PROGRAM "[process name] "
void my_syslog(unsigned int lev,const char *msg,...);
#define mypfdbg
#ifdef mypfdbg
#define my_debug(format,...) my_syslog(LOG_DEBUG, PROGRAM "[%s:%d] " format,__FILE__,__LINE__,##__VA_ARGS__)
#else
#define my_debug(format,...)
#endif
#define my_info(format,...) my_syslog(LOG_INFO, PROGRAM "[%s:%d] " format,__FILE__,__LINE__,##__VA_ARGS__)
#define my_err(format,...) my_syslog(LOG_ERR, PROGRAM "[%s:%d] " format,__FILE__,__LINE__,##__VA_ARGS__)
unsigned char flag_pf = 1; //程序是否前台运行的标记,通过命令行传入参数确地是否前台运行,并修改
unsigned char dbg_lev = 7; //syslog的打印级别,通过命令行传入参数修改
FILE *fp = NULL;
int init_file_point(void)
{
if(NULL==fp)
fp = fopen("/home/mydir/test.log","a+");
if(NULL!=fp)
return 0;
else
return -1;
}
// 添加时间标记前缀
static void add_time_tag(char *dst,int bufsize,const char *format,...)
{
time_t now;
time(&now);
struct tm *local;
local = localtime(&now);
strftime(dst,bufsize,"%m-%d %T ",local);
strcat(dst,format);
}
void my_syslog(unsigned int lev,const char *msg,...)
{
int len = 0,mal_flag = 0, bufsize = 0;
char *ptr = NULL;
char buf[512] = {0};
if(lev<=dbg_lev) //默认的打印等级
{
va_list ap;
openlog("tag",LOG_PID,LOG_USER);
va_start(ap,msg);
if( (flag_pf) || (lev==LOG_ERR) )
{
len = strlen(msg);
if(len<(512-40))
{
ptr = buf;
bufsize = 512;
}
else
{
mal_flag = 1;
bufsize = len + 40;
ptr = (char *)malloc(bufsize);
bzero(ptr,bufsize);
}
add_time_tag(ptr,bufsize,msg);
}
// 在嵌入式linux中不需要下面条件编译的代码,如果没有下面条件编译部分代码,在ubuntu中运行时会段错误,具体原因未深入研究
#ifdef x86
va_list map,myap;
va_copy(map,ap);
va_copy(myap,ap);
#endif
if(flag_pf) //如果是前台运行,实现printf功能
vprintf(ptr,ap);
if( (NULL != fp) && (lev==LOG_ERR)) //如果级别是错误,同时打印到File流文件
#ifdef x86
vfprintf(fp,ptr,map);
#else
vfprintf(fp,ptr,ap); // 在嵌入式平台中只需要这行就行
#endif
if(1 == mal_flag)
free(ptr);
#ifdef x86
vsyslog(lev,msg,myap); //syslog有时间前缀,所有不使用增加前缀的ptr指针
#else
vsyslog(lev,msg,ap); //syslog有时间前缀,所有不使用增加前缀的ptr指针
#endif
va_end(ap);
closelog();
}
}
int main(int argc, const char *argv[])
{
init_file_point();
int i = 8, j = 5;
my_debug("i+j = %d\n",i+j);
my_err("i-j = %d\n",i-j);
return 0;
}
再次感谢谢谢 Z_Dream_ST 、alofm 两位博主!!!
其中有些异常没有考虑,仅示例基本功能,如有考虑不周的地方,还望指正。谢谢!