Java 예외에 대해 가능한 한 많은 정보를 기록하는 방법은 무엇입니까?
예외를 로깅 할 때 몇 번 만난 일반적인 문제가 있습니다. 다루어야 할 다양한 유형이있는 것 같습니다. 예를 들어 일부는 다른 예외를 래핑하고 일부는 메시지를 전혀 가지고 있지 않습니다.
대부분의 코드 내가 사용 중 로그 예외를 본 적이 getMessage()
나 toString(
) 그러나 이들은 항상 문제를 정확하게 파악하는 데 필요한 모든 정보를 수집하지 않습니다 - 같은 다른 방법을 getCause()
하고 getStackTrace()
때로는 추가 정보를 제공합니다.
예를 들어 Eclipse Inspect 창에서 지금보고있는 예외는 InvocationTargetException
. 예외 자체에는 원인, 메시지, 스택 추적이 없지만 getCause ()의 대상은 InvalidUseOfMatchersException
이러한 세부 정보가 채워져 있습니다.
그래서 내 질문은 다음과 같습니다. 입력으로 모든 유형 의 예외가 주어지면 예외에 대한 모든 관련 정보를 포함하는 멋진 형식의 문자열을 출력하는 단일 메서드를 제공하십시오 (예 : getCause()
다른 것들 중에서 재귀 적으로 호출 할 수 있습니까?).이 질문을 게시하기 전에 거의 이걸 직접 찔러야하는데 바퀴를 재발 명하고 싶지는 않아요-확실히 그런 일은 전에 여러 번 했어야하는데 ...?
이 작업을 수행하기 위해 특정 로깅 또는 유틸리티 프레임 워크를 가리 키지 마십시오. 내가 작업중인 프로젝트에 외부 종속성을 추가 할 권한이없고 실제로 파일이 아닌 웹 페이지의 일부에 기록되기 때문에 라이브러리가 아닌 코드 조각을 찾고 있습니다. 그러한 프레임 워크에서 코드 조각을 복사하고 그에 기여하는 경우라면 괜찮습니다 :-)
이 java.util.logging
패키지 는 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가 제안한 것과 정확히 일치합니다. 의 소스 코드를SimpleFormatter.java
참조하십시오 . 이것은 단지 더 높은 수준의 인터페이스입니다.
에서 printStacktrace()
제공 하는 방법 Throwable
(및 모든 예외)에 어떤 문제가 있습니까? 루트 예외의 유형, 메시지 및 스택 추적과 모든 (중첩 된) 원인을 포함하여 요청한 모든 정보를 표시합니다. Java 7에서는 try-with-resources 문에서 발생할 수있는 "억제 된"예외에 대한 정보도 표시합니다.
물론 System.err
메서드의 인수가없는 버전 인 에 작성하고 싶지 않으므로 대신 사용 가능한 오버로드 중 하나를 사용하십시오.
특히, String을 얻고 싶다면 :
Exception e = ...
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionDetails = sw.toString();
훌륭한 Guava 라이브러리 를 사용하는 경우 다음을 수행하는 유틸리티 메서드를 제공합니다 com.google.common.base.Throwables#getStackTraceAsString(Throwable)
..
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);
}
얼마 전에 작성한 로깅 스크립트가 도움이 될 수 있지만 정확히 원하는 것은 아닙니다. 이것은 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
Apache의 ExceptionUtils를 사용할 수도 있습니다 .
예:
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)
Something that I do is to have a static method that handles all exceptions and I add the log to a JOptionPane to show it to the user, but you could write the result to a file in FileWriter
wraped in a BufeeredWriter
. For the main static method, to catch the Uncaught Exceptions I do:
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 );
}
}
);
And as for the method:
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 );
}
}
In you case, instead of "screaming" to the user, you could write a log like I told you before:
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...
}
}
I hope I have helped.
Have a nice day. :)
ReferenceURL : https://stackoverflow.com/questions/14606293/how-to-log-as-much-information-as-possible-for-a-java-exception
'programing' 카테고리의 다른 글
BASH에서 "CLS"와 동일합니까? (0) | 2021.01.14 |
---|---|
getSupportFragmentManager ()가 정의되지 않았습니다. (0) | 2021.01.14 |
Windows 용 Linux에서 Qt 5 빌드 (0) | 2021.01.14 |
Pandas에서 MultiIndex 인덱스 열 값을 쿼리하는 방법 (0) | 2021.01.14 |
Net.Reflector의 "네임 스페이스는 필드 또는 메서드와 같은 멤버를 직접 포함 할 수 없습니다." (0) | 2021.01.14 |