我的开发组长曾经说过这样一句话:“一个好的程序员,不在于他写代码的速度有多快,也不在于他能不能实现这个模块的功能。谁能实现业务实现功能,重要的是他的解决能力,也就是说当程序出错的时候,你能不能快速定位错误并解决。”是的,我也很赞同,代码不可能是完美的,也可能会出现奇怪的bug,尤其是新手,错误比较多。所以我们在写程序的时候,应该有自己的一套调试方法,有自己的LOG方法。一旦程序出错,我们就不需要在程序中添加繁琐的打印来定位错误的位置,从而加快自己的开发速度。那么如何才能拥有一套高效的调试方法呢?我的思路是这样的:在进程中单独开一个线程给Debug&InfoCenter,在这里我们可以看到所有的打印信息,方便跟踪各个程序的动向。标准化一套logs/打印的手段,不要用不再简单的printf了,在合适的位置加上合适的log今天我们先完成一组属于我们LOG的自定义规则1.信息类别和级别我们知道程序中可能会出现各种异常,其中一些是非常严重,一个一不留神就会出现ndcoredump;有些可能只影响程序的运行,但不会挂掉;一些异常是隐藏的。虽然现在还没有对系统造成太大的影响,但是如果不处理的话,将会是一个隐患。如果我们对这些异常使用printf语句,我们将无法区分哪些异常是重要的,哪些不重要,所以我们首先要对信息进行分类和评级(严重性)。我的划分如下:fatalfatalerroralarmerrorthatneedstobecorrectedimmediatelyerrorerrorthatneedsattentionwarningwarning,可能有某种errorinfogeneralpromptinformationdebug调试信息代码定义可以这样写:#defineFATAL1#defineALARM2#defineERROR3#defineWARN4#defineINFO5#defineDEBUG6二、日志的设计根据我们上面规定的打印级别,我们可以很方便的设计出对应的debug日志,废话少说,先上传代码:#defineMY_LOG(level,fmt,args...)do{\if(BIT_ON(debug_flag,level)){\printf("[%s]:",__FUNCTION__);??\printf(fmt,##args);\}\}while(0)当然我们还需要定义一套设置调试级别的方法,我的思路是这样的:采用位图的思路,定义一个unsignedint的数字,这个数字的每一位代表一个级别,比如aunsignedint的个数可以表示32级并定义相应的根据上面的思路,下面的系列可以设置es的操作:#definePRESENT_BIT32(x)(((uint32)((uint32)1<<(x))))#defineBIT_ON32(m,b)(((m)&PRESENT_BIT32(b))!=0)#defineSET_BIT32(m,b)((m)|=PRESENT_BIT32(b))#defineCLEAR_BIT32(m,b)((m)&=~PRESENT_BIT32(b))解释:PRESENT_BIT32(x):位的位置对应电平BIT_ON32(m,b):判断某位是否为1SET_BIT32(m,b):设置指定位为1CLEAR_BIT32(m,b):设置指定为0上面我们使用了宏定义来用级别定义日志,如何使用这些日志?使用方法如下:if(pthread_create(&thread2_id,NULL,(void*)msg_sender2,NULL)){MY_LOG(FATAL,"createhandlerthreadfail!\n");return-1;}MY_LOG(DEBUG,"Ihaverecievedamessage!\n");MY_LOG(DEBUG,"msgtype:%dmsg_src:%ddst:%d\n\n",msg->hdr.msg_type,msg->hdr.msg_src,msg->hdr.msg_dst);当然使用前需要打开相应的日志开关,比如我想查看调试日志,可以这样:SET_BIT(debug_flag,DEBUG);这样,我们就将系统的调试级别定义为DEBUG。让我谈谈印刷技巧:给印刷品上色!printf("\033[46;31m[%s:%d]\033[0m"#fmt"errno=%d,%m\r\n",__func__,__LINE__,##args,errno,errno);当上面的printf在linux命令行中打印出颜色时,方便一目了然的区分不同类型的调试信息。你只需要添加一些颜色代码,例如:这里的46代表背景颜色,31代表字体颜色。使用ascii码是调用颜色的开始和结束格式如下:\033[;m...其中\033[0m之后的“\033[0m”是加载之前颜色的结束,恢复终端颜色原来的背景色和字体,可以尝试修改后面的如下:#defineDEBUG_ERR(fmt,args...)printf("\033[46;31m[%s:%d]\033[40;37m"#fmt"errno=%d,%m\r\n",__func__,__LINE__,##args,错误号,错误号);下面列出了ascii码的颜色值:字符背景颜色范围:40----49字符颜色:30----------3940:黑色30:黑色41:暗红色31:红色42:绿色32:绿色43:黄色33:黄色44:蓝色34:蓝色45:紫色35:紫色46:深绿色36:深绿色47:白色37:白色记忆颜色格式太麻烦,还是做吧宏定义,方便以后使用多个#defineNONE"\e[0m"#defineBLACK"\e[0;30m"#defineL_BLACK"\e[1;30m"#defineRED"\e[0;31m"#defineL_RED"\e[1;31m"#defineGREEN"\e[0;32m"#defineL_GREEN"\e[1;32m"#defineBROWN"\e[0;33m"#defineYELLOW"\e[1;33m"#defineBLUE"\e[0;34m"#defineL_BLUE"\e[1;34m"#definePURPLE"\e[0;35m"#defineL_PURPLE"\e[1;35m"#defineCYAN"\e[0;36m"#defineL_CYAN"\e[1;36m"#defineGRAY"\e[0;37m"#defineWHITE"\e[1;37m"#defineBOLD"\e[1m"#defineUNDERLINE"\e[4m"#defineBLINK"\e[5m"#defineREVERSE"\e[7m"#defineHIDE"\e[8m"#defineCLEAR"\e[2J"#defineCLRLINE"\r\e[K"//或"\e[1K\r"#defineDEBUG_ERROR(fmt,args...)do{\printf(RED"[%s]:"NONE,__FUNCTION__);??\printf(fmt,##args);\}while(0);因此,我建议对致命错误级别的日志使用高亮颜色进行标记,一旦出现此类错误,我们将能够第一时间发现。
