<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          如何使錯(cuò)誤日志更加方便排查問(wèn)題

          共 10555字,需瀏覽 22分鐘

           ·

          2021-03-22 11:23

          不點(diǎn)藍(lán)字,我們哪來(lái)故事?

          每天 11 點(diǎn)更新文章,餓了點(diǎn)外賣(mài),點(diǎn)擊 ??《無(wú)門(mén)檻外賣(mài)優(yōu)惠券,每天免費(fèi)領(lǐng)!》

          作者 | 琴水玉

          來(lái)源 | https://cnblogs.com/lovesqcc/p/4319594.html
          在程序中打錯(cuò)誤日志的主要目標(biāo)是為更好地排查問(wèn)題和解決問(wèn)題提供重要線(xiàn)索和指導(dǎo)。但是在實(shí)際中打的錯(cuò)誤日志內(nèi)容和格式變化多樣,錯(cuò)誤提示上可能殘缺不全、沒(méi)有相關(guān)背景、不明其義,使得排查解決問(wèn)題成為非常不方便或者耗時(shí)的操作。而實(shí)際上,如果編程的時(shí)候稍加用心,就會(huì)減少排查問(wèn)題的很多無(wú)用功。 在闡述如何編寫(xiě)有效的錯(cuò)誤日志之前, 了解錯(cuò)誤是怎么產(chǎn)生的, 非常重要。

          錯(cuò)誤是如何煉成的

          對(duì)于當(dāng)前系統(tǒng)來(lái)說(shuō), 錯(cuò)誤的產(chǎn)生由三個(gè)地方引入:

          1.上層系統(tǒng)引入的非法參數(shù)。對(duì)于非法參數(shù)引入的錯(cuò)誤, 可以通過(guò)參數(shù)校驗(yàn)和前置條件校驗(yàn)來(lái)截獲錯(cuò)誤;

          2.與下層系統(tǒng)交互產(chǎn)生的錯(cuò)誤。與下層交互產(chǎn)生的錯(cuò)誤, 有兩種:

          a.下層系統(tǒng)處理成功了,但是通信出錯(cuò)了, 這樣會(huì)導(dǎo)致子系統(tǒng)之間的數(shù)據(jù)不一致;

          對(duì)于這種情況, 可以采用超時(shí)補(bǔ)償機(jī)制,預(yù)先將任務(wù)記錄下來(lái),通過(guò)定時(shí)任務(wù)在后續(xù)將數(shù)據(jù)訂正過(guò)來(lái)。

          更好的設(shè)計(jì)方案 ?

          b.通信成功了,但是下層處理出錯(cuò)了。

          對(duì)于這種情況, 需要與下層開(kāi)發(fā)人員溝通, 協(xié)調(diào)子系統(tǒng)之間的交互;

          需要根據(jù)下層返回的錯(cuò)誤碼和錯(cuò)誤描述做適當(dāng)?shù)奶幚砘蚪o予合理的提示信息。

          無(wú)論哪一種情況, 都要假設(shè)下層系統(tǒng)可靠性一般, 做好出錯(cuò)的設(shè)計(jì)考慮。

          3.本層系統(tǒng)處理出錯(cuò)。

          本層系統(tǒng)產(chǎn)生錯(cuò)誤的原因:

          原因一:疏忽導(dǎo)致。 疏忽是指程序員能力完全可避免此類(lèi)錯(cuò)誤但實(shí)際上沒(méi)做到。比如將 && 敲成了 & , == 敲成了 = ;邊界錯(cuò)誤, 復(fù)合邏輯判斷錯(cuò)誤等。疏忽要么是程序員注意力不夠集中, 比如處于疲倦狀態(tài)、加班通宵、邊開(kāi)會(huì)邊寫(xiě)程序;要么是急著實(shí)現(xiàn)功能,沒(méi)有顧及程序的健壯性等。

          改進(jìn)措施:使用代碼靜態(tài)分析工具,通過(guò)單元測(cè)試行覆蓋可有效避免此類(lèi)問(wèn)題。

          原因二:錯(cuò)誤與異常處理不夠周全導(dǎo)致的。 比如輸入問(wèn)題。計(jì)算兩個(gè)數(shù)相加, 不僅要考慮計(jì)算溢出問(wèn)題, 還要考慮輸入非法的情形。對(duì)于前者,可能通過(guò)了解、犯錯(cuò)或經(jīng)驗(yàn)就可以避免, 而對(duì)于后者,則必須加以限定,以使之處于我們的智商能夠控制的范圍內(nèi),比如使用正則表達(dá)式過(guò)濾掉不合法的輸入。對(duì)于正則表達(dá)式必須進(jìn)行測(cè)試。對(duì)于不合法輸入, 要給出盡可能詳細(xì)、易懂、友好的提示信息、原因及建議方案。

          改進(jìn)措施:盡可能周全地考慮各種錯(cuò)誤情形和異常處理。在實(shí)現(xiàn)主流程之后,增加一個(gè)步驟:仔細(xì)推敲可能的各種錯(cuò)誤和異常,返回合理錯(cuò)誤碼和錯(cuò)誤描述。每個(gè)接口或模塊都有效處理好自己的錯(cuò)誤和異常,可有效避免因場(chǎng)景交互復(fù)雜導(dǎo)致的bug. 譬如,一個(gè)業(yè)務(wù)用例由場(chǎng)景A.B.C交互完成。實(shí)際執(zhí)行A.B成功了,C失敗了,這時(shí)B需要根據(jù)C返回合理的代碼和消息進(jìn)行回滾并返回給A合理的代碼和消息,A根據(jù)B的返回進(jìn)行回滾,并返回給客戶(hù)端合理的代碼和消息。這是一種分段回滾的機(jī)制,要求每個(gè)場(chǎng)景都必須考慮異常情況下的回滾。

          原因三:邏輯耦合緊密導(dǎo)致。 由于業(yè)務(wù)邏輯耦合緊密, 隨著軟件產(chǎn)品一步步發(fā)展, 各種邏輯關(guān)系錯(cuò)綜復(fù)雜, 難以看到全局狀況, 導(dǎo)致局部修改影響波及到全局范圍,造成不可預(yù)知的問(wèn)題。

          改進(jìn)措施:編寫(xiě)短函數(shù)和短方法, 每個(gè)函數(shù)或方法最好不超過(guò) 50 行。編寫(xiě)無(wú)狀態(tài)函數(shù)和方法, 只讀全局狀態(tài), 相同的前提條件總是會(huì)輸出相同的結(jié)果, 不會(huì)依賴(lài)外部狀態(tài)而變更自己的行為;定義合理的結(jié)構(gòu)、 接口和邏輯段, 使接口之間的交互盡可能正交、低耦合;對(duì)于服務(wù)層, 盡可能提供簡(jiǎn)單、正交的接口;持續(xù)重構(gòu), 保持應(yīng)用模塊化和松耦合, 理清邏輯依賴(lài)關(guān)系。對(duì)于有大量業(yè)務(wù)接口相互影響的情況, 必須整理各個(gè)業(yè)務(wù)接口的邏輯流程及相互依賴(lài)關(guān)系, 從整體上進(jìn)行優(yōu)化;對(duì)于有大量狀態(tài)的實(shí)體, 也需要梳理相關(guān)的業(yè)務(wù)接口, 整理狀態(tài)之間的轉(zhuǎn)換關(guān)系。

          原因四:算法不正確導(dǎo)致。

          改進(jìn)措施:首先將算法從應(yīng)用中分離出來(lái)。若算法有多種實(shí)現(xiàn), 可以通過(guò)交叉校驗(yàn)的單元測(cè)試找出來(lái), 比如排序操作;如果算法具有可逆性質(zhì), 可以通過(guò)可逆校驗(yàn)的單元測(cè)試找出來(lái), 比如加密解密操作。

          原因五:相同類(lèi)型的參數(shù),傳入順序錯(cuò)誤導(dǎo)致。 比如,modifyFlow(int rx, int tx), 實(shí)際調(diào)用為 modifyFlow(tx,rx)

          改進(jìn)措施:盡可能使類(lèi)型具體化, 該用浮點(diǎn)數(shù)就用浮點(diǎn)數(shù), 該用字符串就用字符串, 該用具體對(duì)象類(lèi)型就用具體對(duì)象類(lèi)型;相同類(lèi)型的參數(shù)盡可能錯(cuò)開(kāi);如果上述都無(wú)法滿(mǎn)足, 就必須通過(guò)接口測(cè)試來(lái)驗(yàn)證, 接口參數(shù)值務(wù)必是不同的。

          原因六:空指針異常。 空指針異常通常是對(duì)象沒(méi)有正確初始化, 或者使用對(duì)象之前沒(méi)有對(duì)對(duì)象是否非空做檢測(cè)。

          改進(jìn)措施:對(duì)于配置對(duì)象, 檢測(cè)其是否成功初始化;對(duì)于普通對(duì)象, 獲取到實(shí)體對(duì)象使用之前, 檢測(cè)是否非空。

          原因七:網(wǎng)絡(luò)通信錯(cuò)誤。 網(wǎng)絡(luò)通信錯(cuò)誤通常是因?yàn)榫W(wǎng)絡(luò)延遲、阻塞或不通導(dǎo)致的錯(cuò)誤。網(wǎng)絡(luò)通信錯(cuò)誤通常是小概率事件, 但小概率事件很可能會(huì)導(dǎo)致大面積的故障、 難以復(fù)現(xiàn)的BUG。

          改進(jìn)措施:在前一個(gè)子系統(tǒng)的結(jié)束點(diǎn)和后一個(gè)子系統(tǒng)的入口點(diǎn)分別打 INFO 日志。通過(guò)兩者的時(shí)間差提供一點(diǎn)線(xiàn)索。

          原因八:事務(wù)與并發(fā)錯(cuò)誤。 事務(wù)與并發(fā)結(jié)合在一起, 很容易產(chǎn)生非常難以定位的錯(cuò)誤。

          改進(jìn)措施:對(duì)于程序中的并發(fā)操作, 涉及到共享變量及重要狀態(tài)修改的, 要加 INFO 日志。更有效的做法???

          原因九:配置錯(cuò)誤。

          改進(jìn)措施:在啟動(dòng)應(yīng)用或啟動(dòng)相應(yīng)配置時(shí), 檢測(cè)所有的配置項(xiàng), 打印相應(yīng)的INFO日志, 確保所有配置都加載成功。

          原因十:業(yè)務(wù)不熟悉導(dǎo)致的錯(cuò)誤。 在中大型系統(tǒng), 部分業(yè)務(wù)邏輯和業(yè)務(wù)交互都比較復(fù)雜, 整個(gè)的業(yè)務(wù)邏輯可能存在于多個(gè)開(kāi)發(fā)同學(xué)的大腦里, 每個(gè)人的認(rèn)識(shí)都不是完整的。這很容易導(dǎo)致業(yè)務(wù)編碼錯(cuò)誤。

          改進(jìn)措施:通過(guò)多人討論和溝通, 設(shè)計(jì)正確的業(yè)務(wù)用例, 根據(jù)業(yè)務(wù)用例來(lái)編寫(xiě)和實(shí)現(xiàn)業(yè)務(wù)邏輯;最終的業(yè)務(wù)邏輯和業(yè)務(wù)用例必須完整存檔;在業(yè)務(wù)接口中注明該業(yè)務(wù)的前置條件、處理邏輯、后置校驗(yàn)和注意事項(xiàng);當(dāng)業(yè)務(wù)變化時(shí), 需要同步更新業(yè)務(wù)注釋?zhuān)淮aREVIEW。業(yè)務(wù)注釋是業(yè)務(wù)接口的重要文檔, 對(duì)業(yè)務(wù)理解起著重要的緩存作用。

          原因十一:設(shè)計(jì)問(wèn)題導(dǎo)致的錯(cuò)誤。 比如同步串行方式會(huì)有性能、響應(yīng)慢的問(wèn)題, 而并發(fā)異步方式可以解決性能、響應(yīng)慢的問(wèn)題, 但會(huì)帶來(lái)安全、正確性的隱患。異步方式會(huì)導(dǎo)致編程模型的改變, 新增異步消息推送和接收等新的問(wèn)題。使用緩存能夠提高性能, 但是又會(huì)存在緩存更新的問(wèn)題。

          改進(jìn)措施:編寫(xiě)和仔細(xì)評(píng)審設(shè)計(jì)文檔。設(shè)計(jì)文檔必須闡述背景、需求、所滿(mǎn)足的業(yè)務(wù)目標(biāo)、要達(dá)到的業(yè)務(wù)性能指標(biāo)、可能的影響、設(shè)計(jì)總體思路、詳細(xì)方案、預(yù)見(jiàn)該方案的優(yōu)缺點(diǎn)及可能的影響;通過(guò)測(cè)試和驗(yàn)收, 確保改設(shè)計(jì)方案確實(shí)滿(mǎn)足業(yè)務(wù)目標(biāo)和業(yè)務(wù)性能指標(biāo)。

          原因十二:未知細(xì)節(jié)問(wèn)題導(dǎo)致的錯(cuò)誤。 比如緩沖區(qū)溢出、 SQL 注入攻擊。從功能上看是沒(méi)有問(wèn)題的, 但是從惡意使用上看, 是存在漏洞的。再比如, 選擇 jackson 庫(kù)做 JSON 字符串解析, 默認(rèn)情況下, 當(dāng)對(duì)象新增字段時(shí)會(huì)導(dǎo)致解析出錯(cuò)。必須在對(duì)象上加 @JsonIgnoreProperties(ignoreUnknown = true) 注解才能正確應(yīng)對(duì)變化。如果選用其他 JSON 庫(kù)就不一定有這個(gè)問(wèn)題。

          改進(jìn)措施:一方面要通過(guò)經(jīng)驗(yàn)積累, 另一方面, 考慮安全問(wèn)題和例外情況, 選擇成熟的經(jīng)過(guò)嚴(yán)格測(cè)試的庫(kù)。

          原因十三:隨時(shí)間變化而出現(xiàn)的bug。 有些解決方案在過(guò)去看來(lái)是很不錯(cuò)的,但在當(dāng)前或者未來(lái)的情景中可能變得笨拙甚至不中用,也是常見(jiàn)的事情。比如像加密解密算法, 在過(guò)去可能認(rèn)為是完善的, 在破解之后就要慎重使用了。

          改進(jìn)措施:關(guān)注變化以及漏洞修復(fù)消息,及時(shí)修正過(guò)時(shí)的代碼、庫(kù)、行為。

          原因十四:硬件相關(guān)的錯(cuò)誤。 比如內(nèi)存泄露, 存儲(chǔ)空間不足, OutOfMemoryError 等。

          改進(jìn)措施:增加對(duì)應(yīng)用系統(tǒng)的 CPU / 內(nèi)存 / 網(wǎng)絡(luò)等重要指標(biāo)的性能監(jiān)控。

          系統(tǒng)出現(xiàn)的常見(jiàn)錯(cuò)誤:

          1.實(shí)體在數(shù)據(jù)庫(kù)中的記錄不存在, 必須指明是哪個(gè)實(shí)體或?qū)嶓w標(biāo)識(shí);

          2.實(shí)體配置不正確, 必須指明是哪個(gè)配置有問(wèn)題,正確的配置應(yīng)該是什么;

          3.實(shí)體資源不滿(mǎn)足條件, 必須指明當(dāng)前資源是什么,資源要求是什么;

          4.實(shí)體操作前置條件不滿(mǎn)足, 必須指明需要滿(mǎn)足什么前置條件,當(dāng)前的狀態(tài)是什么;

          5.實(shí)體操作后置校驗(yàn)不滿(mǎn)足, 必須指明需要滿(mǎn)足什么后置校驗(yàn), 當(dāng)前的狀態(tài)是什么;

          6.性能問(wèn)題導(dǎo)致超時(shí), 必須指明是什么導(dǎo)致的性能問(wèn)題,后續(xù)如何優(yōu)化;

          7.多個(gè)子系統(tǒng)交互通信出錯(cuò)導(dǎo)致之間的狀態(tài)或數(shù)據(jù)不一致?

          一般難以定位的錯(cuò)誤會(huì)出現(xiàn)在比較底層的地方。因?yàn)榈讓訜o(wú)法預(yù)知具體的業(yè)務(wù)場(chǎng)景, 給出的錯(cuò)誤消息都是比較通用的。

          這就要求在業(yè)務(wù)上層提供盡可能豐富的線(xiàn)索。錯(cuò)誤的產(chǎn)生一定是多個(gè)系統(tǒng)或?qū)哟谓换サ倪^(guò)程中在某一層棧上不滿(mǎn)足前置條件導(dǎo)致。在編程時(shí), 在每一層棧中盡可能確保所有必須的前置條件滿(mǎn)足,盡可能避免錯(cuò)誤的參數(shù)傳遞到底層, 盡可能地將錯(cuò)誤截獲在業(yè)務(wù)層。

          大多數(shù)錯(cuò)誤都是由多種原因組合產(chǎn)生。但每一種錯(cuò)誤必定有其原因。在解決錯(cuò)誤之后, 要深入分析錯(cuò)誤是如何發(fā)生的, 如何避免這些錯(cuò)誤再次發(fā)生。努力就能成功, 但是: 反思才能進(jìn)步 !

          如何編寫(xiě)更容易排查問(wèn)題的錯(cuò)誤日志

          打錯(cuò)誤日志的基本原則:

          1.盡可能完整。每一條錯(cuò)誤日志都完整描述了:什么場(chǎng)景下發(fā)生了什么錯(cuò)誤, 什么原因(或者哪些可能原因), 如何解決(或解決提示);

          2.盡可能具體。比如 NC 資源不足, 究竟具體指什么資源不足, 是否可以通過(guò)程序直接指明;通用錯(cuò)誤,比如 VM NOT EXIST , 要指明在什么場(chǎng)景下發(fā)生的,可能便于后續(xù)統(tǒng)計(jì)的工作。

          3.盡可能直接。最理想的錯(cuò)誤日志應(yīng)該讓人在第一直覺(jué)下能夠知道是什么原因?qū)е?,該怎么去解決,而不是還要通過(guò)若干步驟去查找真正的原因。

          4.將已有經(jīng)驗(yàn)集成直接到系統(tǒng)中。所有已經(jīng)解決過(guò)的問(wèn)題及經(jīng)驗(yàn)都要盡可能以友好的方式集成到系統(tǒng)中,給新進(jìn)人員更好的提示,而不是埋藏在其他地方。

          5.排版要整潔有序, 格式統(tǒng)一化規(guī)范化。密密麻麻、隨筆式的日志看著就揪心, 相當(dāng)不友好, 也不便于排查問(wèn)題。

          6.采用多個(gè)關(guān)鍵字唯一標(biāo)識(shí)請(qǐng)求,突出顯示關(guān)鍵字:時(shí)間、實(shí)體標(biāo)識(shí)(比如vmname)、操作名稱(chēng)。

          排查問(wèn)題的基本步驟:

          登錄到應(yīng)用服務(wù)器 -> 打開(kāi)日志文件 -> 定位到錯(cuò)誤日志位置 -> 根據(jù)錯(cuò)誤日志的線(xiàn)索的指導(dǎo)去排查、確認(rèn)問(wèn)題和解決問(wèn)題。

          其中:

          1.從登陸到打開(kāi)日志文件:由于應(yīng)用服務(wù)器有多臺(tái), 要逐一登錄上去查看實(shí)在不方便。需要編寫(xiě)一個(gè)工具放在 AG 上直接在 AG 上查看所有服務(wù)器日志, 甚至直接篩選出所需要的錯(cuò)誤日志。

          2.定位錯(cuò)誤日志位置。目前日志的排版密密麻麻,不易定位到錯(cuò)誤日志。一般可以先采用"時(shí)間"來(lái)定位到錯(cuò)誤日志的附近前面的地方, 然后使用 實(shí)體關(guān)鍵字 / 操作名稱(chēng) 組合來(lái)鎖定錯(cuò)誤日志地方。根據(jù) requestId 定位錯(cuò)誤日志雖然比較符合傳統(tǒng),但是要先找到 requestId , 并且不具有描述性。最好能直接根據(jù)時(shí)間/內(nèi)容關(guān)鍵字來(lái)定位錯(cuò)誤日志位置。

          3.分析錯(cuò)誤日志。錯(cuò)誤日志的內(nèi)容最好能夠更加直接明了, 能夠明確指明與當(dāng)前要排查的問(wèn)題特征是吻合的, 并且給出重要線(xiàn)索。

          通常, 程序錯(cuò)誤日志的問(wèn)題就是日志內(nèi)容是針對(duì)當(dāng)前代碼情境才能理解,看上去簡(jiǎn)潔, 但總是寫(xiě)的不全, 半英文格式;一旦離開(kāi)代碼情境, 就很難知道究竟說(shuō)的是什么, 非要讓人思考一下或者去看看代碼才能明白日志說(shuō)的是什么含義。這不是自己給自己罪受?

          比如:

          if ((storageType == StorageType.dfs1 || storageType == StorageType.dfs2)
                          && (zone.hasStorageType(StorageType.io3) || zone.hasStorageType(StorageType.io4))) {
          // 進(jìn)入dfs1 和dfs2 在io3 io4 存儲(chǔ)。
          else {
                log.info("zone storage type not support, zone: " + zone.getZoneId() + ", storageType: "
          + storageType.name());
                throw new BizException(DeviceErrorCode.ZONE_STORAGE_TYPE_NOT_SUPPORT);
          }

          zone 要支持什么 storage type 才是正確的? Do Not Let Me Think !

          錯(cuò)誤日志應(yīng)該做到:即使離開(kāi)代碼情境,也能清晰地描述發(fā)生了什么。

          此外,如果能夠直接在錯(cuò)誤日志中說(shuō)明清楚原因, 在做巡檢日志的時(shí)候也可以省些力氣。

          從某種意義上來(lái)說(shuō), 錯(cuò)誤日志也可以是一種非常有益的文檔,記錄著各種不合法的運(yùn)行用例。

          目前程序錯(cuò)誤日志的內(nèi)容可能存在如下問(wèn)題:

          1. 錯(cuò)誤日志沒(méi)有指明錯(cuò)誤參數(shù)和內(nèi)容:

          catch(Exception ex){
                log.error("control ip insert failed", ex);
                return new ResultSet<AddControlIpResponse>(
          ControlIpErrorCode.ERROR_CONTROL_IP_INSERT_FAILURE);
          }

          沒(méi)有指明插入失敗的 control ip. 如果加上 control ip 關(guān)鍵字, 更容易搜索和鎖定錯(cuò)誤。

          類(lèi)似的還有:

          log.error("Get some errors when insert subnet and its IPs into database. Add subnet or IP failure.", e);

          沒(méi)有指明是哪個(gè) subnet 的它下屬的哪些 IP. 值得注意的是, 要指明這些要額外做一些事情, 可能會(huì)稍微影響性能。這時(shí)候需要權(quán)衡性能和可調(diào)試性。

          解決方案:使用 String.format("Some msg to ErrorObj: %s", errobj) 方法指明錯(cuò)誤參數(shù)及內(nèi)容。

          這通常要求對(duì) DO 對(duì)象編寫(xiě)可讀的 toString 方法。

          2. 錯(cuò)誤場(chǎng)景不明確:

          log.error("nc has exist, nc ip" + request.getIp());

          在 createNc 中檢測(cè)到 NC 已經(jīng)存在報(bào)錯(cuò)。但是日志上沒(méi)有指明錯(cuò)誤場(chǎng)景, 讓人猜測(cè),為什么會(huì)報(bào)NC已存在錯(cuò)誤。

          可以改為

          log.error("nc has exist when want to create nc, please check nc parameters. Given nc ip: " + request.getIp());

          log.error("[create nc] nc has exist, please check nc parameters. Given nc ip: " + request.getIp());

          類(lèi)似的還有:

          log.error("not all vm destroyed, nc id " + request.getNcId());

          改成 log.error("[delete nc] some vms [%s] in the nc are not destroyed. nc id: %s", vmNames, request.getNcId());

          解決方案:錯(cuò)誤消息加上 when 字句, 或者錯(cuò)誤消息前加上 【接口名】, 指明錯(cuò)誤場(chǎng)景,直接從錯(cuò)誤日志就知道明白了。

          一般能夠知道 executor 的可以加上 【接口名】, service 加上 when 字句。

          3. 內(nèi)容不明確, 或不明其義:

          if(aliMonitorReporter == null) {
                  log.error("aliMonitorReporter is null!");
          else {
                 aliMonitorReporter.attach(new ThreadPoolMonitor(namePrefix, asynTaskThreadPool.getThreadPoolExecutor()));
          }

          改為:log.error("aliMonitorReporter is null, probably not initialized properly, please check configuration in file xxx.");

          類(lèi)似的還有:

          if (diskWbps == null && diskRbps == null && diskWiops == null    && diskRiops == null) {
                log.error("none of attribute is specified for modifying");
                throw new BizException(DeviceErrorCode.NO_ATTRIBUTE_FOR_MODIFY);
          }

          改為 log.error("[modify disk attribute] None of [diskWbps,diskRbps,diskWiops,diskRiops] is specified for disk id:" + diskId);

          解決方案:更清晰貼切地描述錯(cuò)誤內(nèi)容。

          4. 排查問(wèn)題的引導(dǎo)內(nèi)容不明確:

          log.error("get gw group ip segment failed. zkPath: " + LockResource.getGwGroupIpSegmnetLockPath(request.getGwGroupId()));

          zkPath ? 如何去排查這個(gè)問(wèn)題?我該去找誰(shuí)?到哪里去查找更具體的線(xiàn)索?

          解決方案:加上相應(yīng)的背景知識(shí)和引導(dǎo)排查措施。

          5. 錯(cuò)誤內(nèi)容不夠具體細(xì)致:

          if (!ncResourceService.isNcResourceEnough(ncResourceDO,    vmResourceCondition)) {
                log.error("disk space is not enough at vm's nc, nc id:" + vmDO.getNcId());
                throw new BizException(ResourceErrorCode.ERROR_RESOURCE_NOT_ENOUGH);
          }

          究竟是什么資源不夠?目前剩余多少?現(xiàn)在需要多少?值得注意的是, 要指明這些要額外做一些事情, 可能會(huì)稍微影響性能。這時(shí)候需要權(quán)衡性能和可調(diào)試性。

          解決方案:通過(guò)改進(jìn)程序或程序技巧, 盡可能揭示出具體的差異所在, 減少人工比對(duì)的操作。

          6. 半英文句式讀起來(lái)不夠清晰明白,需要思考來(lái)拼湊起完整的意思:

          log.warn("cache status conflict, device id "+deviceDO.getId()+" db status "+deviceDO.getStatus() +", nc status "+ status);

          改為:

          log.warn(String.format("[query cache status] device cache status conflicts between regiondb and nc, status of device '%s' in regiondb is %s , but is %s in nc.", deviceDO.getId(), deviceDO.getStatus(), status));

          解決方案:改為自然可讀的英文句式。

          總結(jié)起來(lái), 錯(cuò)誤日志格式可以為:

          log.error("[接口名或操作名] [Some Error Msg] happens. [params] [Probably Because]. [Probably need to do].");

          log.error(String.format("[接口名或操作名] [Some Error Msg] happens. [%s]. [Probably Because]. [Probably need to do].", params));

          log.error("[Some Error Msg] happens to 錯(cuò)誤參數(shù)或內(nèi)容 when [in some condition]. [Probably Because]. [Probably need to do].");

          log.error(String.format("[Some Error Msg] happens to %s when [in some condition]. [Probably Because]. [Probably need to do].", parameters));

          [Probably Reason]. [Probably need to do]. 在某些情況下可以省略;在一些重要接口和場(chǎng)景下最好能說(shuō)明一下。

          每一條錯(cuò)誤日志都是獨(dú)立的,盡可能完整、具體、直接說(shuō)明何種場(chǎng)景下發(fā)生了什么錯(cuò)誤,由什么原因?qū)е?,要采用什么措施或步驟。

          問(wèn)題:

          1.String.format 的性能會(huì)影響打日志嗎?一般來(lái)說(shuō), 錯(cuò)誤日志應(yīng)該是比較少的, 使用 String.format 的頻度并不會(huì)太高,不會(huì)對(duì)應(yīng)用和日志造成影響。

          2.開(kāi)發(fā)時(shí)間非常緊張時(shí), 有時(shí)間去斟酌字句嗎?建立一個(gè)標(biāo)準(zhǔn)化的內(nèi)容格式,將內(nèi)容往格式套,可以節(jié)省斟酌字句的時(shí)間。

          3.什么時(shí)候使用 info, warn , error ?

          info 用于打印程序應(yīng)該出現(xiàn)的正常狀態(tài)信息, 便于追蹤定位;

          warn 表明系統(tǒng)出現(xiàn)輕微的不合理但不影響運(yùn)行和使用;

          error 表明出現(xiàn)了系統(tǒng)錯(cuò)誤和異常,無(wú)法正常完成目標(biāo)操作。

          http://stackoverflow.com/questions/2031163/when-to-use-log-level-warn-vs-error

          錯(cuò)誤日志是排查問(wèn)題的重要手段之一。當(dāng)我們編程實(shí)現(xiàn)一項(xiàng)功能時(shí), 通常會(huì)考慮可能發(fā)生的各種錯(cuò)誤及相應(yīng)原因:

          要排查出相應(yīng)的原因, 就需要一些關(guān)鍵描述來(lái)定位原因。這就會(huì)形成三元組:

          錯(cuò)誤現(xiàn)象 -> 錯(cuò)誤關(guān)鍵描述 -> 最終的錯(cuò)誤原因。

          需要針對(duì)每一種錯(cuò)誤盡可能提供相應(yīng)的錯(cuò)誤關(guān)鍵描述,從而定位到相應(yīng)的錯(cuò)誤原因。

          也就是說(shuō),編程的時(shí)候,要仔細(xì)思考, 哪些描述是非常有利于定位錯(cuò)誤原因的, 盡可能將這些描述添加到錯(cuò)誤日志中。

          文中沒(méi)有指出的問(wèn)題或困難, 請(qǐng)?zhí)岢瞿愕慕ㄗh。

          往期推薦

          大廠薪酬及 996 的 Top 10名單出來(lái)了!網(wǎng)友:雖996,但錢(qián)給得多啊~

          阿里開(kāi)源的 Arthas 在應(yīng)用診斷上十分牛逼

          紅包免費(fèi)送!

          Redis 低成本、高可用設(shè)計(jì),牛逼!

          下方二維碼關(guān)注我

          技術(shù)草根,堅(jiān)持分享 編程,算法,架構(gòu)

          看完文章,餓了點(diǎn)外賣(mài),點(diǎn)擊 ??《無(wú)門(mén)檻外賣(mài)優(yōu)惠券,每天免費(fèi)領(lǐng)!》

          朋友,助攻一把!點(diǎn)個(gè)在看
          瀏覽 46
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲日韩欧美一级片 | 日韩三级片网站在线观看 | 男人的天堂资源网 | 大香蕉熟女 | 成人做爰A片免费看网站 |