我的开发组长从前说过这么一段话“一个优异的程序员不在于他写代码有多快,也不在于他能不能完结这个模块的功用,要完结事务完结功用谁不会啊,重要的是他的处理才干,也就说当程序呈现过错时你能不能够快速定位到过错并处理它。”
是的,我也十分附和,代码不或许完美,也或许有千奇百怪的bug,尤其是新手,犯的过错就更多了,所以,咱们写程序时应有自己的一套debug手法,有一套自己的LOG的办法,一旦程序产生过错,咱们不需求再往程序中加繁琐的打印就能够定位到过错方位,这样才干加速自己的开发速度。
那怎样才算有一套高效的debug手法呢?我的主意是这样:
进程内开一个独立线程用于Debug&Info Center,在这儿咱们能够看到一切的打印信息,便于追寻各程序意向
标准化一套日志/打印的手法,不要再运用粗陋的printf,在恰当的方位加恰当的log
今日咱们先来完结自界说一套归于咱们LOG的规则。
一、信息类别与等级
咱们知道,程序内或许呈现各种反常,有的反常很严重,一不注意就产生coredump;有的反常仅仅或许对程序的运转产生影响,但不至于挂掉;有的反常是荫蔽的,虽然现在没对体系产生明显影响,可是不加处理也终究是个危险。假如咱们对这些反常都运用printf句子的话,咱们就区别不了哪些反常重要哪些不重要了,所以咱们首先得给信息分类别评等级(severity)。我的区别是这样的:
fatal 丧命过错
alarm 需求当即纠正的过错
error 需求重视的过错
warning 正告,或许存在某种过失
info 一般提示信息
debug 调试信息
代码界说能够这么写:
#define FATAL 1#define ALARM 2#define ERROR 3#define WARN 4#define INFO 5#define DEBUG 6
二、log的规划
依据咱们上面规则的打印等级,咱们很简单规划出相应的debug log,闲话少说,先上代码:
#define MY_LOG(level, fmt, args…) do{ \ if(BIT_ON(debug_flag,level)){ \ printf(“[%s]:”, __FUNCTION__); \ printf(fmt, ##args); \ } \}while(0)
当然咱们还需求界说一套设置debug level的办法,我的思路是这样的:
选用bit-map思维,界说一个unsigned int的数,这个数的而每一位表明一个等级,比方一个unsigned int的数就能够表明32个等级
界说相应的函数/宏界说,去设置相应的位
依据以上主意,能够设置出下面一系列的操作:
#define PRESENT_BIT32(x) (((uint32)((uint32)1<<(x))))#define BIT_ON32(m, b) (((m) & PRESENT_BIT32(b)) != 0)#define SET_BIT32(m, b) ((m) |= PRESENT_BIT32(b))#define CLEAR_BIT32(m, b) ((m) &= ~PRESENT_BIT32(b))
解说:
PRESENT_BIT32(x) :对应level的位的方位
BIT_ON32(m, b) :断定某一位是否为1
SET_BIT32(m, b) :设置指定位为1
CLEAR_BIT32(m, b) :将指定为设置为0
上面咱们运用了宏界说来界说出带等级的LOG,那该怎样运用这些LOG呢?运用办法如下:
if(pthread_create(&thread2_id, NULL, (void*)msg_sender2, NULL)){ MY_LOG(FATAL,”create handler thread fail!\n”); return -1; }MY_LOG(DEBUG,”I have recieved a message!\n”);MY_LOG(DEBUG,”msgtype:%d msg_src:%d dst:%d\n\n”,msg->hdr.msg_type,msg->hdr.msg_src,msg->hdr.msg_dst);
当然运用前需求先翻开相应的log开关,比方我想看debug的log,能够这么做:
SET_BIT(debug_flag, DEBUG);
这姿态咱们就将体系的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 code 是对色彩调用的始末格局如下:
\033[ ; m …… \033[0m
后边哪个 ”\033[0m” 是对前面哪个色彩载入的完毕,康复到终端本来的布景色和字体色,能够把后边哪个修改成如下试试:
#define DEBUG_ERR(fmt, args…) printf(“\033[46;31m[%s:%d]\033[40;37m “#fmt” errno=%d, %m\r\n”, __func__, __LINE__, ##args, errno, errno);
下面列出 ascii code 的色彩值:
字布景色彩规模:40—-49 字色彩:30———–39
40:黑 30:黑
41:深红 31:红
42:绿 32:绿
43:黄色 33:黄
44:蓝色 34:蓝色
45:紫色 35:紫色
46:深绿 36:深绿
47:白色 37:白色
回忆色彩格局太麻烦了,咱们将它搞成宏界说吧,这样今后用起来就便利得多。
#define NONE “\e[0m”#define BLACK “\e[0;30m”#define L_BLACK “\e[1;30m”#define RED “\e[0;31m”#define L_RED “\e[1;31m”#define GREEN “\e[0;32m”#define L_GREEN “\e[1;32m”#define BROWN “\e[0;33m”#define YELLOW “\e[1;33m”#define BLUE “\e[0;34m”#define L_BLUE “\e[1;34m”#define PURPLE “\e[0;35m”#define L_PURPLE “\e[1;35m”#define CYAN “\e[0;36m”#define L_CYAN “\e[1;36m”#define GRAY “\e[0;37m”#define WHITE “\e[1;37m”#define BOLD “\e[1m”#define UNDERLINE “\e[4m”#define BLINK “\e[5m”#define REVERSE “\e[7m”#define HIDE “\e[8m”#define CLEAR “\e[2J”#define CLRLINE “\r\e[K” //or “\e[1K\r”#define DEBUG_ERROR(fmt, args…) do{ \ printf(RED”[%s]:”NONE, __FUNCTION__); \ printf(fmt, ##args); \ }while(0);
作用:
所以,我主张将fatal一类丧命过错等级的log用高亮色彩标示,一旦有这类过错产生咱们也能第一时间发觉。