-
java异常 打印_Java异常打印输出中常见方法的分析
2021-02-12 14:46:03但是一般在我们的项目中,由于经验阅历等多方面的原因,依然有若干的童鞋在代码中没有正确的使用异常打印方法,导致在项目的后台日志中,没有收到日志或者日志信息不完整等情况的发生,这些都给项目埋下了若干隐患。...Java异常是在Java应用中的警报器,在出现异常的情况下,可以帮助我们程序猿们快速定位问题的类型以及位置。但是一般在我们的项目中,由于经验阅历等多方面的原因,依然有若干的童鞋在代码中没有正确的使用异常打印方法,导致在项目的后台日志中,没有收到日志或者日志信息不完整等情况的发生,这些都给项目埋下了若干隐患。本文将深入分析在异常日志打印过程中的若干情况,并给出若干的使用建议。
1. Java异常Exception的结构分析
我们通常所说的Exception主要是继承于Throwable而来,可以参见如下的结构图示:
主要的Throwable分为异常和错误两种,然后异常Exception和错误Error做为基类,分别被具体个性化以及衍生出NullPointerException、EOFException等等异常信息类。
基于Java中的源代码来分析,Error和Exception仅仅是继承了Throwable,做了构造函数的拓展,没有进行额外方法的延展;Exception输出的主要核心方法都是定义在Throwable中的,感兴趣的童鞋可以尝试阅读JDK的源代码。
下面将介绍一下关键的几个异常类方法:getMessage(): String
输出异常的描述信息
getLocalizedMessage()
输出本地化的描述信息,一般此方法可被子类所覆盖,缺省实现与getMessage()输出信息一致
printStackTrace()
将异常栈打印到输出流中,此为一类方法,默认打印到console控制台,也可以显式指定输出流。
fillInStackTrace()
将当前的异常栈保存到一个Throwable中,返回这个Throwable。大部分情况下,用在保留异常栈嵌套调用的情况,尝试保留完整的异常栈,无需使用该方法。
2. Error vs Exception
Error在Java体系中定义为不可控制的问题,往往用来描述系统错误或者底层的问题,比如虚拟机错误,例如内存空间不足,方法调用栈溢等。我们以上图中列举出的内存溢出错误(StackOverflowError)为例,它是在JVM层面发生的错误,已经游离于java应用层之外;在应用程序层面是无法进行捕获,且无法从错误中恢复的。一般一旦发了类似问题,一般都是直接宕机,应用停止正常的工作,需要重新启动或者修复问题之后,方可重新正常工作。
Exception一般发生在应用层,即在由项目中的Java代码层面引发的问题,且可以尝试进行捕获,此类问题不会影响到应用程序的正常工作的,即不会导致宕机现象的发生。我们在工作或者代码中常见的都是Exception衍生出来的各类异常。
这里需要强调说明一下,JVM是Java语言的运行环境和平台,但是并不是Java语言体系的一个部分;在JVM平台上,还可以运行Groovy, JPython, JRuby, Closure,scala等等遵守Java语言规范(JavaLanguage Specification)的编程语言,故我们可以将Error理解为脱离Java应用之外的问题。
3. Exception中的运行时异常(RuntimeException)和受控异常(checked exception)
运行时异常(RuntimeException)是指在运行之时发生的异常,无需显式地进行捕获;如果程序中发生类似的异常,JVM会直接抛出此类异常,并打出响应的异常栈信息。此类异常也通常被称为unchecked exception, 未受控异常。
受控异常(checked Exception)是我们最常见的异常种类,在代码中使用的异常基本上都是此类异常,此类异常会在代码编译阶段由Java编译器进行语法检查,如果未显式进行异常捕获,则会报出相应的编译异常信息。
4. 如何在代码中正确打印异常信息
下面我们将通过一系列的例子来说明上述几个Exception中方法的使用技巧。
Case 1: getMessage()/getLocalizedMessage()public void testCase1() {
System.out.println('We are going to do something interesting....');
try {
throw new NullPointerException('I am an exception in the code.');
} catch (Exception e) {
System.out.println('We got unexpected:' + e.getMessage());
System.out.println('We got unexpected:' + e.getLocalizedMessage());
}
}
输出结果:We are going to do testing interesting....
We got unexpected in getMessage==> I am an exception in the code.
We got unexpected in getLocalizedMessage==> I am an exception in the code.
基于结果来分析, 上述两个方法只是将异常对象中的Message打印出来,这些信息对于我们追踪问题和调试帮助有限。
Case 2:e.printStackTrace()public void testCase2() {
System.out.println('We are going to do something interesting....');
try {
throw new Exception('I am an exception in the code.');
} catch (Exception e) {
e.printStackTrace();
}
}
运行结果:
运行结果图
printStackTrace()可以打印出整个异常栈,但是异常栈信息将输出到默认的输出流中,绝大多数情况下是系统的控制台,而在实际项目中,都是需要将异常栈输出到日志文件的,如果不显式指定,则会丢失异常信息,在日志文件中无从追查。
Case 3: 基于log4j/slf4j等输出到日志文件
在实际项目中,一般会使用log4j/log4j2/JDK logging/slf4j/logback等日志系统来存放日志,那如何来讲日志的异常栈存入日志文件呢,我们来看示例。public void testCase3() {
System.out.println('We are going to do something interesting....');
try {
throw new NullPointerException('abcedfeg');
} catch (Exception e) {
logger.info('Unexpected error in ', e);
}
}
我们需要到日志文件中,找到相应的异常信息,异常信息如下:12:24:45.387 [main] INFO org.demo.TestException - Unexpected error in
java.lang.NullPointerException: abcedfeg
at org.demo.TestException.testCase3(TestException.java:39)
at org.demo.TestException.main(TestException.java:12)
我们可以发现,整个异常栈信息由两个部分组成:
>> 异常中的message, 类似getMessage()输出的信息,
>> 使用logger.info之类的方法,将异常信息写入到日志流中.
以下为log4j的声明,这里以slf4j为例来示例:private static final Logger logger = LoggerFactory.getLogger(TestException.class);
Case 4: fillInStackTrace()public class FillInExceptionTest {
public static void main(String[] args) {
FillInExceptionTest fit = new FillInExceptionTest();
try {
fit.outerMehtod();
} catch (Exception e) {
System.out.println('\n==========I am the one evil separation line==============');
e.printStackTrace();
}
}
public void innerMethod() throws Exception {
throw new Exception('I got exception in an inner method.');
}
public void outerMehtod() throws Exception {
try {
innerMethod(); //invoke inner method.
} catch (Exception e) {
e.printStackTrace();
throw (Exception)e.fillInStackTrace();
}
}
}
运行结果:
基于上述的运行结果可知,fillInStackTrace()只提取了当下的异常栈信息,而非完整的异常栈信息,这个就是此方法带给我们的特殊之处。
如果我们需要在最外层将完整的异常栈打印出来,该如何做呢? 将下述的语句:throw (Exception)e.fillInStackTrace();
替换为:throw e;
重新运行程序,我们就可以在最外层得到完整的异常栈信息了。
5. 总结
在本文中,我们介绍了异常类的继承体系,不同类型的异常区别与使用场景;并将基于代码示例展示了如何使用Exception的若干方法,利用这些方法来保留尽可能多的日志信息,方便我们后续针对日志中的异常信息,追查和解决问题。
-
Java 异常日志打印总结
2021-01-24 00:02:42先来做实验 try { int i = 1 / 0; } catch (Exception e) { e.printStackTrace(); log.error("异常信息: {}", e.toString());... log.error("异常信息: {}", e.getMessage()... log.error("异常信息: ", e.toString先来做实验
try { int i = 1 / 0; } catch (Exception e) { e.printStackTrace(); log.error("异常信息: {}", e.toString()); log.error("异常信息: {}", e.getMessage()); log.error("异常信息: ", e.toString()); log.error("异常信息: ", e.getMessage()); log.error("异常信息: ", e); log.error("异常信息: " + e); }
e.printStackTrace(); // 能打印完整异常堆栈信息
java.lang.ArithmeticException: / by zero at com.nokia.wfm.biz.business.wirelessresource.constants.CommonlyConstants.main(CommonlyConstants.java:20)
log.error("异常信息: {}", e.toString()); // 只打印简单的异常信息,没打印堆栈信息
23:52:45.352 [main] ERROR com.nokia.wfm.biz.business.wirelessresource.constants.CommonlyConstants - 异常信息: java.lang.ArithmeticException: / by zero
log.error("异常信息: {}", e.getMessage()); // 只打印简单的异常信息,没打印堆栈信息
23:53:16.133 [main] ERROR com.nokia.wfm.biz.business.wirelessresource.constants.CommonlyConstants - 异常信息: / by zero
log.error("异常信息: ", e.toString()); // 没打印异常信息
23:53:44.404 [main] ERROR com.nokia.wfm.biz.business.wirelessresource.constants.CommonlyConstants - 异常信息:
log.error("异常信息: ", e.getMessage()); // 没打印异常信息
23:55:57.173 [main] ERROR com.nokia.wfm.biz.business.wirelessresource.constants.CommonlyConstants - 异常信息:
log.error("异常信息: ", e); // 能打印完整异常堆栈信息
23:56:37.385 [main] ERROR com.nokia.wfm.biz.business.wirelessresource.constants.CommonlyConstants - 异常信息: java.lang.ArithmeticException: / by zero at com.nokia.wfm.biz.business.wirelessresource.constants.CommonlyConstants.main(CommonlyConstants.java:20)
log.error("异常信息: " + e); // 只打印简单的异常信息,没打印堆栈信息
23:57:32.463 [main] ERROR com.nokia.wfm.biz.business.wirelessresource.constants.CommonlyConstants - 异常信息: java.lang.ArithmeticException: / by zero
总结
发生异常,需要打印日志时。
如果只需要打印异常信息,不需要打印堆栈信息,则使用:
log.error("异常信息: {}", e.getMessage()); // 最简单的异常信息
log.error("异常信息: {}", e.toString()); // e.getMessage() 的基础上,在前面加上打印了异常类
如果需要打印异常和堆栈信息,方便排查问题,则使用
e.printStackTrace(); // 能打印完整异常堆栈信息,但听说会引起死锁,所以最好少用
log.error("异常信息: ", e); // 能打印完整异常堆栈信息,建议使用
-
java 异常堆栈日志分析_Java异常日志堆栈丢失的原因与排查
2021-02-28 14:49:49前言查日志是我们排查问题的重要手段之一,直接又方便。其中异常日志堆栈信息可以...如果面试中,就可以提一些问题:什么情况下Java的异常日志堆栈信息会丢失?其原因是什么? 异常堆栈丢失情况下要如何排查问题?原...前言
查日志是我们排查问题的重要手段之一,直接又方便。其中异常日志堆栈信息可以让我们快速的发现问题所在,但稍微有点经验的开发应该会遇到过日志堆栈信息丢失的情况。
堆栈只打印了一行:java.lang.NullPointerException,然后什么信息都没有了,这是怎么回事?
如果面试中,就可以提一些问题:
什么情况下Java的异常日志堆栈信息会丢失?其原因是什么? 异常堆栈丢失情况下要如何排查问题?
原因
JVM内部同一个方法被调用多次的时候,会被JIT编译器进行优化,在Oracle官方文档中,有一段英文描述:
The compiler in the server VM now provides correct stack backtraces for all "cold" built-in exceptions. For performance purposes, when such an exception is thrown a few times, the method may be recompiled. After recompilation, the compiler may choose a faster tactic using preallocated exceptions that do not provide a stack trace. To disable completely the use of preallocated exceptions, use this new flag: -XX:-OmitStackTraceInFastThrow.
在Server模式下的JVM编译器提供了一种方式可以让我们回溯异常的堆栈信息,但是出于性能的因素,当类似的异常抛出多次的时候,异常方法可以被重新编译,重新编译后,编译器会采用更快的策略使用预分配缓存区的异常,并且不再提供堆栈信息。
如果不想使用预分配缓存的异常使用-XX:-OmitStackTraceInFastThrow标记。
另外一方面异常栈的获取是非常消耗性能的,这点通过JVM内部默认会对一些异常不进行堆栈回溯也可以看出。
异常丢失如何排查
试着隔离一两台机器,重启两台机器观察情况
-XX:-OmitStackTraceInFastThrow可以控制不进行异常堆栈优化,如果关闭,就需要预防产生“日志风暴”,否则,一旦高频应用出现异常可能很快用满服务器磁盘。
验证堆栈丢失Demo
public class ExceptionLossDemo {
public static void main(String[] args) {
boolean flag = false;
for (int i = 0;;i++){
boolean isExceptionStackLoss = exceptionTest();
if (isExceptionStackLoss) {
flag = true;
System.out.println("times:" + i + ", res:" + isExceptionStackLoss);
} else if (flag) {
System.out.println("times:" + i + ", res:" + isExceptionStackLoss);
}
}
}
public static boolean exceptionTest() {
try {
// 构造一个NPE异常
int res = ((Integer)null) + 1;
} catch (Exception e) {
if (e.getStackTrace().length == 0) {
// 打印堆栈信息
e.printStackTrace();
try {
// 当出现 NPE 异常堆栈为空的时候,停留5秒,便于观察
Thread.sleep(5000);
} catch (Exception e1) {
}
// 如果出现 NPE 异常堆栈为空,返回true
return true;
}
// 打印堆栈信息
e.printStackTrace();
}
return false;
}
}
最后
希望对大家有所帮助,技术不断精进..
到此这篇关于Java异常日志堆栈丢失的原因与排查的文章就介绍到这了,更多相关Java异常日志堆栈丢失内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
-
java 异常堆栈日志分析_日志如何打印异常堆栈信息。
2021-02-28 14:49:14import org.junit.Test;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/*** 如何打印异常堆栈信息。* @author doctor** @time 2014年12月11日 上午9:49:00*/public class LogThrowableRule {p...package com.doctor.slf4j;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 如何打印异常堆栈信息。
* @author doctor
*
* @time 2014年12月11日 上午9:49:00
*/
public class LogThrowableRule {
private final Logger log = LoggerFactory.getLogger(getClass());
/**
* 这种e.toString()方法只是得到异常信息,异常堆栈没有得到
*/
@Test
public void test_wrongLogThrowable(){
try {
int test = 10/0;
} catch (Exception e) {
log.error("error" + e);
//main ERROR c.d.s.LogThrowableRule -
// errorjava.lang.ArithmeticException: / by zero
}
}
/**
* 得到异常堆栈信息正确的log方法
*/
@Test
public void test_rightWayGetInfoForThrowable(){
int a = 10;
int b = 0;
try {
int test = a/b;
} catch (Exception e) {
log.error("error" ,e);
//main ERROR c.d.s.LogThrowableRule -
//error
//java.lang.ArithmeticException: / by zero
// at com.doctor.slf4j.LogThrowableRule.test_rightWayGetInfoForThrowable(LogThrowableRule.java:35) ~[classes/:na]
// at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_11]
// .............
String msg = String.format("{error:'%s/%s'}", a,b);//string带参数,利用String.format
log.error(msg, e);
}
}
}
-
java异常日志目录_java异常处理 日志记录异常具体位置的方法
2021-02-26 20:16:22首先要在方法处抛出 Exception异常然后在方法调用处trycatch接收此异常对象这样就能够记录异常具体位置了控制台输出:日志:要点:System.getProperty("line.separator")是用来换行的 通用换行 不限操作系统如果要用... -
java 异常堆栈 打印日志方法
2012-11-23 11:54:02StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); return sw.toString() -
Java异常日志堆栈信息如何打印到日志文件
2018-12-14 16:06:27当我们使用try..catch方法(如下图所示)捕获到异常堆栈信息时,有时候无法打印出具体的错误信息到日志文件,即无法通过抛出的异常迅速定位到问题所在。因此我们需要将异常堆栈信息通过某种方法解析出来,输出完整... -
JAVA 打印异常日志详细信息
2013-11-11 11:21:24static String getStackTrace(Throwable t) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw, true); t.printStackTrace(pw); pw.flush(); sw.flush(); return sw.toString(); -
java日志打印_java日志打印建议
2021-02-12 09:29:54在action中catch到Exception的时候用以下语句将异常记录到日志文件中,以下写法可以保证异常堆栈的信息被记录到日志文件中,方便排查问题错误写法:log.error("查询异常:" + e);2012-10-12 09:52:52.921 ERROR ... -
Java打印日志注意事项和异常类型
2021-02-06 15:21:03一、异常 二、日志 1、什么是日志 简单的说,日志就是记录程序的运行轨迹,方便查找关键信息,也方便快速定位解决问题。 我们 Java 程序员在开发项目时都是依赖 Eclipse/ Idea 等开发工具的 Debug 调试功能来... -
java异常信息日志输出
2015-04-29 10:31:51当程序运行异常时,e.printStackTrace()会打印出异常。但是很多时候我们希望将这些异常输出到日志中,以便日后可以随时查看到,可以通过这些异常快速的找到程序发生异常的代码。 那么有办法可以将异常的详细信息... -
【Java】异常日志只打印一行
2021-02-23 11:10:19一直以为是日志系统的功能,今天发现是jvm实现的,参数是:OmitStackTraceInFastThrow,并且只针对特定5种异常开启。 详见:https://www.javajike.com/article/1768.html -
Java异常打印输出中常见方法的分析
2017-04-30 22:10:35但是一般在我们的项目中,由于经验阅历等多方面的原因,依然有若干的童鞋在代码中没有正确的使用异常打印方法,导致在项目的后台日志中,没有收到日志或者日志信息不完整等情况的发生,这些都给项目埋下了若干隐患。... -
java 日志中打印异常信息
2019-07-29 14:57:29java程序中执行遇到的异常,通过e.printStackTrace(); 会打印在控制台。那怎么将异常信息e.printStackTrace();打印到日志中呢。 百度到了一位大神博主解决了这一问题:... -
JAVA使用日志Log打印异常信息
2020-01-15 16:43:44JAVA使用日志Log打印异常信息 一、前言 最近公司用上了SonarQube代码检测,提示应该用LOGGER.log(…)代替e.printStackTrace()。 经了解到: 通过e.printStackTrace()会调用System.err将错误信息通过流进行打印可能... -
JAVA 日志异常没有打印堆栈信息问题
2020-04-26 15:50:35java.lang.NullPointerException: null ...原因:发现服务器中日志文件只有异常,但是没有打印堆栈信息,找之前的日志文件发现有完整的堆栈异常信息 这个问题其实是跟JDK5引入的一个新特性有关,... -
打印java异常堆栈信息到日志文件
2015-05-26 10:08:09存在问题:e.printStackTrace();无法直接将堆栈信息,打印到日志文件。 解决办法: ... * @功能说明:在日志文件中,打印异常堆栈 * @param Throwable * @return:String */ public static String Log -
Java 异常 自定义打印内容
2019-10-27 15:53:45背景:在开发中,我们可能会使用到自定义异常,但是,这个自定义异常在打印日志时,往往打印的内容比较多。 1.自定义异常打印内容 可以看到,虽然我们使用的是自定义异常,但是当抛出时,还是会打印出堆栈的全部... -
java怎么捕获mysql异常_java项目中如何捕获异常与抛出异常及打印日志?
2021-02-06 21:49:10题主想知道的是怎么讲java的异常应用到实际项目中吧举个例子:场景:假设现在我们有个货物表,记录了商品名称和剩余数量其中笔(pen) 有10支.现在需要写一个业务,减少笔的数量如果笔数量不足,则通知进货大致流程注意以下... -
java异常日志记录
2015-11-09 16:14:57java的日志打印使用默认的e.printStackTrace()时,有时只能打印的空信息,项目上线后,针对日志做分析时如果有这样的情况挺尴尬,对于此情况可以通过如下方式来处理 e.printStackTrace(); ByteArrayOutputStream ... -
java log丢失_Java异常日志堆栈丢失原因
2021-02-28 17:43:55查日志是我们排查问题的重要手段之一,直接又方便。其中异常日志堆栈信息可以...如果面试中,就可以提一些问题:什么情况下Java的异常日志堆栈信息会丢失?其原因是什么? 异常堆栈丢失情况下要如何排查问题?原因J... -
Java异常集中处理和日志集中打印
2019-06-23 23:50:00。。。。。 转载于:https://www.cnblogs.com/lishaojun/p/11074955.html -
将Java异常的完整堆栈内容打印到log4j日志
2017-01-23 12:40:571.当我们在Java遇到异常,却很难根据default打印的异常内容来判断问题所在的时候,我们可以用以下的API打印发生异常时堆栈的完整内容。...2.将Java异常的完整堆栈内容打印到log4j日志 异常打印建议:logger.error( -
java 异常堆栈输出_打印Java异常堆栈信息
2021-02-28 14:50:16背景在开发Java应用程序的时候,遇到程序抛异常,我们通常会把抛异常时的运行时环境保存下来(写到日志文件或者在控制台中打印出来)。这样方便后续定位问题。需要记录的运行时环境包含两部分内容:抛异常时的参数信息... -
log4j中调试与错误日志分开_Java中异常打印输出的常见方法总结
2021-01-27 06:44:55但是一般在我们的项目中,由于经验阅历等多方面的原因,依然有若干的童鞋在代码中没有正确的使用异常打印方法,导致在项目的后台日志中,没有收到日志或者日志信息不完整等情况的发生,这些都给项目埋下了若干隐患。... -
java异常在控制台和日志里面的打印记录
2018-08-04 14:56:081、e.printStackTrace()打印在哪里 在catch中的e.printStackTrace()将打印到控制台 2、e.printStackTrace()打印的内容是什么 import org.apache.logging.log4j.Logger; public class ExceptionTest { private ... -
java 中 log 日志打印
2021-01-27 20:39:51// java 自带的日志打印, 仅限于个人调试使用, 不适用于企业级项目开发 System.out.println("正常日志"); System.err.println("异常日志"); 这里, 我们采用 slf4j 搭配 logback 介绍下日志打印 引入 pom.xml 依赖 &...