[日志] 打印异常堆栈信息的技巧

  • Java的异常堆栈信息,对提升排查问题的效率,有极大的帮助————便于我们快速定位异常的发生过程和发生异常的代码行。

  • 本文使用的日志框架

  • slf4j : 1.7.25
  • log4j(2) : 2.20.0
  • 日志行的打印策略 : log4j2.properties
# property.log.layout.consolePattern=%d{yyyy/MM/dd HH:mm:ss.SSS} %-5p | %T | %t | (%C{1}.java:%L %M) | %m%n
# property.log.layout.consolePattern=[%d{yyyy/MM/dd HH:mm:ss.SSS}] [%traceId] [%-5p] [%t] [%C{1}.java:%L %M] %m%n
#property.log.layout.consolePattern=[%d{yyyy/MM/dd HH:mm:ss.SSS}] [%X{traceId}] [%-5p] [%t] [%C{1}.java:%L %M] %m%n
property.log.layout.consolePattern=[%traceId] [${application.name}] [system] [%d{yyyy/MM/dd HH:mm:ss.SSS}] [%-5p] [%t] [%C{1}] %M:%L__|%X{traceId}|__%m%n
#property.log.layout.mainPattern=[${application.name}] [${instance.name}] [${env:HOST_IP}] [${env:CONTAINER_IP}] [%d{yyyy/MM/dd HH:mm:ss.SSS}] [%p] [%t] [%l] %m%n

...

# console
# 指定输出源的类型与名称
appender.console.type=Console
appender.console.name=CONSOLE_APPENDER
#appender.console.layout.type=PatternLayout
appender.console.layout.type=CustomPatternLayout
appender.console.layout.pattern=${log.layout.consolePattern}

...

打印异常堆栈信息的技巧

错误示范

  • 错误的关键:不应该使用{}
package xxx.yyy.zzz;

//import lombok.extern.slf4j.Slf4j;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

//@Slf4j
public class Demo {
    private static final Logger log = LoggerFactory.getLogger(Demo.class);

    public static void main(String[] args) {
        try {
            test();
        } catch (Exception exception) {
            log.info("exception.message:{}\nexception:{}", exception.getMessage(), exception);
        }
    }

    public static void test(){
        System.out.println("hello");
        throw new RuntimeException("Xxxx abnormal!");
    }
}

运行效果: 未打印出堆栈信息

hello
[TID: N/A] [my-app-service] [system] [2025/01/22 18:07:37.956] [INFO ] [main] [Demo] main:16__||__exception.message:Xxxx abnormal!
exception:java.lang.RuntimeException: Xxxx abnormal!

正确示范

  • 正确的关键:想打印出堆栈,就不要使用{}
package xxx.yyy.zzz;

//import lombok.extern.slf4j.Slf4j;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

//@Slf4j
public class Demo {
    private static final Logger log = LoggerFactory.getLogger(Demo.class);

    public static void main(String[] args) {
        try {
            test();
        } catch (Exception exception) {
            log.info("exception.message:{}\nexception:", exception.getMessage(), exception);
        }
    }

    public static void test(){
        System.out.println("hello");
        throw new RuntimeException("Xxxx abnormal!");
    }
}

运行效果: 打印出了堆栈信息

hello
[TID: N/A] [my-app-service] [system] [2025/01/22 18:09:41.949] [INFO ] [main] [Demo] main:16__||__exception.message:Xxxx abnormal!
exception:
java.lang.RuntimeException: Xxxx abnormal!
	at xxx.yyy.zzz.Demo.test(Demo.java:22) ~[classes/:?]
	at xxx.yyy.zzz.Demo.main(Demo.java:14) [classes/:?]

场景延伸:String.format(xxx, exception)

  • 同样需求,String.format(xxx, exception)的表现如何呢?
  • 错误示范
    public static void main(String[] args) {
        try {
            throw new RuntimeException("hello\n3535329rew8g8723tr8gsi\nwerewfds");
        } catch (Exception exception) {
            logger.info(String.format("exception:", exception));
        }
    }

out

exception:
  • 正确示范
    public static void main(String[] args) {
        try {
            throw new RuntimeException("hello\n3535329rew8g8723tr8gsi\nwerewfds");
        } catch (Exception exception) {
            logger.info(String.format("exception:%s", exception));//重点:`%s`
        }
    }

out

exception:
3535329rew8g8723tr8gsi
werewfds
posted @ 2025-01-22 18:15  千千寰宇  阅读(140)  评论(0)    收藏  举报