欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

在日志中記錄Java異常信息的正確姿勢分享

 更新時(shí)間:2021年09月24日 10:07:06   作者:空山新雨天氣晚秋  
這篇文章主要介紹了在日志中記錄Java異常信息的正確姿勢,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

日志中記錄Java異常信息

遇到的問題

今天遇到一個(gè)線上的BUG,在執(zhí)行表單提交時(shí)失敗,但是從程序日志中看不到任何異常信息。
在Review源代碼時(shí)發(fā)現(xiàn),當(dāng)catch到異常時(shí)只是輸出了e.getMessage(),如下所示:

logger.error("error: {}, {}", params, e.getMessage());

在日志中看不到任何信息,說明e.getMessage()返回值為空字符串。

原因分析

先來看一下Java中的異常類圖:

Throwable是Java中所有異常信息的頂級父類,其中的成員變量detailMessage就是在調(diào)用e.getMessage()返回的值。
那么這個(gè)屬性會在什么時(shí)候賦值呢,追溯源碼發(fā)現(xiàn),該屬性只會在Throwable構(gòu)造函數(shù)中賦值。

public Throwable() {
    // 在默認(rèn)構(gòu)造函數(shù)中不會給detailMessage屬性賦值
    fillInStackTrace();
}
public Throwable(String message) {
    fillInStackTrace();
    // 直接將參數(shù)賦值給detailMessage
    detailMessage = message;
}
public Throwable(String message, Throwable cause) {
    fillInStackTrace();
    // 直接將參數(shù)賦值給detailMessage
    detailMessage = message;
    this.cause = cause;
}
public Throwable(Throwable cause) {
    fillInStackTrace();
    // 當(dāng)傳入的Throwable對象不為空時(shí),為detailMessage賦值
    detailMessage = (cause==null ? null : cause.toString());
    this.cause = cause;
}
protected Throwable(String message, Throwable cause,
                        boolean enableSuppression,
                        boolean writableStackTrace) {
    if (writableStackTrace) {
        fillInStackTrace();
    } else {
        stackTrace = null;
    }
    // 直接將參數(shù)賦值給detailMessage
    detailMessage = message;
    this.cause = cause;
    if (!enableSuppression)
        suppressedExceptions = null;
}

顯然,從源碼中可以看到在Throwable的默認(rèn)構(gòu)造函數(shù)中是不會給detailMessage屬性賦值的。

也就是說,當(dāng)異常對象是通過默認(rèn)構(gòu)造函數(shù)實(shí)例化的,或者實(shí)例化時(shí)傳入的message為空字符串,那么調(diào)用getMessage()方法時(shí)返回值就為空,也就是我遇到的情形。

所以,在程序日志中不要單純使用getMessage()方法獲取異常信息(返回值為空時(shí),不利于問題排查)。

正確的做法

在Java開發(fā)中,常用的日志框架及組件通常是:slf4j,log4j和logback,他們的關(guān)系可以描述為:slf4j提供了統(tǒng)一的日志API,將具體的日志實(shí)現(xiàn)交給log4j與logback。

也就是說,通常我們只需要在項(xiàng)目中使用slf4j作為日志API,再集成log4j或者logback即可。


<!-- 使用slf4j作為日志API -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.25</version>
</dependency>
<!-- 集成logback作為具體的日志實(shí)現(xiàn) -->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-core</artifactId>
    <version>1.2.3</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>

上述配置以集成slf4j和logback為例,添加對應(yīng)的logback配置文件(logback.xml):

<configuration scan="false" scanPeriod="30 seconds" debug="false" packagingData="true">
    <statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener"/>
    <!-- 輸出到控制臺 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
        </encoder>
    </appender>
      
    <!-- 輸出到文件 -->
    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>test.log</file>
        <encoder>
            <pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
        </encoder>
    </appender>
    <root level="info">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="FILE" />
    </root>
</configuration>

在Java中通過slf4j提供的日志API記錄日志:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Test {
    private static final Logger logger = LoggerFactory.getLogger(Test.class);
}

當(dāng)我們需要在程序日志中輸出異常信息時(shí),應(yīng)該直接傳入異常對象即可,而不要單純通過異常對象的getMessage()方法獲取輸出異常信息。

public void test() {
    try {
        // 使用默認(rèn)構(gòu)造函數(shù)實(shí)實(shí)例化異常對象
        throw new NullPointerException();
    } catch (Exception e) {
        // 直接將異常對象傳入日志接口,保存異常信息到日志文件中
        logger.error("error: {}", e.getMessage(), e);
        e.printStackTrace();
    }
}

如下是保存到日志文件中的異常信息片段:

2019-06-20 20:04:25,290 ERROR [http-nio-8090-exec-1] o.c.s.f.c.TestExceptionController [TestExceptionController.java:26] error: null # 使用默認(rèn)構(gòu)造參數(shù)實(shí)例化異常對象時(shí),getMessage()方法返回值為空對象
# 如下是具體的異常堆棧信息
java.lang.NullPointerException: null
 at org.chench.springboot.falsework.controller.TestExceptionController.test(TestExceptionController.java:24) ~[classes/:na]
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_181]
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_181]
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_181]
 at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_181]
 at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209) [spring-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
 at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136) [spring-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
 at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) [spring-webmvc-5.0.6.RELEASE.jar:5.0.6.RELEASE]
 at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:877) [spring-webmvc-5.0.6.RELEASE.jar:5.0.6.RELEASE]
 at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:783) [spring-webmvc-5.0.6.RELEASE.jar:5.0.6.RELEASE]
 at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) [spring-webmvc-5.0.6.RELEASE.jar:5.0.6.RELEASE]
 at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991) [spring-webmvc-5.0.6.RELEASE.jar:5.0.6.RELEASE]
 at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925) [spring-webmvc-5.0.6.RELEASE.jar:5.0.6.RELEASE]
 at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974) [spring-webmvc-5.0.6.RELEASE.jar:5.0.6.RELEASE]
 at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:866) [spring-webmvc-5.0.6.RELEASE.jar:5.0.6.RELEASE]
 at javax.servlet.http.HttpServlet.service(HttpServlet.java:635) [tomcat-embed-core-8.5.31.jar:8.5.31]
 at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851) [spring-webmvc-5.0.6.RELEASE.jar:5.0.6.RELEASE]
 at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) [tomcat-embed-core-8.5.31.jar:8.5.31]
......

java異常在控制臺和日志里面的打印記錄

1、e.printStackTrace()打印在哪里

在catch中的e.printStackTrace()將打印到控制臺

2、e.printStackTrace()打印的內(nèi)容是什么

import org.apache.logging.log4j.Logger; 
public class ExceptionTest {
    private static final Logger logger=LogManager.getLogger(); 
    public void  test() {
        try {
            int i=1/0;            
        }catch(Exception e){    
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        ExceptionTest test= new ExceptionTest();
        test.test();        
    }    
}

輸出結(jié)果如下:

java.lang.ArithmeticException: / by zero
at myProject.ExceptionTest.test(ExceptionTest.java:10)
at myProject.ExceptionTest.main(ExceptionTest.java:18)

可見,e.printStackTrace()打印了錯(cuò)誤的具體信息,即這個(gè)錯(cuò)誤出現(xiàn)的位置,便于查找錯(cuò)誤源

3、如果將e.printStackTrace()的信息打印在日志里應(yīng)該怎么做呢?

見如下代碼:

package myProject; 
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; 
public class ExceptionTest {
    private static final Logger logger=LogManager.getLogger(); 
    public void  test() {
        try {
            int i=1/0;            
        }catch(Exception e){    
            logger.error(e);
        }
    }
    public static void main(String[] args) {
        ExceptionTest test= new ExceptionTest();
        test.test();        
    }    
}

用logger.error(e);打印日志,輸出結(jié)果如下:

19:17:39.753 [main] ERROR myProject.ExceptionTest - java.lang.ArithmeticException: / by zero

可見,用這種方法打印的日志,只有大概的錯(cuò)誤信息,并沒有指出報(bào)錯(cuò)的代碼位置,不便于查找錯(cuò)誤。用logger.error(e.getMessage());也是輸出這種大概的錯(cuò)誤信息。

再見如下代碼:

package myProject; 
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; 
public class ExceptionTest {
    private static final Logger logger=LogManager.getLogger(); 
    public void  test() {
        try {
            int i=1/0;            
        }catch(Exception e){    
            logger.error("ExceptionTest Exception:",e);
        }
    }
    public static void main(String[] args) {
        ExceptionTest test= new ExceptionTest();
        test.test();        
    }    
}

用logger.error("ExceptionTest Exception:",e);,則輸出結(jié)果如下:

9:20:32.948 [main] ERROR myProject.ExceptionTest - ExceptionTest Exception:
java.lang.ArithmeticException: / by zero
at myProject.ExceptionTest.test(ExceptionTest.java:10) [classes/:?]
at myProject.ExceptionTest.main(ExceptionTest.java:18) [classes/:?]

這和e.printStackTrace()打印的內(nèi)容大致是相同的。不過最好,還是使用logger.error(e.getMessage(),e)方法來在日志上查看異常的詳細(xì)結(jié)果

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java雜談之代碼重構(gòu)的方法多長才算長

    Java雜談之代碼重構(gòu)的方法多長才算長

    關(guān)于代碼重構(gòu)的理解:在不改變軟件系統(tǒng)/模塊所具備的功能特性的前提下,遵循/利用某種規(guī)則,使其內(nèi)部結(jié)構(gòu)趨于完善。其在軟件生命周期中的價(jià)值體現(xiàn)主要在于可維護(hù)性和可擴(kuò)展性
    2021-10-10
  • 一文帶你徹底理解Java序列化和反序列化

    一文帶你徹底理解Java序列化和反序列化

    這篇文章主要介紹了Java序列化和反序列化的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)Java,感興趣的朋友可以了解下
    2020-09-09
  • 如何在Intellij中安裝LeetCode刷題插件方便Java刷題

    如何在Intellij中安裝LeetCode刷題插件方便Java刷題

    這篇文章主要介紹了如何在Intellij中安裝LeetCode刷題插件方便Java刷題,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-08-08
  • Mybatis查詢Sql結(jié)果未映射到對應(yīng)得實(shí)體類上的問題解決

    Mybatis查詢Sql結(jié)果未映射到對應(yīng)得實(shí)體類上的問題解決

    使用mybatis查詢表數(shù)據(jù)得時(shí)候,發(fā)現(xiàn)對應(yīng)得實(shí)體類字段好多都是null,本文主要介紹了Mybatis查詢Sql結(jié)果未映射到對應(yīng)得實(shí)體類上的問題解決,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-02-02
  • 詳解堆排序算法原理及Java版的代碼實(shí)現(xiàn)

    詳解堆排序算法原理及Java版的代碼實(shí)現(xiàn)

    如果將堆理解為二叉樹,那么樹中任一非葉結(jié)點(diǎn)的關(guān)鍵字均不大于(或不小于)其左右孩子(若存在)結(jié)點(diǎn)的關(guān)鍵字,堆排序的時(shí)間復(fù)雜度為O(N*logN),這里我們就來詳解堆排序算法原理及Java版的代碼實(shí)現(xiàn)
    2016-06-06
  • Java中的CountDownLatch原理深入解析

    Java中的CountDownLatch原理深入解析

    這篇文章主要介紹了Java中的CountDownLatch原理深入解析,CountDownLatch是多線程控制的一種同步工具類,它被稱為門閥、 計(jì)數(shù)器或者閉鎖,這個(gè)工具經(jīng)常用來用來協(xié)調(diào)多個(gè)線程之間的同步,或者說起到線程之間的通信,需要的朋友可以參考下
    2024-01-01
  • SpringCloud?分布式微服務(wù)架構(gòu)操作步驟

    SpringCloud?分布式微服務(wù)架構(gòu)操作步驟

    SpringCloud是一種微服務(wù)的框架,利用它我們可以去做分布式服務(wù)開發(fā),這篇文章主要介紹了SpringCloud?分布式微服務(wù)架構(gòu),需要的朋友可以參考下
    2022-07-07
  • 基于maven的三種packaging方式

    基于maven的三種packaging方式

    這篇文章主要介紹了maven的三種packaging方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • SpringBoot Feign使用教程超全面講解

    SpringBoot Feign使用教程超全面講解

    現(xiàn)在的微服務(wù)項(xiàng)目不少都使用的是springboot+Feign構(gòu)建的項(xiàng)目,微服務(wù)之間的調(diào)用都離不開feign來進(jìn)行遠(yuǎn)程調(diào)用,這篇文章主要介紹了SpringBoot Feign使用教程,需要的朋友可以參考下
    2022-11-11
  • springboot集成redis lettuce

    springboot集成redis lettuce

    目前java操作redis的客戶端有jedis跟Lettuce。本文主要介紹了springboot集成redis lettuce,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09

最新評論