首先記錄異常的根本原因

Logback日志庫的0.9.30版本帶來了一個很棒的新功能:從根(最內部)異常而不是最外部異常開始記錄堆棧跟蹤。 當然,我的興奮與我貢獻了此功能無關。

用塞西爾·德·米勒(Cecil B. de Mille) 的話來解釋:“撰寫博客文章的方法是從堆棧跟蹤開始,直到達到高潮 ” –在這里:

詳細信息還不重要,但是從100英尺視圖中您可以看到很長的堆棧跟蹤,并且有多個相互包裹的異常( 引起 )。 我們將回到此堆棧跟蹤,但首先要介紹一些基礎知識。 如果拋出異常,則會以某種方式記錄日志,以顯示異常發生時瞬間堆棧的外觀。 在最底部,您將看到靜態的main()Thread.run() ,該方法通過調用直到第一個堆棧跟蹤行的方法進行處理,該行指示實際拋出異常的位置。 這非常方便,因為您可以看到導致異常的整個控制流程:

public class BookController {private final BookService bookService = new BookService();public void alpha() { beta(); }private void beta() { gamma(); }private void gamma() { bookService.delta(); }public static void main(String[] args) {new BookController().alpha();}
}class BookService {private final BookDao bookDao = new BookDao();public void delta() { epsilon(); }private void epsilon() { zeta(); }private void zeta() { bookDao.eta(); }
}class BookDao {public void eta() { theta(); }private void theta() { iota(); }public void iota() { throw new RuntimeException("Omega server not available"); }
}

如果您不知道希臘字母 ,則可以從堆棧跟蹤中開始學習(請記住,控制流從底部開始并一直向上):

java.lang.RuntimeException: Omega server not availableat BookDao.iota(BookController.java:50)at BookDao.theta(BookController.java:48)at BookDao.eta(BookController.java:46)at BookService.zeta(BookController.java:41)at BookService.epsilon(BookController.java:39)at BookService.delta(BookController.java:37)at BookController.gamma(BookController.java:22)at BookController.beta(BookController.java:20)at BookController.alpha(BookController.java:18)at BookController.main(BookController.java:26)

太好了吧? 從上到下閱讀時,您可以說: iota()由theta()調用,而eta()則調用…清晰而簡單。 但是,如果有人決定包裝原始異常并重新拋出該異常怎么辦?

public class BookController {private static final Logger log = LoggerFactory.getLogger(BookController.class);private final BookService bookService = new BookService();public void alpha() { beta(); }private void beta() { gamma(); }private void gamma() {try {bookService.delta();} catch (Exception e) {throw new RuntimeException("Sorry, try again later", e);}}public static void main(String[] args) {try {new BookController().alpha();} catch (Exception e) {log.error("", e);}}
}class BookService {private final BookDao bookDao = new BookDao();public void delta() { epsilon(); }private void epsilon() { zeta(); }private void zeta() {try {bookDao.eta();} catch (Exception e) {throw new RuntimeException("Unable to save order", e);}}
}class BookDao {public void eta() { theta(); }private void theta() { iota(); }public void iota() {try {throw new RuntimeException("Omega server not available");} catch (Exception e) {throw new RuntimeException("Database problem", e);}}
}

現在快速:在堆棧跟蹤中找到根本原因!

java.lang.RuntimeException: Sorry, try again laterat BookController.gamma(BookController.java:26)at BookController.beta(BookController.java:20)at BookController.alpha(BookController.java:18)at BookController.main(BookController.java:32)
Caused by: java.lang.RuntimeException: Unable to save orderat BookService.zeta(BookController.java:51)at BookService.epsilon(BookController.java:45)at BookService.delta(BookController.java:43)at BookController.gamma(BookController.java:24)... 8 common frames omitted
Caused by: java.lang.RuntimeException: Database problemat BookDao.iota(BookController.java:66)at BookDao.theta(BookController.java:60)at BookDao.eta(BookController.java:58)at BookService.zeta(BookController.java:49)... 11 common frames omitted
Caused by: java.lang.RuntimeException: Omega server not availableat BookDao.iota(BookController.java:64)... 14 common frames omitted

原來main()不再是最后一行。 更糟糕的是,一切似乎都出現了亂碼,請嘗試再次閱讀希臘字母…現在讓我們回到原始的堆棧跟蹤中。 它來自Spring框架啟動失敗,想象它可能長達數頁。

為了方便起見,我添加了箭頭來標記您重構控制流所應遵循的路徑:從紅色箭頭的尾部( Thread.run() )開始,在中間的某個位置向上,然后…跳至橙色箭頭的尾部。 從橙色箭頭的頭部跳到綠色箭頭的尾巴,依此類推...不是很直觀,您不覺得嗎? 這個紅色的橢圓顯示了什么? 是的,這是失敗的根本原因(最內部的異常)。 另一方面,在最開始打印的異常(通常是您一開始就讀到的異常 )說明了創建DefaultAnnotationHandlerMapping#0時發生的錯誤 (是什么?)真正的錯誤( 沒有匹配的bean類型…… )被巧妙地隱藏了……

那么這個新功能到底是什么呢? 還是我們的簡單例子。 升級到0.9.30之后,只需在日志記錄模式的末尾添加%rEx (或等效的%rootException ):

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>%d{ISO8601} | %-5level | %thread | %logger{1} | %m%n%rEx</pattern></encoder>
</appender>

這將用我親自貢獻的默認堆棧跟蹤打印路由代替。 現在將打印相同的希臘程序:

java.lang.RuntimeException: Omega server not availableat BookDao.iota(BookController.java:64)
Wrapped by: java.lang.RuntimeException: Database problemat BookDao.iota(BookController.java:66)at BookDao.theta(BookController.java:60)at BookDao.eta(BookController.java:58)at BookService.zeta(BookController.java:49)
Wrapped by: java.lang.RuntimeException: Unable to save orderat BookService.zeta(BookController.java:51)at BookService.epsilon(BookController.java:45)at BookService.delta(BookController.java:43)at BookController.gamma(BookController.java:24)
Wrapped by: java.lang.RuntimeException: Sorry, try again laterat BookController.gamma(BookController.java:26)at BookController.beta(BookController.java:20)at BookController.alpha(BookController.java:18)at BookController.main(BookController.java:32)

請仔細將其與先前的輸出進行比較。 首先,第一行指出了問題所在。 在大多數情況下,您可能都不會跳過“ 由...引起的 ”例外,因此可能會跳過其余部分。 其次,控制流是不間斷且連續的–您仍然可以從上至下閱讀,反之亦然。 最后但并非最不重要的一點是–同時保留了異常被包裹的事實,但不會使堆棧跟蹤混亂。

現在您應該看到利用%rEx打印的原始Spring異常:

觀察結果完全相同:問題的根本原因從一開始就出現,從而縮短了需要研究問題的時間。 同樣,在分析控制流時,不會跳躍-Thread.main()位于底部,您可以連續讀取底部到頂部的軌跡。

如果您使用堆棧跟蹤(在開發中或在生產/支持中)進行大量工作–請考慮切換到根本原因優先日志記錄。 每次您分析特定異常時,它將節省您幾秒鐘的時間。 但是我還注意到,經驗不足的開發人員有時甚至不知道“ 由...引起的 ”規則: 找到第一個異常并查看最后一個“由...引起的” –仍然不清楚問題到底是什么,僅查看最外部,最不具體,最通用的錯誤。 這也將對他們有幫助。

順便說一下,如果您完全避免包裝和重新拋出異常,則可以避免所有這些麻煩。 我知道,我們經常會因檢查異常而被迫這么做……

參考: 日志異常的根源首先來自我們的JCG合作伙伴Tomek Nurkiewicz,位于NoBlogDefFound

編碼愉快! 不要忘記分享!

相關文章:

  • Java日志混亂
  • 正確記錄應用程序的10個技巧
  • 使用AspectJ,Javassist和Java Proxy進行代碼注入的實用介紹
  • Java最佳實踐系列
  • 每個程序員都應該知道的事情
  • 生存在狂野西部開發過程中的9條提示
  • 軟件設計法則

翻譯自: https://www.javacodegeeks.com/2011/09/logging-exceptions-root-cause-first.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/374132.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/374132.shtml
英文地址,請注明出處:http://en.pswp.cn/news/374132.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

成功醒言

成功醒言 C01 只有敢犯錯誤的人才能成事&#xff1b; 只有不犯同樣錯誤的人才能成大事。 C02 固執≠執著&#xff1b; 幻想≠希望。 固執是無目標的執著&#xff1b; 執著是有目標的固執。 幻想是無法兌現的希望&#xff1b; 希望是有望實現的幻想。 固執地執著幻想&#xf…

Android 中的 Service 全面總結

1、Service的種類 按運行地點分類&#xff1a; 類別區別 優點缺點 應用本地服務&#xff08;Local&#xff09;該服務依附在主進程上&#xff0c; 服務依附在主進程上而不是獨立的進程&#xff0c;這樣在一定程度上節約了資源&#xff0c;另外Local服務因為是在同一進程因此不…

python基礎學習1-三元表達式和lambda表達式

#!/usr/bin/env python # -*- coding:utf-8 -*- 三元運算 if else 的簡寫name "alex" if 11 else "SB" #如果條件成立 賦alex 否則 賦SB print(name)#--------------lambda表達式 f2 lambda a1,a2:a1a2100 #等價 下邊函數定義 def f1(a1,a2): return …

怎么讓存儲過程通用化_怎么做分布式存儲的面試?

cholerae 大神已經做了詳細回答&#xff0c;http://zenlife.tk/interview-for-distributed-storage.md寫于幾年前&#xff0c;內容有點稚嫩&#xff0c;WAL辨識度很高, 其他問題一般.CAP不會再問了&#xff0c;專業的存儲文獻中很少(幾乎不)提及CAP或PACELC, 這個詞用于市場和銷…

Java EE中的配置管理

我嘗試配置管理在云計算中具有很多相關性 爭論 較早。 實際上&#xff0c;我大膽地宣稱配置管理是任何認真嘗試從軟件中節省幾美元的基石。 那么什么是配置管理及其主要目標&#xff1f; 在不使事情變得過于復雜的情況下&#xff0c;我認為接下來的兩個目標與事實相差不遠。 以…

十年總結,一個JAVA人的十年人生路

十年總結-開篇&#xff1a;歇一歇&#xff0c;才能走的更遠經常見壇子里有人問&#xff0c;學習java該如何入手&#xff0c;或者是該學java還是學XX語言。我一直覺得&#xff0c;編程跟語言關系不大&#xff0c;重點是要有解決問題的思路。學習一門語言&#xff0c;其實只是尋求…

(四)Qt實現自定義模型基于QAbstractTableModel (一般)

Qt實現自定義模型基于QAbstractTableModel 兩個例子 例子1代碼 Main.cpp #include <QtGui>#include "currencymodel.h"int main(int argc, char *argv[]) {QApplication app(argc, argv);//數據源QMap<QString, double> currencyMap;currencyMap.insert(…

pt-query-digest使用介紹【轉】

本文來自&#xff1a;http://isadba.com/?p651 一、pt-query-digest參數介紹. pt-query-digest --useranemometer --passwordanemometerpass --review h192.168.11.28,Dslow_query_log,tglobal_query_review \--history h192.168.11.28,Dslow_query_log,tglobal_query_re…

python代碼模板_python 代碼模板

python中的Module是比較重要的概念。常見的情況是&#xff0c;事先寫好一個.py文 件&#xff0c;在另一個文件中需要import時&#xff0c;將事先寫好的.py文件拷貝 到當前目錄&#xff0c;或者是在sys.path中增加事先寫好的.py文件所在的目錄&#xff0c;然后import。這樣的做法…

Java并發教程–重入鎖

Java的synced關鍵字是一個很棒的工具–它使我們能夠以一種簡單可靠的方式來同步對關鍵部分的訪問&#xff0c;而且也不難理解。 但是有時我們需要對同步進行更多控制。 我們要么需要分別控制訪問類型&#xff08;讀取和寫入&#xff09;&#xff0c;要么使用起來很麻煩&#xf…

找出互聯網類似以下圖的實例

轉載于:https://www.cnblogs.com/sghcjy/p/4978851.html

python比較運算符重載_python運算符重載

1、打印操作會首先嘗試__str__和str內置函數&#xff0c;他通常返回一個用戶友好顯示。__repr__用于所有其他環境&#xff0c;用于交互式模式下提示回應以及repr函數&#xff0c;如果沒有使用__str__&#xff0c;則會使用print和str。它通常返回一個編碼字符串&#xff0c;可以…

使用Spring MVC開發Restful Web服務

REST簡介 摘自Wikipedia&#xff1a; REST風格的體系結構由客戶端和服務器組成。 客戶端向服務器發起請求&#xff1b; 服務器處理請求并返回適當的響應。 請求和響應圍繞資源表示的傳遞而構建。 資源本質上可以是可以解決的任何連貫且有意義的概念。 正如您所閱讀的&#xff0…

深入Java核心 Java內存分配原理精講

深入Java核心 Java內存分配原理精講 Java內存分配與管理是Java的核心技術之一&#xff0c;之前我們曾介紹過Java的內存管理與內存泄露以及Java垃圾回收方面的知識&#xff0c;今天我們再次深入Java核心&#xff0c;詳細介紹一下Java在內存分配方面的知識。一般Java在內存分配時…

iOS正則表達式(親測,持續更新)

先來說說判斷方法,書寫不簡介但是好理解: -(BOOL)isRealNmaeString:(NSString *)str{NSString *pattern "填寫正則表達式";NSPredicate *pred [NSPredicate predicateWithFormat:"SELF MATCHES %", pattern];BOOL isMatch [pred evaluateWithObject:str…

python新建一個文件夾需要重新安裝模塊嗎_解決pycharm每次新建項目都要重新安裝一些第三方庫的問題...

目前有三個解決辦法&#xff0c;也是親測有用的&#xff1a;第一個方法&#xff1a;因為之前有通過pycharm的project interpreter里的號添加過一些庫&#xff0c;但添加的庫只是指定的項目用的&#xff0c;如果想要用&#xff0c;就必須用之前的項目的python解釋器&#xff0c;…

端到端測試的濫用–測試技術2

我的上一個博客是有關測試代碼方法的一系列博客中的第一篇&#xff0c;概述了使用一種非常常見的模式從數據庫檢索地址的簡單方案&#xff1a; …并描述了一種非常通用的測試技術&#xff1a; 不編寫測試 &#xff0c; 而是手動進行所有操作。 今天的博客涵蓋了另一種實踐&…

[AlwaysOn Availability Groups]排查:AG超過RPO

[AlwaysOn Availability Groups]排查&#xff1a;AG超過RPO 排查&#xff1a;AG超過RPO 在異步提交的secondary上執行了切換&#xff0c;你可能會發現數據的丟失大于RPO&#xff0c;或者在計算可以忍受的數據都是超過了RPO。 1.通常原因 1.網絡延遲太高&#xff0c;網絡吞吐量太…

那些年困擾我們的Linux 的蠕蟲、病毒和木馬

雖然針對Linux的惡意軟件并不像針對Windows乃至OS X那樣普遍&#xff0c;但是近些年來&#xff0c;Linux面臨的安全威脅卻變得越來越多、越來越嚴重。個中原因包括&#xff0c;手機爆炸性的普及意味著基于Linux的安卓成為惡意黑 客最具吸引力的目標之一&#xff0c;以及使用Lin…

python單元測試框架unittest介紹和使用_Python+Selenium框架設計篇之-簡單介紹unittest單元測試框架...

前面文章已經簡單介紹了一些關于自動化測試框架的介紹&#xff0c;知道了什么是自動化測試框架&#xff0c;主要有哪些特點&#xff0c;基本組成部分等。在繼續介紹框架設計之前&#xff0c;我們先來學習一個工具&#xff0c;叫unittest。unittest是一個單元測試框架&#xff0…