web-dev-qa-db-ja.com

Java Exception?

例外をログに記録するときに何度か遭遇した共通の問題があります。対処すべきさまざまな種類があるようです。例えば。一部は他の例外をラップし、一部はまったくメッセージを持たない-タイプだけです。

私が見たほとんどのコードはgetMessage()またはtoString()を使用して例外を記録しますが、これらは常に問題を特定するために必要なすべての情報をキャプチャするわけではありません-getCause()getStackTrace()時々追加情報を提供します。

例として、Eclipse Inspectウィンドウで現在見ている例外はInvocationTargetExceptionです。例外自体には原因もメッセージもスタックトレースもありませんが、getCause()からのターゲットはこれらの詳細が取り込まれたInvalidUseOfMatchersExceptionです。

したがって、私の質問は:any typeの例外を入力として指定すると、all例外に関する関連情報を含む適切にフォーマットされた文字列を出力する単一のメソッドを提供してください再帰的にgetCause()を呼び出しますか?)この質問を投稿する前に、私はこれを自分で突き刺そうとしていましたが、本当に車輪を再発明したくありません-確かにそのようなことは何度も行われたに違いありません。 ..?

これを行うために特定のロギングまたはユーティリティフレームワークを指定しないでください。プロジェクトに外部依存関係を追加する権限がないため、ライブラリではなくコードのフラグメントを探しています。作業中で、実際にはファイルではなくWebページの一部に記録されています。そのようなフレームワークからコードフラグメントをコピーする(そしてそれを帰属させる)場合は問題ありません:-)

53
Steve Chambers

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が提案しているとおりです。 SimpleFormatter.Javaのソースコード を参照してください。これは単なる高レベルのインターフェースです。

69
flup

Throwableによって提供されるprintStacktrace()メソッド(およびすべての例外)の何が問題になっていますか?タイプ、メッセージ、ルート例外のスタックトレース、およびすべての(ネストされた)原因など、要求したすべての情報が表示されます。 Java 7では、try-with-resourcesステートメントで発生する可能性のある「抑制された」例外に関する情報も表示されます。

もちろん、メソッドの引数なしバージョンが行う_System.err_には書き込みたくないので、代わりに利用可能なオーバーロードの1つを使用します。

特に、単に文字列を取得したい場合:

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

素晴らしい Guava ライブラリを使用する場合、これを行うユーティリティメソッド com.google.common.base.Throwables#getStackTraceAsString(Throwable) が提供されます。

19
Philipp Wendler

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);
}
11

少し前に書いたログ記録スクリプトが役立つかもしれませんが、それはまさにあなたが望むものではありません。 System.out.printlnのように機能しますが、StackTraceなどに関するmuch more情報を使用します。また、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;
}

コンソールへのこの出力に注意してください。変更できます。 http://docs.Oracle.com/javase/1.4.2/docs/api/Java/util/logging/Logger.html を参照してください。詳細については。

さて、次はおそらくあなたが望むことをするでしょう。 Throwableのすべての原因を調べて、文字列に保存します。これは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

1
Danyel

私がやることは、すべての例外を処理する静的メソッドを持ち、ログをJOptionPaneに追加してユーザーに表示することですが、FileWriterのファイルに結果を書き込むことができますBufeeredWriter。メインの静的メソッドの場合、キャッチされない例外をキャッチするには、次のようにします。

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 );
    }
}

あなたの場合、ユーザーに「叫ぶ」代わりに、前に言ったようにログを書くことができます:

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...
    }
}

お役に立てば幸いです。

ごきげんよう。 :)

1

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)
1
RIP_SunMicroSys