嵌入式C/C++开发过程中日志输出的一点思考
在开发过程中,需要经常输出日志以协助调试和分析问题,一个良好的日志输出能够快速的帮助我们定位和分析问题。在一些linux平台嵌入式开发过程中,开发过程中对单步调试支持的并不好,它的调试很大一部分是借助于日志来完成。对最近一段时间嵌入式开发的反思与总结,个人感觉,日志输出时尽量做到以下几点: 1、个人认为可以把日志内容分为:定位日志和错误报告日志,除此两者之外的其他调试日志内容在调试
·
在开发过程中,需要经常输出日志以协助调试和分析问题,一个良好的日志输出能够快速的帮助我们定位和分析问题。在一些linux平台嵌入式开发过程中,开发过程中对单步调试支持的并不好,它的调试很大一部分是借助于日志来完成。对最近一段时间嵌入式开发的反思与总结,个人感觉,日志输出时尽量做到以下几点:
1、个人认为可以把日志内容分为:定位日志和错误报告日志,除此两者之外的其他调试日志内容在调试完毕提交代码的时候就要删除掉,这样可以减少无关日志的输出,便于查看日志内容和定位问题,同时也可以减少多余的代码量,增加代码的清晰度,便于维护代码。
定位日志:是指用于提示某个功能已经开始执行或已经执行完成,这种类型的日志可以隔离问题域,一旦程序发生问题,可以根据定位日志缩小排查问题的范围,进而提高问题解决的速度。
错误日志:是指提示代码中发生了某个具体问题,对于代码中可以预料到的错误和try...catch捕捉到的异常都需要进行有效且清晰的日志输出。例如打开文件失败的时候,在返回之前就应该有日志输出,可参考的条目2中的代码段3
2、不要直接使用库函数(例如printf、cout之类)进行输出,而是每个cpp文件自定义一个日志输出函数(如果是面向对象,则为每个类定义一个私有的日志输出成员函数),在该自定义的日志输出函数中在调用输出库函数,这样方便以后统一更改日志输出,例如想以后引入log4cpp的话就只需要修改自定义的日志输出函数即可,而不需要修改每一个日志输出之处:
例如:
原来代码:
4、在每个cpp文件的自定义日志输出函数中为每条日志默认加上文件名,例如:
[test.cpp]: 日志内容
这样当项目较大,日志较多时比较容易定位每条日志的位置,如代码段4所示。
5、日志输出应该简单、清晰,描述清除问题即可。在以往的代码开发中见到很多人(其实我以前也如此做过)这么写日志:printf("***********************************");这样输出本来是想增加该条日志的醒目程度,但是往往,这里增加一条,那里还会增加以后,不久之后就会发现满屏的乱七八糟的东西,非常不利于调试。
6、每条日志占用一行。
1、个人认为可以把日志内容分为:定位日志和错误报告日志,除此两者之外的其他调试日志内容在调试完毕提交代码的时候就要删除掉,这样可以减少无关日志的输出,便于查看日志内容和定位问题,同时也可以减少多余的代码量,增加代码的清晰度,便于维护代码。
一些多余的调试日志例如代码段1所示,对于一些不方便单步调试的开发,其单步调试主要借助日志来完成,因此这样的日志输出会更多。
代码段1
int Open(char* pFileName/*IN*/)
{
printf("into func:Open ");//------------多余的调试日志
if(NULL == pFileName)
{
printf("pointer of file name is NULL ");
return -1;
}
if(NULL != g_logfile)
{
printf("logfile has been opened");
return 2;
}
printf("into func:Open,before fopen ");//------------多余的调试日志
g_logfile = fopen(pFileName,"rw+");
if(NULL == g_logfile)
{
printf("logfile open fail");
return -2;
}
return 1;
}
定位日志:是指用于提示某个功能已经开始执行或已经执行完成,这种类型的日志可以隔离问题域,一旦程序发生问题,可以根据定位日志缩小排查问题的范围,进而提高问题解决的速度。
错误日志:是指提示代码中发生了某个具体问题,对于代码中可以预料到的错误和try...catch捕捉到的异常都需要进行有效且清晰的日志输出。例如打开文件失败的时候,在返回之前就应该有日志输出,可参考的条目2中的代码段3
2、不要直接使用库函数(例如printf、cout之类)进行输出,而是每个cpp文件自定义一个日志输出函数(如果是面向对象,则为每个类定义一个私有的日志输出成员函数),在该自定义的日志输出函数中在调用输出库函数,这样方便以后统一更改日志输出,例如想以后引入log4cpp的话就只需要修改自定义的日志输出函数即可,而不需要修改每一个日志输出之处:
例如:
原来代码:
代码段2:
int Open(char* pFileName/*IN*/)
{
if(NULL == pFileName)
{
printf("pointer of file name is NULL ");
return -1;
}
if(NULL != g_logfile)
{
printf("logfile has been opened");
return 2;
}
g_logfile = fopen(pFileName,"rw+");
if(NULL == g_logfile)
{
printf("logfile open fail");
return -2;
}
return 1;
}
将其修改为不直接引用输出库函数printf的形式,例如:
代码段3:
int Open(char* pFileName/*IN*/)
{
if(NULL == pFileName)
{
_DisplayLog("pointer of file name is NULL ");
return -1;
}
if(NULL != g_logfile)
{
_DisplayLog("logfile has been opened");
return 2;
}
g_logfile = fopen(pFileName,"rw+");
if(NULL == g_logfile)
{
_DisplayLog("logfile open fail");
return -2;
}
return 1;
}
上述使用的自定义日志输出函数为:
代码段4
void _DisplayLog(char* pMsg/*IN*/)
{
if(g_bUseLog && NULL != pMsg)
{
printf("[test.cpp]: ");
printf("%s",pMsg);
printf("\n");
}
}
3、日志文件应该可以开关,即不需要修改代码和重新编译就能打开或关闭日志的输出,这一点可以通过定义一个开关变量来实现,在自定义日志输出函数中根据该开关来决定是否进行日志输出,如代码段4中所示。4、在每个cpp文件的自定义日志输出函数中为每条日志默认加上文件名,例如:
[test.cpp]: 日志内容
这样当项目较大,日志较多时比较容易定位每条日志的位置,如代码段4所示。
5、日志输出应该简单、清晰,描述清除问题即可。在以往的代码开发中见到很多人(其实我以前也如此做过)这么写日志:printf("***********************************");这样输出本来是想增加该条日志的醒目程度,但是往往,这里增加一条,那里还会增加以后,不久之后就会发现满屏的乱七八糟的东西,非常不利于调试。
6、每条日志占用一行。
更多推荐
已为社区贡献4条内容
所有评论(0)