スタックトレースをlog4jに送信する方法は?


152

e.printStackTrace()を実行すると、例外をキャッチして、標準出力(たとえば、コンソールなど)で次のようになります。

java.io.FileNotFoundException: so.txt
        at java.io.FileInputStream.<init>(FileInputStream.java)
        at ExTest.readMyFile(ExTest.java:19)
        at ExTest.main(ExTest.java:7)

これを、たとえばlog4jのようなロガーに送信して、以下を取得します。

31947 [AWT-EventQueue-0] ERROR Java.io.FileNotFoundException: so.txt
32204 [AWT-EventQueue-0] ERROR    at java.io.FileInputStream.<init>(FileInputStream.java)
32235 [AWT-EventQueue-0] ERROR    at ExTest.readMyFile(ExTest.java:19)
32370 [AWT-EventQueue-0] ERROR    at ExTest.main(ExTest.java:7)

これどうやってするの?

try {
   ...
} catch (Exception e) {
    final String s;
    ...  // <-- What goes here?
    log.error( s );
}

回答:


262

例外をロガーに直接渡します。

try {
   ...
} catch (Exception e) {
    log.error( "failed!", e );
}

スタックトレースをレンダリングするのは、log4j次第です。


32
ロガーは最初の引数としてオブジェクトを受け取り、それをtoString()します。ただし、2番目の引数はThrowableでなければならず、スタックトレースを表示します。
Peter Lawrey

1
最初の文字列に何を入れればよいかわからないので、通常、結局log.error(e.getLocalizedMessage(), e)は完全に冗長になります。最初の引数のnullを処理しますか?
マークピーターズ

5
@マーク:例外のメッセージよりもコンテキストに関連するメッセージを与えてみてください。
skaffman 2010

2
@マークピーターズ、良い例としては、現在のメソッドへの引数をメッセージとしてログに記録する、またはFileNotFound例外の場合は、開こうとしたパスの完全な名前が挙げられます。何が問題なのかを見つけるのに役立つすべてのもの-状況をデバッグできないと考えてください。
するThorbjörnRavnアンデルセン

1
@skaffman:実際に使用log4j-1.2.8.jarしていて、すべてstackTraceをログファイルに印刷したいので、上記のように試しましたが、ログファイルのみに印刷していますnullPointerExceptione.printStackTrace()すべてのトレースを出力するコードで使用されました。なぜこのKolaveryなのか?
ユバラジ2013

9

例外を発生させずにスタックトレースをログに記録したい場合は、次のようにします。

String message = "";

for(StackTraceElement stackTraceElement : Thread.currentThread().getStackTrace()) {                         
    message = message + System.lineSeparator() + stackTraceElement.toString();
}   
log.warn("Something weird happened. I will print the the complete stacktrace even if we have no exception just to help you find the cause" + message);

3
System.lineSeparator()の+1、これは、リモートサービスからの応答として取得したスタックトレースを出力するのに役立ちました
Stephanie

1
私が検索したものですが、ここではStringBuilderを使用する必要があります
Xerus

9

スタックトレースは、を介して文字列として取得することもできますExceptionUtils.getStackTrace

参照:ExceptionUtils.java

単純log.debugにするために、私はそれをにのみ使用しlog.errorます。


4

それが私に起こったからといって、役に立つかもしれません。あなたがこれをするなら

try {
   ...
} catch (Exception e) {
    log.error( "failed! {}", e );
}

スタックトレース全体ではなく、例外のヘッダーを取得します。ロガーはあなたが文字列を渡していると考えているからです。{}スカフマンが言ったようにせずにそれを行います


1
確かにここでスタックトレース全体を取得できますが、{}もそのまま(置換なしで)出力されますか?
k1eran 2015

1
私の友達がそう確信していないでください!それは私にはうまくいきませんでした、私はヘッダーだけを得ました。ただし、log4jのバージョンによって異なる可能性があります
iberbeu

スタックトレースをThrowable.toString()返さないため、@ iberbeuは正しいです。( '{}'との関係を認識しているロガーを使用していると仮定します。)

4

skaffmanからの答えは間違いなく正しい答えです。など、すべてのロガーの方法はerror()warn()info()debug()2番目のパラメータとしてのThrowableを取ります:

try {
...
 } catch (Exception e) {
logger.error("error: ", e);
}

ただし、スタックトレースを文字列として抽出することもできます。"{}"プレースホルダーを使用してフォーマット機能を利用したい場合に役立つことがあります-メソッドを参照してくださいvoid info(String var1, Object... var2);。この場合、スタックトレースが文字列であるとすると、実際には次のようになります。

try {
...
 } catch (Exception e) {
String stacktrace = TextUtils.getStacktrace(e);
logger.error("error occurred for usename {} and group {}, details: {}",username, group, stacktrace);
}

これは、メソッドの場合と同じ方法で、パラメータ化されたメッセージとスタックトレースを最後に出力します。 logger.error("error: ", e);

私は実際に、スタックトレースからノイズをスマートに取り除くオプションを備えた文字列としてスタックトレースを抽出するためのユーティリティを備えたオープンソースライブラリを作成しました。つまり、抽出したスタックトレースに関心のあるパッケージ接頭辞を指定すると、無関係な部分が除外され、非常にサイズの大きな情報が残ります。ライブラリが持つユーティリティとその入手場所(Mavenアーティファクトとgitソースの両方)とその使用方法を説明する記事へのリンクは次のとおりです。スタックトレースフィルタリング、サイレント文字列解析Unicodeコンバーター、バージョン比較備えたオープンソースJavaライブラリ「スタックトレースノイズフィルター」の段落を参照


1
埋もれたが良い答え。
ペイン

ありがとう、@ payne。素敵なフィードバックに感謝します
マイケルガントマン

2

この回答は、尋ねられた質問に関連しているのではなく、質問のタイトルに関連している可能性があります。

public class ThrowableTest {

    public static void main(String[] args) {

        Throwable createdBy = new Throwable("Created at main()");
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        PrintWriter pw = new PrintWriter(os);
        createdBy.printStackTrace(pw);
        try {
            pw.close();
            os.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        logger.debug(os.toString());
    }
}

または

public static String getStackTrace (Throwable t)
{
    StringWriter stringWriter = new StringWriter();
    PrintWriter  printWriter  = new PrintWriter(stringWriter);
    t.printStackTrace(printWriter);
    printWriter.close();    //surprise no IO exception here
    try {
        stringWriter.close();
    }
    catch (IOException e) {
    }
    return stringWriter.toString();
}

または

StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
for(StackTraceElement stackTrace: stackTraceElements){
    logger.debug(stackTrace.getClassName()+ "  "+ stackTrace.getMethodName()+" "+stackTrace.getLineNumber());
}

1

Log4j 2では、Logger.catching()を使用して、キャッチされた例外からのスタックトレースをログに記録できます。

    try {
        String msg = messages[messages.length];
        logger.error("An exception should have been thrown");
    } catch (Exception ex) {
        logger.catching(ex);
    }

0

これは、優れたlog4jエラー/例外ロギングです。splunk/他のロギング/モニタリングs / wで読み取り可能です。すべてがキーと値のペアの形式です。log4jは例外objからスタックトレースを取得しますe

    try {
          ---
          ---
    } catch (Exception e) {
        log.error("api_name={} method={} _message=\"error description.\" msg={}", 
                  new Object[]{"api_name", "method_name", e.getMessage(), e});
    }


-1

次のコードを使用できます。

import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

public class LogWriterUtility {
    Logger log;

    public LogWriterUtility(Class<?> clazz) {
        log = LogManager.getLogger(clazz);
    }

public void errorWithAnalysis( Exception exception) {

        String message="No Message on error";
        StackTraceElement[] stackTrace = exception.getStackTrace();
        if(stackTrace!=null && stackTrace.length>0) {
            message="";
            for (StackTraceElement e : stackTrace) {
                message += "\n" + e.toString();
            }
        }
        log.error(message);


    }

}

ここで呼び出すことができます: LogWriterUtility.errorWithAnalysis( YOUR_EXCEPTION_INSTANCE);

stackTraceをログに出力します。


-2

これを作成class

public class StdOutErrLog {

private static final Logger logger = Logger.getLogger(StdOutErrLog.class);

public static void tieSystemOutAndErrToLog() {
    System.setOut(createLoggingProxy(System.out));
    System.setErr(createLoggingProxy(System.err));
}

public static PrintStream createLoggingProxy(final PrintStream realPrintStream) {
    return new PrintStream(realPrintStream) {
        public void print(final String string) {
            logger.info(string);
        }
        public void println(final String string) {
            logger.info(string);
        }
    };
}
}

コードでこれを呼び出します

StdOutErrLog.tieSystemOutAndErrToLog();
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.