Effective Debug Logging (part 2)
è¿™æ˜¯è¿™ä¸ªç³»åˆ—æ–‡ç« çš„ç¬¬äºŒéƒ¨åˆ†ï¼Œæˆ‘ä»¬å°†å…³æ³¨å¦‚ä½•è¿‡æ»¤è°ƒè¯•æ—¥å¿—çš„é—®é¢˜ï¼Œäº¦å³ç´¢å¼•å½“ä¸â€œè°ƒè¯•æ—¥å¿—的分级和分类:æ高日志的信噪比â€ä¸€é¡¹ã€‚
调试日志的分级和分类
调试日志的分级和分类的目的在于能够更好的对大é‡çš„日志进行过滤,使得å¯ä»¥å®¹æ˜“地从æŸä¸ªæˆ–æŸäº›æ–¹é¢åˆ†æžæ—¥å¿—。
日志的分级是已ç»å¹¿ä¸ºæŽ¥å—的一ç§åšæ³•ï¼Œä¾‹å¦‚Windows的事件日志就分为错误ã€è¦å‘Šã€ä¿¡æ¯ä¸‰ç§çº§åˆ«ï¼Œè€Œå†…æ ¸çš„DbgPrintEx函数也包å«æœ‰æ—¥å¿—分级的å‚数,并且给出了四ç§é¢„设的级别。为调试日志实现分级的主è¦ç›®çš„是过滤ä¸å¿…è¦çš„消æ¯ï¼Œä»¥ä¾¿èƒ½å¤Ÿè®©é‡è¦çš„调试信æ¯ä¸ä¼šæ·¹æ²¡åœ¨å¤§é‡çš„æ— ç”¨ä¿¡æ¯å½“ä¸ï¼ŒåŒæ—¶åœ¨æ£å¸¸çš„使用过程当ä¸ï¼ŒæŽ§åˆ¶è°ƒè¯•ä¿¡æ¯çš„输出也å¯ä»¥æ高系统的效率。
在具有分级的调试日志实现当ä¸ï¼Œé€šå¸¸ç³»ç»Ÿéƒ½ä¼šè‡³å°‘指定3ç§è°ƒè¯•ä¿¡æ¯çš„级别,å³é”™è¯¯ã€è¦å‘Šå’Œä¿¡æ¯ã€‚也有系统æä¾›æ›´åŠ ç»†è‡´çš„çº§åˆ«ï¼Œä¾‹å¦‚æ¯”é”™è¯¯æ›´é«˜çº§åˆ«çš„â€œè‡´å‘½é”™è¯¯â€çº§åˆ«ï¼Œæˆ–比信æ¯çº§åˆ«æ›´ä½Žçš„“调试â€çº§åˆ«å’Œâ€œè¿½è¸ªâ€çº§åˆ«ã€‚通常情况下ä¸åŒçš„级别使用一个æ£æ•´æ•°å€¼æ¥è¡¨ç¤ºï¼Œä¸€èˆ¬çš„约定是使用较å°çš„值表示优先级较高的调试信æ¯ï¼Œä¾‹å¦‚致命错误为0级,å¯æ¢å¤é”™è¯¯ä¸º1级ç‰ç‰ã€‚
通常具有调试日志分级的产å“都会采用æŸç§æ–¹å¼æ¥æŒ‡å®šéœ€è¦æ‰“å°çš„调试级别,这个å¯ä»¥é€šè¿‡å‘½ä»¤è¡Œå‚数或者é…置文件指定,通常接å—一个æ£æ•´æ•°ã€‚在打å°è°ƒè¯•æ—¥å¿—的地方,开å‘人员需è¦æŒ‡å®šè°ƒè¯•æ—¥å¿—的级别,当这个级别高于或ç‰äºŽå…¨å±€çš„调试级别时,这æ¡è°ƒè¯•æ—¥å¿—便会输出。这ç§æ–¹å¼ç®€å•è€Œä¸”æœ‰æ•ˆï¼Œå› æ¤å¾—到了广泛的应用。
但是这里é¢éšå«ç€ä¸€ä¸ªå®žé™…当ä¸éœ€è¦é¢å¯¹çš„问题。虽然我们æ供了ä¸åŒçš„级别,四ç§æˆ–者五ç§ï¼Œä½†æ˜¯é€šå¸¸è¢«ç”¨åˆ°çš„通常åªæœ‰å…¶ä¸çš„两个æžç«¯çš„级别:在æ£å¸¸è¿è¡Œè¿‡ç¨‹
当ä¸ï¼Œç”¨æˆ·å¾€å¾€é€‰æ‹©ä¸æ‰“å°ä»»ä½•çš„日志,或者åªæ‰“å°çº§åˆ«è¾ƒé«˜çš„日志;而当软件在客户处é‡åˆ°äº†é—®é¢˜çš„时候,支æŒäººå‘˜å¾€å¾€è¦æ±‚客户直接将调试日志级别调到最详细
的级别,然åŽæœé›†æ—¥å¿—ã€‚å› æ¤ï¼Œæ—¥å¿—分级需è¦é¦–è¦è€ƒè™‘的问题很多的时候并éžä¸ºç”¨æˆ·æ供对于日志输出é‡çš„控制,而是为了开å‘人员拿到细致的日志的时候,能够快速的对其进行过滤,并在ä¸åŒçº§åˆ«
上定ä½é—®é¢˜ã€‚å› æ¤è°ƒè¯•çº§åˆ«ä¸å®œå¤ªå¤šï¼Œåˆ†çš„过细没有太大的æ„义,而且容易使得在编写调试日志的时候难以确定æ£ç¡®çš„级别。我们比较倾å‘于五个级别:致命错误ã€å¯æ¢å¤é”™è¯¯ã€è¦å‘Šã€ä¿¡æ¯ã€è°ƒè¯•ï¼Œæœ‰æ—¶å€™è‡´å‘½é”™è¯¯å’Œå¯æ¢å¤é”™è¯¯ä¸åŠ 区分,也就å˜æˆçš„å››ç§çº§åˆ«ã€‚å¦å¤–,应当在最终的日志文件当ä¸è®°å½•æ¯æ¡æ—¥å¿—的级别,以便于拿到日志之åŽå¯ä»¥æ ¹æ®çº§åˆ«è¿‡æ»¤ã€‚
å› æ¤ï¼Œæˆ‘们有了Tip 3å’ŒTip 4:
Tip 3:使用日志分级显示的机制,在æ£å¸¸è¿è¡Œå½“ä¸æŽ§åˆ¶æ—¥å¿—的输出é‡ï¼Œè°ƒè¯•æƒ…况下输出尽å¯èƒ½ç»†è‡´ã€‚
Tip 4:在日志当ä¸è®°å½•å½“å‰æ—¥å¿—的级别,便于拿到日志之åŽçš„过滤和分æžã€‚
由于通常开å‘人员拿到的都是最详细的级别的调试日志,而在这个级别上é¢ï¼Œå„个模å—通常都会打å°å‡ºå¤§é‡çš„日志,这ç§æ—¥å¿—到了支æŒäººå‘˜å’Œå¼€å‘人员手ä¸ä¹‹åŽï¼Œä¹Ÿå¾€å¾€ç”±äºŽæ•°é‡å·¨å¤§è€Œéš¾äºŽå¤„ç†å’Œåˆ†æžã€‚å› æ¤å¦‚何å¯ä»¥æ›´åŠ 细致的进行日志的分类,就是æˆäº†å¦ä¸€ä¸ªéœ€è¦è§£å†³çš„问题。
对于调试日志分类的设计有两个方é¢çš„考虑:一方é¢ï¼Œå¯¹äºŽæ—¥å¿—分类倾å‘于尽å¯èƒ½çš„细致,以便拿到日志的开å‘äººå‘˜èƒ½å¤Ÿåœ¨æ›´åŠ ç»†è‡´çš„çº§åˆ«ä¸Šåˆ†æžæ—¥å¿—,å¦ä¸€æ–¹é¢ï¼Œç”±äºŽæ—¥å¿—所从属的类别需è¦å¼€å‘人员在写æ¯ä¸€æ¡æ—¥å¿—çš„æ—¶å€™ç¡®å®šï¼Œå› æ¤ï¼Œåº”该能够让开å‘人员能够快速的决定日志的类别,以便å‡å°‘å¼€å‘人员的工作,这就è¦æ±‚日志的分类ä¸èƒ½è¿‡äºŽç»†è‡´ã€‚这两个方é¢ç›¸äº’çŸ›ç›¾ï¼Œå› æ¤ï¼Œè®¾è®¡è‰¯å¥½åˆ†ç±»æ–¹å¼ï¼ŒæŠ›å¼ƒä¸å¿…è¦çš„分类,使设计当ä¸éœ€è¦è€ƒè™‘的一个é‡è¦æ–¹é¢ï¼Œå¦åˆ™å¼€å‘人员花费在确定日志的类别上的时间比写代ç 的时间还多,就得ä¸å¿å¤±äº†ã€‚
å¦å¤–,由于调试日志的分类å¯ä»¥æœ‰å‡ ç§ä¸åŒçš„æ–¹å¼ï¼Œä¾‹å¦‚基于模å—进行分类,基于目的进行分类,ç‰ç‰ï¼Œå› æ¤è®¾è®¡å‡ 个分类的维度也是一个需è¦ä»”ç»†è€ƒè™‘çš„é—®é¢˜ã€‚å› ä¸ºå¼€å‘人员在写日志的时候,需è¦è€ƒè™‘的问题目å‰è‡³å°‘有:什么级别,什么内容。我们æ¯å¢žåŠ 一个日志的分类维度,就使得开å‘äººå‘˜å¢žåŠ äº†ä¸€ä¸ªéœ€è¦è€ƒè™‘的问题,这æžå¤§çš„å¢žåŠ äº†å¼€å‘人员的工作,也å¯èƒ½æ˜¯çš„å¼€å‘äººå‘˜å› æ¤å¼€å§‹ä¸å–œæ¬¢å†™è°ƒè¯•æ—¥å¿—,å而适得其åã€‚å› æ¤ï¼Œæˆ‘们的ç»éªŒæ˜¯æœ€å¤šåªæ·»åŠ 一ç§åˆ†ç±»çš„维度,这ç§é€šå¸¸å°±æ˜¯åŸºäºŽæ¨¡å—的分类。
Tip 5ï¼šæ·»åŠ è°ƒè¯•æ—¥å¿—çš„å·¥ä½œè¶Šç®€å•ï¼Œå¼€å‘人员越喜欢在代ç 当ä¸æ·»åŠ 调试日志。
基于模å—的分类和过滤方案å¯ä»¥æœ‰å¤šç§æ–¹å¼å®žçŽ°ã€‚第一ç§æ˜¯å¯¹äºŽä¸åŒçš„模å—使用ä¸åŒçš„é…置项控制其调试级别,之间互ä¸å½±å“。å¦ä¸€ç§ä½¿ç”¨å…¨å±€çš„é…置项控制调试级别,但是对于ä¸åŒæ¨¡å—的日志文件使用ä¸åŒçš„文件åå‰ç¼€ã€‚例如按照第一部分的那ç§æ—¥å¿—文件命å方案,使用ä¸åŒçš„basename。第三ç§æ–¹æ¡ˆåˆ™ä½¿ç”¨ç±»ä¼¼äºŽåˆ†çº§çš„æ–¹å¼å®žçŽ°ï¼Œå¼€å‘人员在代ç 当ä¸åŠ 入调试日志的时候,指定一个模å—çš„æ ‡è¯†ï¼Œè€Œåœ¨ç¨‹åºè¿è¡Œçš„时候,通过æŸç§æ–¹å¼å¦‚命令行和é…置文件æ¥æŒ‡å®šéœ€è¦æ˜¾ç¤ºçš„模å—,æ¥å®žçŽ°åŸºäºŽæ¨¡å—的过滤。
三ç§æ–¹æ¡ˆå„有其优劣。
第一ç§æ–¹æ¡ˆçš„优势在于å¯ä»¥ç»†è‡´çš„控制å„个模å—的日志信æ¯ã€‚è¿™ç§åœ¨çŽ°åœºè°ƒè¯•çš„æ—¶å€™æ¯”è¾ƒæœ‰ä¼˜åŠ¿ï¼Œä½†æ˜¯åœ¨æ— æ³•çŽ°åœºæ”¯æŒçš„时候就å˜åœ¨ä¸€å®šçš„æ“ä½œéš¾åº¦ã€‚å› ä¸ºå¯¹äºŽæ”¯æŒäººå‘˜æ¥è¯´ï¼Œå¾€å¾€å€¾å‘于拿到尽å¯èƒ½è¯¦ç»†çš„æ—¥å¿—ï¼Œå› æ¤åœ¨æœé›†æ—¥å¿—的时候,也往往è¦æ±‚用户将模å—çš„è°ƒè¯•çº§åˆ«éƒ½è°ƒåˆ°æœ€è¯¦ç»†ã€‚è¿™æ ·ä¸€æ¥ï¼Œä¸€æ–¹é¢å¢žåŠ 了用户的æ“作难度,å¦ä¸€æ–¹é¢å¯¹äºŽæœ€åŽåˆ†æžæ—¥å¿—çš„å¼€å‘人员æ¥è¯´ï¼Œè¿™ç§æ–¹æ¡ˆå¹¶æ²¡æœ‰æ”¹å˜å¤šå°‘é—®é¢˜ã€‚å› æ¤ï¼Œ
Tip 6:å³ä½¿éœ€è¦å¯¹äºŽæ¯ä¸ªæ¨¡å—分别控制日志级别,最好也能够æ供一个全局的日志级别控制选项。
第二ç§æ–¹æ¡ˆåˆ™ç¨æœ‰æ”¹è¿›ï¼Œå…¶ä¼˜åŠ¿åœ¨äºŽä¾¿äºŽæœé›†å’Œæµè§ˆï¼Œå› 为æ¯ä¸ªæ–‡ä»¶éƒ½å•çº¯çš„对应于一个模å—,ä¸å˜åœ¨æ¨¡å—之间互相穿æ’çš„é—®é¢˜ï¼Œå› æ¤äººé˜…读比较容易,也便于工具的处ç†ã€‚但是如果模å—划分过细,会导致难于跟踪模å—之间的互æ“作。比如模å—A会在处ç†è¿‡ç¨‹å½“ä¸è°ƒç”¨æ¨¡å—B,但是两者的日志分布在ä¸åŒçš„日志文件当ä¸ï¼Œè¿™æ ·çš„结果往往是在察看日志的时候,需è¦åœ¨ä¸¤ä¸ªæ—¥å¿—文件之间跳æ¥è·³åŽ»ï¼Œå而使得分æžå˜å¾—éº»çƒ¦ã€‚å› æ¤è¿™ç§æ–¹æ¡ˆé€šå¸¸ç”¨åœ¨æ¯”较粗粒度的å系统级别。将ä¸åŒå系统的日志输出到ä¸åŒå‰ç¼€çš„日志文件,å¯ä»¥åœ¨åˆ’分模å—和便于分æžä¹‹é—´æ‰¾åˆ°ä¸€ç§æŠ˜ä¸ã€‚而且结åˆç¬¬ä¸€ç§æ–¹æ¡ˆï¼Œä¹Ÿå¯ä»¥å¯¹äºŽä¸åŒçš„å系统æä¾›ä¸åŒçš„调试级别的控制。
Tip 7:在å系统级别上,让ä¸åŒçš„å系统把日志输出到ä¸åŒçš„日志文件
第三ç§æ–¹æ¡ˆåˆ™åœ¨ç¬¬äºŒç§æ–¹æ¡ˆä¸Šé¢æ›´è¿›äº†ä¸€æ¥ï¼Œå¯ä»¥ç”¨æ¥åŒºåˆ†å系统当ä¸ä¸åŒçš„模å—。这ç§æ–¹æ¡ˆå½“ä¸å¯¹äºŽæ¨¡å—æ ‡è¯†çš„é€‰æ‹©ä¹Ÿæœ‰å‡ ç§ä¸åŒçš„设计。一ç§æ˜¯ä½¿ç”¨çŸå—符串作为模å—çš„æ ‡è¯†ï¼Œä¾‹å¦‚main,server,clientç‰å—符串,而在é…置文件当ä¸ï¼Œä½¿ç”¨é€—å·æˆ–其他符å·åˆ†å‰²çš„å—符串选择需è¦è¾“出的模å—。å¦ä¸€ç§æ–¹æ¡ˆæ˜¯ä½¿ç”¨æ•´æ•°çš„ä½æŽ©ç (bit mask),æ¯ä¸ªæ¨¡å—对应于一个整数当ä¸çš„一个ä½ï¼Œè€Œä½¿ç”¨ä½ANDæ“作æ¥ç¡®å®šæ˜¯å¦éœ€è¦è¾“出该模å—çš„ä¿¡æ¯ã€‚表é¢çœ‹èµ·æ¥ä¼¼ä¹Žå‰è€…更具有良好的å¯è¯»æ€§å’Œå¯é…置性,而åŽè€…则相对难于ç†è§£å’Œé…置。但实际当ä¸ï¼Œè¿™ç§è€ƒè™‘应该放在相对较为次è¦çš„ä½ç½®ã€‚å› ä¸ºç”¨æˆ·å¯¹äºŽæ¨¡å—的调试日志的控制往往也是两个æžç«¯ï¼šnone或all,而如何让开å‘äººå‘˜æ›´åŠ å®¹æ˜“çš„æ·»åŠ è°ƒè¯•æ—¥å¿—ï¼Œä»¥åŠæ‹¿åˆ°æ‰€æœ‰æ¨¡å—éƒ½æ‰“å¼€çš„æ—¥å¿—çš„æ—¶å€™å¦‚ä½•ä¾¿äºŽæ ¹æ®æ¨¡å—进行过滤和分æžï¼Œæ‰æ˜¯è®¾è®¡è°ƒè¯•æ—¥å¿—方案的首è¦è€ƒè™‘ã€‚å› æ¤ï¼Œæˆ‘更倾å‘于使用第二ç§æ–¹æ¡ˆæ¥å®žçŽ°ï¼Œè¿™æ ·åœ¨æœ€åŽçš„日志分æžå½“ä¸ï¼Œæ›´å®¹æ˜“用脚本æ¥è¿›è¡Œè¾…助。与日志级别类似,在最终的日志文件当ä¸ï¼Œä¹Ÿåº”该记录该日志æ¡ç›®æ‰€ä»Žå±žçš„类别。
Tip 8:在å系统内部,对于ä¸åŒçš„模å—,使用ä¸åŒçš„模å—æ ‡è¯†ï¼Œä¾¿äºŽå¼€å‘人员进行分æžå’Œè¿‡æ»¤ã€‚
实际当ä¸ï¼Œè¿™ä¸‰ç§æ–¹æ¡ˆæ”¾åœ¨ä¸€èµ·å®žçŽ°æ˜¯æœ€ä¸ºæœ‰æ•ˆçš„。总结一下就是:æ供一个全局的调试级别控制,在æ¯ä¸ªå系统上é¢æ供一个该å系统的级别控制,该控制默认情况下使用全局控制,在特殊情况下å¯ä»¥è¦†ç›–全局控制;让ä¸åŒå系统的日志输出到ä¸åŒçš„日志文件当ä¸ï¼›å系统内部的模å—使用模å—æ ‡è¯†åŒºåˆ†ï¼Œå¹¶å°†å…¶è®°å½•è¿›æœ€ç»ˆçš„æ—¥å¿—æ¡ç›®å½“ä¸ï¼Œä¾¿äºŽå¼€å‘人员使用人工或脚本过滤和区分。
如上Tip 5æ‰€è¿°ï¼Œæˆ‘ä»¬å¸Œæœ›æ·»åŠ çš„æ¨¡å—ä¿¡æ¯ä¸ä¼šå¢žåŠ å¼€å‘äººå‘˜çš„å·¥ä½œï¼Œå› æ¤å®žçŽ°æ—¥å¿—æ ¹æ®æ¨¡å—划分类别,å¯ä»¥é‡‡ç”¨äº†ä¸€äº›tricksæ¥ç®€åŒ–æ—¥å¿—çš„æ·»åŠ å·¥ä½œã€‚ä¾‹å¦‚ï¼Œæ¯ä¸ªæºä»£ç 文件通常都åªä»Žå±žäºŽä¸€ä¸ªæ¨¡å—ï¼Œå› æ¤ï¼Œæˆ‘们å¯ä»¥åœ¨æ¯ä¸ªæºä»£ç æ–‡ä»¶çš„é¡¶ç«¯æ·»åŠ å®ƒä»Žå±žçš„æ¨¡å—çš„ä¿¡æ¯ï¼Œè€Œä½¿ç”¨å®æ¥è‡ªåŠ¨çš„在æ¯æ¡æ—¥å¿—当ä¸æ·»åŠ 模å—ä¿¡æ¯ã€‚è¿™æ ·ï¼Œå¼€å‘äººå‘˜å…¶å®žå¹¶æ²¡æœ‰å¢žåŠ å¤ªå¤šçš„å·¥ä½œè¦åšã€‚
而在实际当ä¸ï¼Œå¾ˆå¤šæ—¶å€™ç®€å•çš„æ ¹æ®æ—¥å¿—从属的模å—区分还ä¸å¤Ÿï¼Œæ¯”如å¯èƒ½éœ€è¦æŠŠæ‰€æœ‰çš„函数跟踪日志和路径跟踪日志作为两个å•ç‹¬çš„级别,这时也许我们就需è¦å¼•å…¥ä¸€äº›åˆ«çš„分类方å¼ï¼Œä½†æ˜¯å³ä½¿æœ‰è¿™ç§éœ€æ±‚,我们也建议把他们并入到模å—级别当ä¸ï¼Œå› ä¸ºä»»ä½•ä¸€ä¸ªå¢žåŠ çš„ç»´åº¦éƒ½æ˜¯ä»¥å¢žåŠ å¼€å‘人员的工作作为代价的。通常,我们建议使用å®æ¥ç®€åŒ–è¿™äº›æ·»åŠ åŠ¨ä½œï¼Œè€Œä¸”ï¼Œé™¤éžçœŸçš„å¿…è¦ï¼ˆå¾ˆå¤šæ—¶å€™è¿™ä¸¤ç§éœ€æ±‚是å¯ä»¥ç”±å…¶ä»–的日志代替的),我们ä¸å»ºè®®å¢žåŠ 更多的日志分类方å¼ã€‚
Tip 9:使用一些tricksæ¥ç®€åŒ–è°ƒè¯•æ—¥å¿—çš„æ·»åŠ ï¼Œå‡å°‘å¼€å‘人员在写调试日志时需è¦è€ƒè™‘的问题。
下é¢ï¼Œæˆ‘们开始探讨如何在æ£ç¡®çš„åœ°æ–¹æ·»åŠ æ£ç¡®çš„日志,也就是“日志应该写些什么â€çš„问题。