在å‰é¢çš„两个部分当ä¸ï¼Œæˆ‘们讨论了将调试日志写到什么地方,以åŠå¦‚何对调试日志进行分级和分类。但是至今我们ä»ç„¶æ²¡æœ‰æ¶‰åŠåˆ°æœ€æ ¸å¿ƒçš„问题:应该在什么地方写调试日志?应该怎么写调试日志?这就是这一部分的主题。
如何写调试日志
å¦‚ä½•å†™è°ƒè¯•æ—¥å¿—çš„æ ¸å¿ƒé—®é¢˜å°±æ˜¯ï¼Œåº”è¯¥åœ¨ä»€ä¹ˆåœ°æ–¹å†™ä»€ä¹ˆå†…å®¹ã€‚åœ¨è€ƒè™‘å†™æ—¥å¿—çš„æ—¶å€™ï¼Œæˆ‘ä»¬çš„æœ€åŸºæœ¬çš„è€ƒé‡ä»ç„¶æ˜¯åœ¨ç¬¬ä¸€éƒ¨åˆ†å½“ä¸æåˆ°çš„æ ¸å¿ƒæ ‡å‡†ï¼šå¦‚ä½•ä¾¿äºŽæ·»åŠ ã€ä¾¿äºŽåˆ†æžå¤„ç†ï¼Œè¿›è€Œå®¹æ˜“定ä½é”™è¯¯ã€‚
现在考虑我们应该在调试日志当ä¸åŒ…å«å“ªäº›å†…容,让我们能够从å„个方é¢æ¥å®šä½é”™è¯¯ã€‚首先毋庸置疑,必è¦çš„元信æ¯æ˜¯åº”该被打å°å‡ºæ¥çš„,例如调试日志被打å°å‡ºæ¥çš„æ—¶é—´ï¼Œè€Œæ ¹æ®ç¬¬äºŒéƒ¨åˆ†çš„建议,调试日志的级别和分类信æ¯ä¹Ÿæ˜¯å¿…è¦çš„。为了便于跟踪多线程程åºï¼ŒæŠŠè¿›ç¨‹ID和线程ID包å«åœ¨å…¶ä¸ä¹Ÿæ˜¯å¤©ç»åœ°ä¹‰çš„事情。如果为了便于开å‘人员定ä½æ—¥å¿—在代ç 当ä¸çš„ä½ç½®ï¼ŒæŠŠæ‰“å°æ—¥å¿—çš„è¯å¥æ‰€åœ¨çš„代ç 文件ã€ä»£ç 行以åŠå‡½æ•°å称包å«åœ¨å…¶ä¸ä¹Ÿæ˜¯å¿…è¦çš„。幸è¿çš„是这些问题在一个好的日志记录模å—之下,大多数都å¯ä»¥é€šè¿‡ä¸€äº›è¾…助函数或系统内置的å®ï¼ˆä¾‹å¦‚__FILE__,__LINE__,__FUNCTION__)自动获å–å’Œæ·»åŠ ï¼Œä¸éœ€è¦å¼€å‘äººå‘˜åŽ»è¿‡å¤šå…³å¿ƒã€‚å› æ¤éœ€è¦å¼€å‘äººå‘˜æ·»åŠ æ—¥å¿—æ—¶çœŸæ£éœ€è¦å…³å¿ƒçš„问题其实åªå‰©ä¸‹äº†è¿™æ¡æ—¥å¿—的级别和日志的消æ¯å—符串了。
Tip 10:在日志æ¡ç›®å½“ä¸åŒ…å«å¿…è¦çš„元信æ¯ï¼Œä¾‹å¦‚时间ã€PID/TIDã€æ—¥å¿—级别和分类ã€ä»£ç 文件ã€ä»£ç è¡Œã€å‡½æ•°ç‰ã€‚
在这里å•ç‹¬æŠŠæ—¶é—´çš„输出æ出æ¥è®¨è®ºä¸€ä¸‹ã€‚在时间的打å°ä¸Šï¼Œæœ‰å¤šç§æ–¹å¼å¯ä¾›é€‰æ‹©ã€‚一般的说,我们比较倾å‘äºŽä½¿ç”¨æ ‡å‡†çš„æ ¼å¼æ¥æ‰“å°æ—¶é—´ï¼Œå¦‚RFC822当ä¸è§„å®šçš„æ ‡å‡†Internetæ—¶é—´æ ¼å¼ï¼Œæˆ–者asctimeè¾“å‡ºçš„æ ¼å¼ï¼ŒåŒæ—¶åœ¨å…¶ä¸åŒ…å«å¿…è¦çš„时区信æ¯ã€‚ä½¿ç”¨æ ‡å‡†çš„æ ¼å¼æ‰“å°æ—¶é—´ï¼Œå¯ä»¥ä½¿å¾—日志便于被脚本程åºå¤„ç†ï¼Œå› 为主æµçš„脚本程åºéƒ½æœ‰ç›¸åº”的库æ¥è¿›è¡Œæ—¶é—´çš„解æžï¼›æ·»åŠ å¿…è¦çš„时区信æ¯æ˜¯ä¸ºäº†å¾—到更多的关于客户环境的信æ¯ï¼Œä¾‹å¦‚å¤ä»¤æ—¶åˆ‡æ¢å’Œéžæ ‡å‡†çš„æ•´å°æ—¶æ—¶åŒºã€‚
Tip 11:在调试日志的时间当ä¸ï¼ŒåŒ…å«å¿…è¦çš„时区信æ¯ã€‚
日志的消æ¯å—符串是日志当ä¸çµæ´»æ€§æœ€å¤§çš„部分。æ£å› 为çµæ´»æ€§å¤§ï¼Œå¼€å‘人员也往往å¯èƒ½é—æ¼æŸäº›ä¿¡æ¯ï¼Œå¯¼è‡´åœ¨æ‹¿åˆ°ç”¨æˆ·å¤„æœé›†çš„调试日志之åŽï¼Œæ— 法进行有效的分æžã€‚æ ¹æ®æˆ‘的一些ç»éªŒï¼Œåœ¨è¿™é‡Œå°±å¦‚何包å«æœ‰æ•ˆçš„ä¿¡æ¯ç»™å‡ºä¸€äº›è®¨è®ºã€‚
第一个需è¦è€ƒè™‘的问题是日志的相关性。例如一个采用异æ¥IO模型的æœåŠ¡å™¨ç¨‹åºï¼Œé€šè¿‡æœ‰é™çš„å‡ ä¸ªçº¿ç¨‹æ¥æœåŠ¡å¤§é‡çš„会è¯ï¼Œå› 为æ¯ä¸ªçº¿ç¨‹éƒ½å¯èƒ½æœåŠ¡å¤šä¸ªä¼šè¯ï¼Œè€Œæ¯ä¸ªä¼šè¯å¯èƒ½å…ˆåŽç”±ä¸åŒçš„线程æ¥æœåŠ¡ï¼Œå› æ¤éœ€è¦åœ¨æ—¥å¿—当ä¸æ·»åŠ æŸç§å¯ä»¥å°†è¿™äº›æ—¥å¿—å…³è”èµ·æ¥çš„键值,通过这个键值,分æžæ—¥å¿—çš„å¼€å‘人员就å¯ä»¥å°†å¯¹äºŽåŒä¸€ä¸ªå¯¹è±¡çš„æ“作èšåˆåœ¨ä¸€èµ·è¿›è¡Œåˆ†æžã€‚这个键值应该å¯ä»¥å”¯ä¸€åœ°æ ‡ç¤ºæ‰€æ“作的对象(例如会è¯å¯¹è±¡ï¼‰ï¼Œæ¯”如å¯ä»¥ä½¿ç”¨å¯¹è±¡çš„地å€ã€ä¼šè¯å½“ä¸socket的值,业务相关的对象ID如邮件的Message IDç‰ç‰ã€‚
Tip 12:在调试信æ¯å½“ä¸åŒ…å«å¯ä»¥åŒºåˆ†ä¸åŒæ“作对象的键值,以便ä¿è¯å¯¹åŒä¸€å¯¹è±¡æ“作的日志的相关性。
å¦ä¸€ä¸ªé—®é¢˜æ˜¯ä¿è¯æ ¹æ®æ‹¿åˆ°çš„日志å¯ä»¥å¯¹ç¨‹åºçš„执行路径进行跟踪。一个简å•çš„方法就是在å„个æ¡ä»¶åˆ†æ”¯å¤„æ·»åŠ åˆé€‚的日志,ä¿è¯æ¯ä¸ªåˆ†æ”¯éƒ½è¢«æ—¥å¿—覆盖。通常æ¡ä»¶åˆ†æ”¯åˆ†ä¸ºä¸¤ç±»ï¼Œä¸€ç±»æ˜¯é”™è¯¯å¤„ç†çš„分支,å¦ä¸€ç±»æ˜¯ä¸šåŠ¡é€»è¾‘相关的分支。对于å‰è€…,比较常è§çš„就是在函数调用结æŸä¹‹åŽï¼Œå¯¹äºŽè¿”回值得检查,例如
FILE* pf = fopen(fileName, "r");
if ( NULL == pf ) {
  DebugLog(LOG_ERROR, "open file %s to read failed. CRT errno=%d", fileName, errno);
  // Other error handling code
}
DebugLog(LOG_INFO, "Open file %s to read succeeded", fileName);
在这个例å当ä¸ï¼Œæ— 论进入哪个分支,å‡æœ‰è°ƒè¯•æ—¥å¿—打å°å‡ºæ¥ã€‚而且,在æ£å¸¸çš„è¿è¡ŒçŠ¶æ€ä¸‹ï¼Œå®¢æˆ·å¯ä»¥å°†æ—¥å¿—çº§åˆ«è°ƒåˆ°é”™è¯¯æˆ–æ›´é«˜ï¼Œè¿™æ ·é™¤éžå‡ºé”™ï¼Œç”¨æˆ·ä¸éœ€è¦æ“心大é‡çš„日志输出所å 用的ç£ç›˜ç©ºé—´å’Œé€ æˆçš„效率æŸå¤±ã€‚通过在错误处ç†åˆ†æ”¯ä¸Šæ·»åŠ 错误级别的日志,在æ£å¸¸æµç¨‹ä¸Šæ·»åŠ ä¿¡æ¯æˆ–调试级别的日志,能够有效的跟踪错误å‘生之å‰çš„程åºæ‰§è¡Œè·¯å¾„。
è€Œå¯¹äºŽä¸šåŠ¡é€»è¾‘é€ æˆçš„æ¡ä»¶åˆ†æ”¯ï¼Œä¹Ÿå¯ä»¥é€šè¿‡ç±»ä¼¼çš„æ–¹å¼ï¼Œåœ¨æ¯ä¸ªåˆ†æ”¯çš„å…¥å£å¤„æ·»åŠ æ—¥å¿—ã€‚åœ¨ç†æƒ³çš„情况下,任何æ¡ä»¶åˆ†æ”¯è¯å¥éƒ½åº”该å¯ä»¥è¢«è°ƒè¯•æ—¥å¿—覆盖到。
Tip 13:在æ¯ä¸€ä¸ªå˜åœ¨é”™è¯¯å¤„ç†çš„地方,在错误处ç†åˆ†æ”¯ä¸Šæ·»åŠ 错误级别的日志,在æ£å¸¸æµç¨‹ä¸Šæ·»åŠ ä¿¡æ¯æˆ–调试级别的日志。
Tip 14ï¼šå¯¹äºŽä¸šåŠ¡é€»è¾‘é€ æˆçš„æ¡ä»¶åˆ†æ”¯ï¼Œåœ¨æ¯ä¸ªåˆ†æ”¯çš„å…¥å£å¤„æ·»åŠ æ—¥å¿—ï¼Œä¿è¯ä»»ä½•åˆ†æ”¯è·¯å¾„都在调试日志覆盖之下。
上é¢çš„例å还展示了打å°è°ƒè¯•æ—¥å¿—时需è¦æ³¨æ„çš„å¦å¤–å‡ ä¸ªé—®é¢˜ã€‚ä¸ºäº†ä½¿å¾—æ—¥å¿—å®¹æ˜“ç†è§£ï¼Œæœ€å¥½è®©æ—¥å¿—æ ¹æ®é€šç”¨çš„å¥æ³•æ¥ç»„织,例如例å当ä¸ï¼Œå°±æ ¹æ®å¥æ³•â€œå¯¹ä»€ä¹ˆåšäº†ä»€ä¹ˆæ“作,结果如何,为什么â€æ¥ç»„织的。相å,如果在打开文件出错的时候仅仅打å°å‡º"Cannot open file",其实对于排错并没有什么用处:拿到这个日志的开å‘äººå‘˜æ—¢æ— æ³•çŸ¥é“打开哪个文件出错,也ä¸çŸ¥é“为什么出错。
这里列出一些通用的å¥æ³•æ¨¡å¼ï¼š
- [æ“作] [æŸå¯¹è±¡] [æˆåŠŸ/失败],(å¦‚æžœå¤±è´¥ï¼Œå¤±è´¥åŽŸå› æ˜¯[æŸåŽŸå› ])
例å:Open file [d:\test.txt] for read failed. Win32 Last Error=2. The system cannot file the file specified.
- 现在[æ¡ä»¶]æˆç«‹ï¼Œéœ€è¦åš[æŸç§æ“作]
例å:Command [TEST] is not recoginized, will ignore it.
- 现在系统处在[æŸç§çŠ¶æ€],(如果ä¸æ˜¯æ£å¸¸çŠ¶æ€ï¼Œä»€ä¹ˆåŽŸå› )
例å:Virus scanning is disabled, invalid Activation Code is provided.
例å2:SMTP server status is SMTP_EHLO_ISSUED.
- [æŸå¯¹è±¡]进行了[æŸç§æ“作]
例å:Server thread #1 started.
- [æŸå¯¹è±¡]å³å°†è¿›è¡Œ[æŸç§æ“作]
例å:Will send response [220 ready] to socket 0x1234.
Tip 15:尽é‡ä¿è¯æ¯æ¡æ—¥å¿—ä¿¡æ¯çš„å®Œæ•´æ€§ï¼Œæ ¹æ®é€šç”¨çš„å¥æ³•æ¨¡å¼æ¥ç»„织æ¯ä¸€æ¡è°ƒè¯•ä¿¡æ¯ã€‚
在上述å¥æ³•å½“ä¸ï¼Œå¸¸å¸¸éœ€è¦è¾“å‡ºå‡ºé”™çš„åŽŸå› ï¼Œæˆ‘ä»¬å¯ä»¥é‡‡ç”¨å‡ ç§æ–¹å¼è¾“出:å¯ä»¥é€šè¿‡æ‰“å°é”™è¯¯ä»£ç 实现,或者将其转æ¢ä¸ºæ˜“于ç†è§£çš„å—符串打å°ã€‚å‰è€…æ¯”è¾ƒå®¹æ˜“åŠ å…¥ç¨‹åºå½“ä¸ï¼Œä½†æ˜¯åŽè€…更便于察看。但是建议å³ä½¿ä½¿ç”¨åŽè€…çš„æ–¹å¼ï¼ŒåŒæ—¶ä¹Ÿæ‰“å°å‡ºåŽŸå§‹çš„错误代ç ï¼Œå› ä¸ºå¯¹äºŽå¼€å‘人员æ¥è®²ï¼Œé”™è¯¯ä»£ç 更具有确定性,也更容易从代ç 的角度定ä½é”™è¯¯çš„åŽŸå› ã€‚ä¸Žæ¤åŒæ—¶ï¼Œåœ¨æ‰“å°é”™è¯¯ä»£ç 时建议将“这是什么类型的错误代ç â€æ‰“å°å‡ºæ¥ï¼Œå› 为ä¸åŒçš„库和代ç 使用的错误ç 体系也ä¸åŒï¼Œåœ¨ä¸€ä¸ªç¨ç¨å¤æ‚çš„Windows程åºå½“ä¸ï¼Œå°±è‡³å°‘å˜åœ¨CRT errno,Win32 Last Error,COM HRESULT,NTSTATUS,Winsock Last Error,å¯èƒ½è¿˜åŒ…括应用程åºè‡ªå®šä¹‰çš„错误代ç 。如果ä¸
打å°å‡ºâ€œä»€ä¹ˆç±»åž‹çš„错误ç â€ï¼Œåˆ™å¾ˆå®¹æ˜“将这些错误ç 混淆,使得难于跟踪。例如在例å当ä¸ï¼Œè¾“出"CRT errno=%d"ï¼Œè¿™æ ·åˆ†æžæ—¥å¿—的时候开å‘人员å¯ä»¥åŽ»CRTçš„errnoå¯èƒ½çš„å–值当ä¸åŽ»æŸ¥æ‰¾å¯¹åº”çš„åŽŸå› ï¼Œå¦‚æžœå•å•è¾“出"error no=%d",则å¯èƒ½é€ æˆæ··æ·†ï¼Œä¾‹å¦‚13在CRT errno当ä¸è¡¨ç¤ºAccess Denied,而在Win32 error code当ä¸è¡¨ç¤ºinvalid data。
Tip 16:在日志当ä¸è¾“出错误代ç 时,åŒæ—¶è¾“出错误代ç 的类别。
在多线程程åºå½“ä¸ï¼Œå› 为ä¸åŒçš„线程å¯èƒ½æ‰“å°çš„日志类型也ä¸åŒï¼Œä¾‹å¦‚代ç†æœåŠ¡å™¨è½¯ä»¶çš„æœåŠ¡ç«¯çº¿ç¨‹å’Œå®¢æˆ·ç«¯çº¿ç¨‹æ‰€æ‰“å°çš„日志显然ä¸åŒã€‚在需è¦ä½¿ç”¨è„šæœ¬ç‰å·¥å…·è‡ªåŠ¨åˆ†æžçš„情况下,需è¦èƒ½å¤Ÿç®€å•çš„区分线程的类型。åŒæ—¶ï¼Œç”±äºŽçº¿ç¨‹çš„生命周期å¯èƒ½æ¯”整个进程è¦çŸï¼Œå› æ¤åœ¨çº¿ç¨‹å…¥å£å‡½æ•°çš„开始处和结æŸå¤„输出必è¦çš„ä¿¡æ¯ï¼Œå¹¶ä¸”在开始处æ供能够区分ä¸åŒçº¿ç¨‹çš„日志信æ¯ï¼Œä¾‹å¦‚"Server listen thread #1 started",或者"Client listen thread #1 exit with code 0x00"ç‰ç‰ã€‚
Tip 17:在线程函数的开始和结æŸå¤„æ·»åŠ æ—¥å¿—ï¼Œå¹¶æ供能够简å•çš„区分线程类型的å—符串。
有的时候,线程å¯èƒ½éœ€è¦ç‰å¾…æŸä¸ªåŒæ¥å¯¹è±¡ï¼Œå› 为ç‰å¾…的结果多ç§å¤šæ ·ï¼Œå¹¶ä¸”å¯èƒ½å› 为其他线程调用TerminateThreadæˆ–ç±»ä¼¼çš„å‡½æ•°å¯¼è‡´å…¶é€€å‡ºï¼Œå› æ¤å»ºè®®åœ¨ç‰å¾…æ“作之å‰æ‰“å°ä¸€æ¡æ—¥å¿—,并在ç‰å¾…之åŽæ ¹æ®ç‰å¾…的结果打å°å‡ºå¦ä¸€æ¡æ—¥å¿—ï¼Œè¿™æ ·çš„å¥½å¤„åœ¨äºŽï¼Œå¼€å‘人员å¯ä»¥ä»Žæ—¥å¿—当ä¸å‘现线程éžæ£å¸¸ä¸æ¢æˆ–éžæ£å¸¸çš„ç‰å¾…结果。åŒæ ·çš„建议适用于需è¦è¿›è¡Œä¸€äº›è€—时的æ“作的时候,例如调用socketçš„IO相关函数的时候。这ç§æ—¥å¿—有时也å¯ä»¥åœ¨æ²¡æœ‰æ€§èƒ½åˆ†æžå™¨ï¼ˆPerformance Profiler)的时候进行简å•çš„性能分æžã€‚
Tip 18:在进行å¯èƒ½æ¯”较耗时的æ“作之å‰å’Œä¹‹åŽï¼Œæ·»åŠ 日志进行跟踪,以便å‘现异常情况或进行简å•çš„性能分æžã€‚
ä¸Žçº¿ç¨‹çš„ç”Ÿå‘½å‘¨æœŸè·Ÿè¸ªç±»ä¼¼ï¼Œå¯¹äºŽå¯¹è±¡çš„æž„é€ å’Œæžæž„最好也能够进行适当的跟踪。这ç§æ—¥å¿—ä¿¡æ¯å»ºè®®æ·»åŠ åœ¨æž„é€ å‡½æ•°ã€æ‹·è´æž„é€ å‡½æ•°ã€æžæž„函数和赋值è¿ç®—符当ä¸ã€‚使用这ç§è·Ÿè¸ªä¿¡æ¯ï¼Œå¯ä»¥æ–¹ä¾¿å¯¹äºŽå†…å˜æ³„æ¼çš„检查,也是和工具的分æžã€‚
Tip 19ï¼šåœ¨å¯¹è±¡çš„æž„é€ ã€æžæž„和拷è´å¤„æ·»åŠ è°ƒè¯•æ—¥å¿—ï¼Œå…¶ä¸åŒ…å«å¯¹è±¡çš„地å€æˆ–其他å¯æ ‡ç¤ºè¯¥å¯¹è±¡çš„键值,用于跟踪对象的生命周期。
对于æŸäº›å…·æœ‰å¤æ‚状æ€çš„对象,有å¯èƒ½éœ€è¦åœ¨è·Ÿè¸ªæ—¶äº†è§£å„个æ“作之åŽçš„对象状æ€ï¼Œå°¤å…¶å½“对象牵涉到å¤æ‚的线程åŒæ¥çš„æ—¶å€™ã€‚å› æ¤å¯èƒ½éœ€è¦ä¸ºæŸäº›å¯¹è±¡æ供类似dumpçš„æ“作,并在需è¦çš„时候将dump的结果写入调试日志。或者对于å议相关的问题,å¯ä»¥åœ¨æ¯æ¬¡æ”¶åˆ°æ•°æ®ä¹‹åŽæˆ–å‘é€æ•°æ®ä¹‹å‰dumpæ•°æ®å¹¶å†™å…¥æ—¥å¿—ï¼Œä»¥ä¾¿äºŽæ›´åŠ ç»†è‡´çš„åˆ†æžã€‚è¿™ç§æ—¥å¿—å¯èƒ½éžå¸¸æ¶ˆè€—æ‰§è¡Œæ—¶é—´ï¼Œå› ä¸ºä»–ä»¬å¯èƒ½è¢«é¢‘ç¹çš„打å°å‡ºæ¥ï¼Œè€Œä¸”å¯èƒ½æ¯æ¬¡çš„æ•°æ®é‡éƒ½éžå¸¸å¤§ï¼Œå› æ¤è¿™ç§æ—¥å¿—通常情况下建议使用éžå¸¸ä½Žçš„级别,至少ä¸åº”高于Debug或Tracing级别,如果必è¦ï¼Œç”šè‡³å¯ä»¥å•ç‹¬æˆä¸ºä¸€ä¸ªçº§åˆ«ã€‚
Tip 20:如果必è¦ï¼Œå¯ä»¥åœ¨è¾ƒä½Žçš„调试级别上æ供对象或å议数æ®çš„转储(dump),以便分æžã€‚
有时候软件产å“çš„é…ç½®å¯èƒ½éžå¸¸å¤æ‚,而ä¸åŒçš„é…置往往æ„味ç€ä¸åŒçš„行为和对于环境的ä¸åŒçš„ä¾èµ–ã€‚å› æ¤ï¼Œå¤„于排错的需è¦ï¼Œå¯ä»¥åœ¨æ—¥å¿—当ä¸è¾“出一些与用户环境相关的信æ¯ï¼Œä¾‹å¦‚当å‰æ“作系统的版本,以åŠå¿…è¦çš„é…置项的值。但是如果使用这ç§æ–¹æ³•ï¼Œæ³¨æ„ä¸è¦æ³„æ¼ç”¨æˆ·éšç§ï¼Œä¾‹å¦‚密ç 散列,或者其他éšç§æ•°æ®ã€‚
Tip 21:如果必è¦ï¼Œåœ¨æ—¥å¿—当ä¸è¾“出软件è¿è¡Œçš„环境信æ¯ï¼Œä¾‹å¦‚软件的é…置和æ“作系统信æ¯ã€‚
最åŽè®¨è®ºä¸€ä¸‹å¼‚常的使用。通常情况下,虽然异常对于写出简å•çš„程åºéžå¸¸æœ‰æ•ˆï¼Œä½†æ˜¯å¾€å¾€åœ¨å‡ºé”™æ—¶éš¾äºŽè·Ÿè¸ªã€‚å› ä¸ºå¼‚å¸¸å¾€å¾€ä¼šæ²¿ç€è°ƒç”¨æ ˆä¾æ¬¡å‘ä¸Šä¼ é€’ï¼Œè€Œåœ¨æœ€å¤–å±‚è¢«catchã€‚è¿™æ ·ï¼Œå³ä½¿åœ¨æœ€å¤–层的catchå¤„ï¼Œå…¶å®žä¹Ÿå¾ˆéš¾å¯¹äºŽé”™è¯¯çš„ç»†èŠ‚åŽŸå› ç»™å‡ºç”案。而C++æ ‡å‡†åº“æ‰€ç»™å‡ºçš„é¢„å®šä¹‰å¼‚å¸¸æ•°é‡åˆå¤ªå°‘ï¼Œå› æ¤ä½¿ç”¨try-catch往往是分æžè°ƒè¯•æ—¥å¿—的大敌。为了尽å¯èƒ½çš„å‡å°‘使用异常对分æžè°ƒè¯•æ—¥å¿—带æ¥çš„难度,建议在throw exception的地方将尽å¯èƒ½è¯¦ç»†çš„ä¿¡æ¯ä¿å˜åœ¨exception对象当ä¸ï¼Œç©¶ç«Ÿä¿å˜å“ªäº›ä¿¡æ¯å¯ä»¥å€Ÿé‰´ä¸€æ¡å®Œæ•´çš„错误日志应该具有的信æ¯ï¼Œä¾‹å¦‚抛出异常的è¯å¥æ‰€åœ¨çš„代ç 行和代ç æ–‡ä»¶ï¼ŒæŠ›å‡ºå¼‚å¸¸çš„åŽŸå› ï¼Œå¿…è¦çš„相关信æ¯ï¼Œä¾‹å¦‚æ— æ³•æ‰“å¼€çš„æ–‡ä»¶åã€‚è€Œæ— è®ºåœ¨ä»€ä¹ˆåœ°æ–¹è¿™ä¸ªå¼‚å¸¸è¢«catch,都应该将这些信æ¯ä»Žä¸dump出æ¥ï¼Œå¹¶æ‰“å°æˆè°ƒè¯•æ—¥å¿—。
æ˜¾ç„¶ï¼Œè¿™æ ·ä¼šæžå¤§çš„å¢žåŠ å¼‚å¸¸å¯¹è±¡çš„å¤æ‚ç¨‹åº¦ï¼Œä½†æ˜¯æˆ‘ä»¬è®¤ä¸ºï¼Œä¸ºäº†è®©è°ƒè¯•æ—¥å¿—æ›´åŠ å®¹æ˜“ç†è§£å’Œè·Ÿè¸ªï¼Œè¿™ç§å¤æ‚程度是必è¦çš„,而且与调试日志的打å°ç±»ä¼¼ï¼Œæˆ‘们å¯ä»¥é€šè¿‡ä¸€äº›å®æˆ–者辅助函数æ¥è¾¾åˆ°ç®€åŒ–编程的目的。
Tip 22:如果使用异常,则尽å¯èƒ½åœ¨å¼‚常当ä¸åŒ…å«å®Œæ•´çš„å¯ä»¥æž„建一个错误日志的元信æ¯ï¼Œå¹¶åœ¨catch异常处将其打å°åˆ°è°ƒè¯•æ—¥å¿—。
所有的这些写日志的建议,最终的目的还是能够容易的被人看懂,已ç»èƒ½å¤Ÿå®¹æ˜“的被自动化程åºåˆ†æžã€‚现在我们有了组织良好的日志文件,如何对其进行分æžï¼Œè¿™å°±æ˜¯ä¸‹ä¸€éƒ¨åˆ†è¦è®¨è®ºçš„问题。