如何在Java中记录尽可能多的异常信息?

如何在Java中记录尽可能多的异常信息?,java,exception,logging,methods,stack-trace,Java,Exception,Logging,Methods,Stack Trace,在Java中记录异常时,我遇到了一个常见的问题。似乎有各种不同的类型需要处理。例如,有些包装其他异常,有些根本没有消息-只有一个类型 我见过的大多数代码都通过使用getMessage()或toString()记录异常。但是,这些方法并不总是能够捕获查明问题所需的所有信息——其他方法,如getCause()和getStackTrace()有时会提供额外的信息 例如,我现在在Eclipse Inspect窗口中看到的异常是InvocationTargetException。异常本身没有原因,没有消息

在Java中记录异常时,我遇到了一个常见的问题。似乎有各种不同的类型需要处理。例如,有些包装其他异常,有些根本没有消息-只有一个类型

我见过的大多数代码都通过使用
getMessage()
toString(
)记录异常。但是,这些方法并不总是能够捕获查明问题所需的所有信息——其他方法,如
getCause()
getStackTrace()
有时会提供额外的信息

例如,我现在在Eclipse Inspect窗口中看到的异常是
InvocationTargetException
。异常本身没有原因,没有消息,没有堆栈跟踪。。。但是getCause()的目标是InvalidUseofMatcherException,并填充了这些详细信息

因此,我的问题是:给定任何类型的异常作为输入,请在发布之前提供一个方法,该方法将输出一个格式良好的字符串,其中包含有关该异常的所有相关信息(例如,可能递归调用
getCause()
,等等),我自己差点就要尝试一下了,但我真的不想重新发明轮子——肯定这样的事情以前已经做过很多次了


请不要指点我在任何特定的日志或实用程序框架来做这件事。我正在寻找一段代码,而不是一个库,因为我没有权利在我正在处理的项目中添加外部依赖项,而且它实际上是记录到网页的一部分而不是文件中。如果是从这样一个框架中复制代码片段(并赋予它属性),那很好:-)

Throwable
提供的
printStacktrace()
方法(以及所有异常)有什么问题?它显示您请求的所有信息,包括根异常的类型、消息和堆栈跟踪以及所有(嵌套)原因。在Java7中,它甚至向您显示了在trywithresources语句中可能出现的“suppressed”异常的信息

当然,您不想写入
System.err
,方法的无参数版本就是这样做的,因此请使用一个可用的重载

特别是,如果您只想获取字符串:

  Exception e = ...
  StringWriter sw = new StringWriter();
  e.printStackTrace(new PrintWriter(sw));
  String exceptionDetails = sw.toString();

如果您碰巧使用了great library,它提供了一个实用方法来实现这一点:。

我不久前编写的日志脚本可能会有所帮助,尽管它并不完全是您想要的。它的工作方式类似于System.out.println,但包含更多有关StackTrace等的信息。它还为Eclipse提供可单击的文本:

private static final SimpleDateFormat   extended    = new SimpleDateFormat( "dd MMM yyyy (HH:mm:ss) zz" );

public static java.util.logging.Logger initLogger(final String name) {
    final java.util.logging.Logger logger = java.util.logging.Logger.getLogger( name );
    try {

        Handler ch = new ConsoleHandler();
        logger.addHandler( ch );

        logger.setLevel( Level.ALL ); // Level selbst setzen

        logger.setUseParentHandlers( false );

        final java.util.logging.SimpleFormatter formatter = new SimpleFormatter() {

            @Override
            public synchronized String format(final LogRecord record) {
                StackTraceElement[] trace = new Throwable().getStackTrace();
                String clickable = "(" + trace[ 7 ].getFileName() + ":" + trace[ 7 ].getLineNumber() + ") ";
                /* Clickable text in Console. */

                for( int i = 8; i < trace.length; i++ ) {
                    /* 0 - 6 is the logging trace, 7 - x is the trace until log method was called */
                    if( trace[ i ].getFileName() == null )
                        continue;
                    clickable = "(" + trace[ i ].getFileName() + ":" + trace[ i ].getLineNumber() + ") -> " + clickable;
                }

                final String time = "<" + extended.format( new Date( record.getMillis() ) ) + "> ";

                StringBuilder level = new StringBuilder("[" + record.getLevel() + "] ");
                while( level.length() < 15 ) /* extend for tabby display */
                    level.append(" ");

                StringBuilder name = new StringBuilder(record.getLoggerName()).append(": ");
                while( name.length() < 15 ) /* extend for tabby display */
                    name.append(" ");

                String thread = Thread.currentThread().getName();
                if( thread.length() > 18 ) /* trim if too long */
                    thread = thread.substring( 0, 16 ) + "..."; 
                else {
                    StringBuilder sb = new StringBuilder(thread);
                    while( sb.length() < 18 ) /* extend for tabby display */
                        sb.append(" ");
                    thread = sb.insert( 0, "Thread " ).toString();
                }

                final String message = "\"" + record.getMessage() + "\" ";

                return level + time + thread + name + clickable + message + "\n";
            }
        };
        ch.setFormatter( formatter );
        ch.setLevel( Level.ALL );
    } catch( final SecurityException e ) {
        e.printStackTrace();
    }
    return logger;
}
问候,
Danyel是中的标准。它包括一个接受对象的重载日志方法。 它将为您记录异常及其原因

例如:

import java.util.logging.Level;
import java.util.logging.Logger;

[...]

Logger logger = Logger.getAnonymousLogger();
Exception e1 = new Exception();
Exception e2 = new Exception(e1);
logger.log(Level.SEVERE, "an exception was thrown", e2);
将记录:

严重:引发了异常
java.lang.Exception:java.lang.Exception
位于LogStacktrace.main(LogStacktrace.java:21)
原因:java.lang.Exception
位于LogStacktrace.main(LogStacktrace.java:20)
顺便说一句,在内部,这正是@philipp wendler所建议的。 看。这只是一个更高级别的接口。

您也可以使用Apache的

例如:

import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.log4j.Logger;


public class Test {

    static Logger logger = Logger.getLogger(Test.class);

    public static void main(String[] args) {

        try{
            String[] avengers = null;
            System.out.println("Size: "+avengers.length);
        } catch (NullPointerException e){
            logger.info(ExceptionUtils.getFullStackTrace(e));
        }
    }

}
控制台输出:

java.lang.NullPointerException
    at com.aimlessfist.avengers.ironman.Test.main(Test.java:11)

如果您使用的是LogBack或SLF4J,那么它应该非常简单。我按下面的方法做

//imports
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

//Initialize logger
Logger logger = LoggerFactory.getLogger(<classname>.class);
try {
   //try something
} catch(Exception e){
   //Actual logging of error
   logger.error("some message", e);
}
//导入
导入org.slf4j.Logger;
导入org.slf4j.LoggerFactory;
//初始化记录器
Logger Logger=LoggerFactory.getLogger(.class);
试一试{
//试试看
}捕获(例外e){
//错误的实际记录
记录器错误(“某些消息”,e);
}

我要做的是使用一个静态方法来处理所有异常,我将日志添加到JOptionPane以向用户显示它,但您可以将结果写入
FileWriter
中的一个文件,该文件被包装在
BufeeredWriter
中。 对于主静态方法,要捕获未捕获的异常,我执行以下操作:

SwingUtilities.invokeLater(新的Runnable(){
@凌驾
公开募捐{
//初始化。。。
}
});
Thread.setDefaultUncaughtExceptionHandler(
新线程。UncaughtExceptionHandler(){
@凌驾
public void uncaughtException(线程t,可丢弃的ex){
handleExceptions(ex,true);
}
}
);
至于方法:

publicstaticvoidhandleexceptions(可丢弃的异常,布尔关闭){
JOptionPane.showMessageDialog(null,
“出现严重错误!\n”,
“系统故障”,
JOptionPane.ERROR_消息);
StringBuilder sb=新的StringBuilder(例如toString());
对于(StackTraceElement存储:例如getStackTrace()){
sb.append(“\n\tat”)。append(ste);
}
而((ex=ex.getCause())!=null){
某人附加(“\n”);
对于(StackTraceElement存储:例如getStackTrace()){
sb.append(“\n\tat”)。append(ste);
}
}
字符串跟踪=sb.toString();
JOptionPane.showMessageDialog(null,
“请将此错误发送给我,以便我可以修复。\n\n”+跟踪,
“系统故障”,
JOptionPane.ERROR\u消息);
如果(关闭){
Runtime.getRuntime().exit(0);
}
}
在您的情况下,您可以像我之前告诉您的那样编写日志,而不是向用户“尖叫”:

String trace=sb.toString();
File File=新文件(“mylog.txt”);
FileWriter myFileWriter=null;
BufferedWriter myBufferedWriter=null;
试一试{
//使用FileWriter(File File,boolean append),您可以将其写入
//文件的结尾
myFileWriter=新的FileWriter(文件,true);
myBufferedWriter=新的BufferedWriter(myFileWriter);
myBufferedWriter.write(跟踪);
}
捕获(IOException ex1){
//你想怎么做就怎么做。你想用递归来处理吗
//这个例外?我不建议你相信我。。。
}
最后{
试一试{
MyBufferedWrite
//imports
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

//Initialize logger
Logger logger = LoggerFactory.getLogger(<classname>.class);
try {
   //try something
} catch(Exception e){
   //Actual logging of error
   logger.error("some message", e);
}