在记录例外情况时,我遇到了一些常见问题。似乎有各种不同类型可以处理。例如。一些包装其他异常,有些根本没有消息 - 只是一种类型。
我见过的大多数代码使用getMessage()
或toString(
来记录例外情况,但这些代码并不总是捕获查明问题所需的所有信息 - 其他方法如getCause()
并且getStackTrace()
有时会提供其他信息。
作为一个例子,我现在在Eclipse Inspect窗口中看到的Exception是InvocationTargetException
。 Exception本身没有原因,没有消息,没有堆栈跟踪......但getCause()的目标是InvalidUseOfMatchersException
,并填充了这些详细信息。
所以我的问题是:如果任何类型作为输入的异常,请提供一个方法,该方法将输出格式正确的String,其中包含所有有关异常的相关信息(例如,可能递归地调用getCause()
等等?)在发布这个问题之前,我几乎要自己捅这个问题,但是真的不想重新发明轮子 - 当然这样的事情肯定已经完成了很多之前......?
请不要指向任何特定的日志记录或实用程序框架来执行此操作。我正在寻找代码片段而不是库,因为我没有权利在我正在处理的项目上添加外部依赖项,它实际上是记录到网页的一部分而不是文件。如果是将代码片段从这样的框架中复制出来(并归因于它),那很好: - )
答案 0 :(得分:69)
java.util.logging
package是Java SE中的标准。其Logger
包含一个接受Throwable
个对象的重载日志方法。
它会记录异常堆栈跟踪及其原因。
例如:
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);
将记录:
SEVERE: an exception was thrown
java.lang.Exception: java.lang.Exception
at LogStacktrace.main(LogStacktrace.java:21)
Caused by: java.lang.Exception
at LogStacktrace.main(LogStacktrace.java:20)
顺便说一句,在内部,这正是@ philipp-wendler所建议的。
请参阅source code for SimpleFormatter.java
。这只是一个更高级别的界面。
答案 1 :(得分:18)
printStacktrace()
提供的Throwable
方法有什么问题(因此每个例外)?它显示了您请求的所有信息,包括根异常的类型,消息和堆栈跟踪以及所有(嵌套)原因。在Java 7中,它甚至会向您显示有关try-with-resources语句中可能出现的“被抑制”异常的信息。
当然你不想写System.err
,这是方法的无参数版本,所以改为使用其中一个可用的重载。
特别是,如果你只想获得一个字符串:
Exception e = ...
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionDetails = sw.toString();
如果您碰巧使用了很棒的Guava库,它会提供一种实用程序方法:com.google.common.base.Throwables#getStackTraceAsString(Throwable)
。
答案 2 :(得分: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);
}
答案 3 :(得分:2)
我所做的是拥有一个处理所有异常的静态方法,并将日志添加到JOptionPane以向用户显示,但是您可以将结果写入FileWriter
中的文件中。 BufeeredWriter
。
对于main静态方法,要捕获我所做的Uncaught Exceptions:
SwingUtilities.invokeLater( new Runnable() {
@Override
public void run() {
//Initializations...
}
});
Thread.setDefaultUncaughtExceptionHandler(
new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException( Thread t, Throwable ex ) {
handleExceptions( ex, true );
}
}
);
至于方法:
public static void handleExceptions( Throwable ex, boolean shutDown ) {
JOptionPane.showMessageDialog( null,
"A CRITICAL ERROR APPENED!\n",
"SYSTEM FAIL",
JOptionPane.ERROR_MESSAGE );
StringBuilder sb = new StringBuilder(ex.toString());
for (StackTraceElement ste : ex.getStackTrace()) {
sb.append("\n\tat ").append(ste);
}
while( (ex = ex.getCause()) != null ) {
sb.append("\n");
for (StackTraceElement ste : ex.getStackTrace()) {
sb.append("\n\tat ").append(ste);
}
}
String trace = sb.toString();
JOptionPane.showMessageDialog( null,
"PLEASE SEND ME THIS ERROR SO THAT I CAN FIX IT. \n\n" + trace,
"SYSTEM FAIL",
JOptionPane.ERROR_MESSAGE);
if( shutDown ) {
Runtime.getRuntime().exit( 0 );
}
}
在你的情况下,而不是&#34;尖叫&#34;对于用户,您可以像我之前写的那样写一个日志:
String trace = sb.toString();
File file = new File("mylog.txt");
FileWriter myFileWriter = null;
BufferedWriter myBufferedWriter = null;
try {
//with FileWriter(File file, boolean append) you can writer to
//the end of the file
myFileWriter = new FileWriter( file, true );
myBufferedWriter = new BufferedWriter( myFileWriter );
myBufferedWriter.write( trace );
}
catch ( IOException ex1 ) {
//Do as you want. Do you want to use recursive to handle
//this exception? I don't advise that. Trust me...
}
finally {
try {
myBufferedWriter.close();
}
catch ( IOException ex1 ) {
//Idem...
}
try {
myFileWriter.close();
}
catch ( IOException ex1 ) {
//Idem...
}
}
我希望我有所帮助。
祝你有个愉快的一天。 :)
答案 4 :(得分:1)
我之前写过的日志记录脚本可能会有所帮助,尽管它并不完全符合您的要求。它的作用方式类似于System.out.println,但有关于StackTrace等的更多信息。它还为Eclipse提供了Clickable文本:
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;
}
请注意此输出到控制台,您可以更改它,有关详细信息,请参阅http://docs.oracle.com/javase/1.4.2/docs/api/java/util/logging/Logger.html。
现在,以下内容可能会满足您的需求。它将遍历Throwable的所有原因并将其保存在String中。请注意,这不会使用StringBuilder
,因此您可以通过更改进行优化。
Throwable e = ...
String detail = e.getClass().getName() + ": " + e.getMessage();
for( final StackTraceElement s : e.getStackTrace() )
detail += "\n\t" + s.toString();
while( ( e = e.getCause() ) != null ) {
detail += "\nCaused by: ";
for( final StackTraceElement s : e.getStackTrace() )
detail += "\n\t" + s.toString();
}
的问候,
Danyel
答案 5 :(得分:1)
您也可以使用Apache的ExceptionUtils.
示例:
Mat
控制台输出:
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));
}
}
}