c语言sscanf函数的用法是什么
279
2022-12-06
在日志中记录Java异常信息的正确姿势分享
目录日志中记录java异常信息遇到的问题原因分析正确的做法java异常在控制台和日志里面的打印记录1、e.printStackTrace()打印在哪里2、e.printStackTrace()打印的内容是什么3、如果将e.printStackTrace()的信息打印在日志里应该怎么做呢?
日志中记录Java异常信息
遇到的问题
今天遇到一个线上的BUG,在执行表单提交时失败,但是从程序日志中看不到任何异常信息。
在Review源代码时发现,当catch到异常时只是输出了e.getMessage(),如下所示:
logger.error("error: {}, {}", params, e.getMessage());
在日志中看不到任何信息,说明e.getMessage()返回值为空字符串。
原因分析
先来看一下Java中的异常类图:
Throwable是Java中所有异常信息的顶级父类,其中的成员变量detailMessage就是在调用e.getMessage()返回的值。
那么这个属性会在什么时候赋值呢,追溯源码发现,该属性只会在Throwable构造函数中赋值。
public Throwable() {
// 在默认构造函数中不会给detailMessage属性赋值
fillInStackTrace();
}
public Throwable(String message) {
fillInStackTrace();
// 直接将参数赋值给detailMessage
detailMessage = message;
}
public Throwable(String message, Throwable cause) {
fillInStackTrace();
// 直接将参数赋值给detailMessage
detailMessage = message;
this.cause = cause;
}
public Throwable(Throwable cause) {
fillInStackTrace();
// 当传入的Throwable对象不为空时,为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;
}
// 直接将参数赋值给detailMessage
detailMessage = message;
this.cause = cause;
if (!enableSuppression)
suppressedExceptions = null;
}
显然,从源码中可以看到在Throwable的默认构造函数中是不会给detailMessage属性赋值的。
也就是说,当异常对象是通过默认构造函数实例化的,或者实例化时传入的message为空字符串,那么调用getMessage()方法时返回值就为空,也就是我遇到的情形。
所以,在程序日志中不要单纯使用getMessage()方法获取异常信息(返回值为空时,不利于问题排查)。
正确的做法
在Java开发中,常用的日志框架及组件通常是:slf4j,log4j和logback,他们的关系可以描述为:slf4j提供了统一的日志API,将具体的日志实现交给log4j与logback。
也就是说,通常我们只需要在项目中使用slf4j作为日志API,再集成log4j或者logback即可。
上述配置以集成slf4j和logback为例,添加对应的logback配置文件(logback.xml):
在Java中通过slf4j提供的日志API记录日志:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Test {
private static final Logger logger = LoggerFactory.getLogger(Test.class);
}
当我们需要在程序日志中输出异常信息时,应该直接传入异常对象即可,而不要单纯通过异常对象的getMessage()方法获取输出异常信息。
public void test() {
try {
// 使用默认构造函数实实例化异常对象
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 # 使用默认构造参数实例化异常对象时,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.InvocableHandlerMethodYCuQyeL.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()打印的内容是什么
import org.apache.logging.log4j.Logger;
public class ExceptionTest {
private static final Logger logger=LogManager.getLogger();
public vhttp://oid test() {
try {
int i=1/0;
}catch(Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) {
ExceptionTest test= new ExceptionTest();
test.test();
}
}
输出结果如下:
java.lang.ArithmeticException: / by zero
at myProject.ExceptionTest.test(ExceptionTest.java:10)
at myProject.ExceptionTest.main(ExceptionTest.java:18)
可见,e.printStackTrace()打印了错误的具体信息,即这个错误出现的位置,便于查找错误源
3、如果将e.printStackTrace()的信息打印在日志里应该怎么做呢?
见如下代码:
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);打印日志,输出结果如下:
19:17:39.753 [main] ERROR myProject.ExceptionTest - java.lang.ArithmeticException: / by zero
可见,用这种方法打印的日志,只有大概的错误信息,并没有指出报错的代码位置,不便于查找错误。用logger.error(e.getMessage());也是输出这种大概的错误信息。
再见如下代码:
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);,则输出结果如下:
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()打印的内容大致是相同的。不过最好,还是使用logger.error(e.getMessage(),e)方法来在日志上查看异常的详细结果
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~