スタックトレースを文字列に変換するにはどうすればよいですか?


1502

の結果をThrowable.getStackTrace()スタックトレースを表す文字列に変換する最も簡単な方法は何ですか?


6
jqnoの答えは実際には質問で指定したThrowable.getStackTrace()メソッドを使用しますが、Brianは使用しません。代わりに、Throwable.printStackTrace()を使用しています。
Stijn de Witt 2012

10
ほぼすべてのJavaプロジェクトにApache commons-langを含める必要があります。非常に一般的な開発ニーズを実装する多くの便利なメソッドが含まれています。
Russell Silva

20
@StijndeWittこれらの3行のコードでは、ほとんどの場合、呼び出した場所から因数分解する必要があります。どこに置くかわからないので、ユーティリティツールボックスに他の便利なスニペットをすべて入れます。ビンゴ!guava / commons-lang /何でも再発明しました...うまくいかないだけです。代わりに賢明なユーティリティライブラリをインポートして、ホイールの再発明を節約してください。初心者の本当の兆候は、ライブラリライターよりも優れた仕事ができると考えていることです。
Andrew Spencer

6
1.グアバは持っている- Throwables.getStackTraceAsString(E)2. Apacheのコモンズラング- ExceptionUtils.getFullStackTrace 3.書き込み、当社独自の方法
user2323036

8
@AndrewSpencer小さなスニペットでこれを実現したいのに、なぜStijndeWittをバッシュしようと頑張っているのか理解できません。小さなユーティリティメソッドを書くことには、それほど大きな危険はありません(「SHEER ARROGANCE oh nooooo !!彼はApacheよりも優れていると思います!!」)。特にJava以外のJVM言語では、スタックトレースをログに記録するためだけにGuavaやCommons Langを含めたくないプロジェクトがたくさんあります。私はScala&Clojureライブラリーを作成していますが、Apache Commons Langを1つの方法だけで推移的な依存関係にするつもりはありません。
jm0

回答:


1039

Exceptionスタックトレースをに変換するには、次のメソッドを使用できますString。このクラスは、Apache commons-langで使用できます。Apachecommons-langは、多くの一般的なオープンソースを備えた最も一般的な依存ライブラリです。

org.apache.commons.lang.exception.ExceptionUtils.getStackTrace(Throwable)


88
@Stijn-公平であるために(私は以下で現在最も高い投票された回答を書きました)、より多くの機能性のためにcommons-langを見る価値があります
Brian Agnew

54
@StijndeWitt Commons Langはかなり一般的です。それは私の仕事で私のプロジェクト/プロジェクトのほとんどにすでに存在しています。
WhyNotHugo

16
@Hugoに感謝します。新しいライブラリの追加を回避するためにStringWriterを使用するつもりでした-それはすでに私の依存関係の3つの依存関係であることがわかりました。残りの部分は、すでに持っているかどうかを確認してください。
Nathanial 2013

33
@MartinAsenov-あなたのロジックに従って、あなたはそのようなライブラリを決して使用しないでしょうか?すでに使用していない限り、使用しないでしょうか?
Brian Agnew 2013

16
Fyi、パッケージが変更され、クラスは次の場所にありorg.apache.commons.lang3.exception.ExceptionUtilsます。
schmmd 2013年

2201

Throwable.printStackTrace(PrintWriter pw)スタックトレースを適切なライターに送信するために使用します。

import java.io.StringWriter;
import java.io.PrintWriter;

// ...

StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
String sStackTrace = sw.toString(); // stack trace as a string
System.out.println(sStackTrace);

505
これほど小さくてシンプルな外部ライブラリを含めたくない場合は、この回答を使用してください。
Stijn de Witt 2012

8
これは、printStackTrace()と同じ方法でスタックトレースをトリミングします。スタック内のすべての例外が表示されますが、例外ごとにスタックがトリミングされる場合があります。トレース全体を必要とする場合は、これを考慮する必要があります。
Laila Agaev 2013年

5
結局のところ、これは、apacheのExceptionUtils.getStackTrace()メソッドが行うこととほぼ同じです。実際にはほとんど手紙に。
ticktock 2014年

6
@BrianAgnew、あなたは閉じてはならないStringWriterPrintWriter
Muhammad Gelbana 2015

13
@BrianAgnew、返信ありがとうございます。それは私は好奇心旺盛だし、ここで私が見つけたものです:stackoverflow.com/questions/14542535/...
ムハンマドGelbana

459

これはうまくいくはずです:

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

69
簡潔なJavaコンテキストは常に陽気です。それprintStackTraceは単に文字列を返し、それを印刷するかどうかの決定をユーザーに残す必要があります:)
dmitry

35
コンソールでのprintStackTrace印刷は許容されますが、少なくともStringとしてそれを返すgetStackTraceがデフォルトで使用可能である必要があります
Mateus Viccari

5
これのどの部分が簡潔ですか?スタックトレースを文字列に入れる以外に存在しない2つのオブジェクトを作成する必要があります。
ArtOfWarfare 2016年

7
@dmitry呼び出されたメソッドはprintXXX()XXXを出力する必要があります。
ローン侯爵

2
@Greg実際、それは皮肉でさえありませんでした、それは彼が言ったことの単純な読みを必要としました。
Andrew

224

Android向けに開発している場合は、これを使用する方がはるかに簡単です。

import android.util.Log;

String stackTrace = Log.getStackTraceString(exception); 

フォーマットは、たとえば、getStacktraceと同じです。

09-24 16:09:07.042: I/System.out(4844): java.lang.NullPointerException
09-24 16:09:07.042: I/System.out(4844):   at com.temp.ttscancel.MainActivity.onCreate(MainActivity.java:43)
09-24 16:09:07.042: I/System.out(4844):   at android.app.Activity.performCreate(Activity.java:5248)
09-24 16:09:07.043: I/System.out(4844):   at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1110)
09-24 16:09:07.043: I/System.out(4844):   at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2162)
09-24 16:09:07.043: I/System.out(4844):   at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2257)
09-24 16:09:07.043: I/System.out(4844):   at android.app.ActivityThread.access$800(ActivityThread.java:139)
09-24 16:09:07.043: I/System.out(4844):   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1210)
09-24 16:09:07.043: I/System.out(4844):   at android.os.Handler.dispatchMessage(Handler.java:102)
09-24 16:09:07.043: I/System.out(4844):   at android.os.Looper.loop(Looper.java:136)
09-24 16:09:07.044: I/System.out(4844):   at android.app.ActivityThread.main(ActivityThread.java:5097)
09-24 16:09:07.044: I/System.out(4844):   at java.lang.reflect.Method.invokeNative(Native Method)
09-24 16:09:07.044: I/System.out(4844):   at java.lang.reflect.Method.invoke(Method.java:515)
09-24 16:09:07.044: I/System.out(4844):   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
09-24 16:09:07.044: I/System.out(4844):   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)

2
ありがとう。この場合、日付とタグは、printStackTrace()のようにすべての行に書き込まれるわけではありません。
CoolMind 2016年

1
実際、コアのLog.getStackTraceStringは、上記の(D. Wroblewskiの)StringWriterとPrintwriterを使用しています。
MikeL 2016

2
ただAndroidのログにそれを印刷する最も簡単な方法は次のとおりです。 Log.e("TAG", "My message", new Throwable());
エリックM.シュプレンゲル


113

警告:原因は含まれていません(通常は役立ちます)。

public String stackTraceToString(Throwable e) {
    StringBuilder sb = new StringBuilder();
    for (StackTraceElement element : e.getStackTrace()) {
        sb.append(element.toString());
        sb.append("\n");
    }
    return sb.toString();
}

1
トレースをトリミングする場合は、このアプローチの拡張を使用します。たとえば、maxLinesパラメーターを渡して、その数の行のみをトレースに追加します
Rich Seller

e.getStackTraceの後の括弧が欠落しています。public static String stackTraceToString(Exception e){StringBuilder sb = new StringBuilder(); for(StackTraceElement element:e.getStackTrace()){sb.append(element.toString()); sb.append( "<br />"); } return sb.toString(); }
rlc '10 / 10/20

2
確かではありませんが、これは根本原因例外のスタックトレースを出力しないと思います。
apoorv020

7
何をするにしても、トレースをトリミングしないでください。GlassFishのログで、有用な部分が削除されたスタックトレースを確認したことが何度もありました。
cayhorstmann 2012

DOSラマーを幸せにするためString.format("%n")に、代わりにまたは同様のものを使用してください"\n"
2013

89

私にとって最もクリーンで簡単な方法は:

import java.util.Arrays;
Arrays.toString(e.getStackTrace());

37
コードはクリーンですが、出力はクリーンではありません。最後に.replaceAll( "、"、 "\ n")を実行する必要があります。ただし、printStackTraceが提案するインデントは失われます。
フューリー

4
これは、トレースを1行で記録する場合に役立ちます
webjockey 2017年

28
public static String getStackTrace(Throwable t) {
    StringWriter sw = new StringWriter();
    t.printStackTrace(new PrintWriter(sw));
    return sw.toString();
}

1
こんにちは、引用されている回答のコメントセクションで、StringWriterおよびPrintWriterオブジェクトはclosed ....であるPrintWriter必要があることを指摘していることを指摘したいと思います(または、閉じる必要もあるので、閉じる必要もありStringWriterます)
エリック

8
触発されたということは、コピーされたという意味ですか?あなたはそれをメソッドに入れるだけです...ここで答えを読むのは、「Groundhog Day」を見るようなものです
Murmel

26

次のコードを使用すると、Stringlog4JなどのAPIを使用することなく、stackTrace全体をフォーマットで取得できますjava.util.Logger

catch (Exception e) {
    StackTraceElement[] stack = e.getStackTrace();
    String exception = "";
    for (StackTraceElement s : stack) {
        exception = exception + s.toString() + "\n\t\t";
    }
    System.out.println(exception);
    // then you can send the exception string to a external file.
}

1
うん、でもちょっとかさばらないと思いませんか?合理的なサイズのプロジェクトロギングフレームワークでは
絶対

これは最初にエラーメッセージを与えていません。追加可能です
kommradHomer 2013年

単純な連結の代わりにStringBufferを使用したい場合があります。
dedda1994、19年

これは、プライバシー上の理由からメッセージをログに記録することが許可されていない場合に役立ちます。
A1m

ただし、このソリューションは内部の原因を記録しないことに注意してください
A1m

19

以下は、コードに直接コピーして貼り付けることができるバージョンです。

import java.io.StringWriter; 
import java.io.PrintWriter;

//Two lines of code to get the exception into a StringWriter
StringWriter sw = new StringWriter();
new Throwable().printStackTrace(new PrintWriter(sw));

//And to actually print it
logger.info("Current stack trace is:\n" + sw.toString());

または、キャッチブロックで

} catch (Throwable t) {
    StringWriter sw = new StringWriter();
    t.printStackTrace(new PrintWriter(sw));
    logger.info("Current stack trace is:\n" + sw.toString());
}

これは、現在の機能の範囲を超えて続行されます。どこThrowableで定義されていますか?
n611x007

16
Arrays.toString(thrown.getStackTrace())

結果を文字列に変換する最も簡単な方法です。これをプログラムで使用して、スタックトレースを出力します。

LOGGER.log(Level.SEVERE, "Query Builder Issue Stack Trace : {0} ,Message : {1} objid {2}", new Object[]{Arrays.toString(e.getStackTrace()), e.getMessage(),objId});

私のために働いた、トリミングされているようには見えない!他の回答よりも簡単で、外部ライブラリもありません。すばらしい回答です。
Shaung Cheng

16

スタックトレースをaに出力しPrintStream、それをa に変換しますString

// ...

catch (Exception e)
{
    ByteArrayOutputStream out = new ByteArrayOutputStream(); 
    e.printStackTrace(new PrintStream(out));
    String str = new String(out.toByteArray());

    System.out.println(str);
}

1
これが最も直接的な答えです
DaSqy Stc

11

スタックトレースを文字列に出力する

import java.io.PrintWriter;
import java.io.StringWriter;

public class StackTraceUtils {
    public static String stackTraceToString(StackTraceElement[] stackTrace) {
        StringWriter sw = new StringWriter();
        printStackTrace(stackTrace, new PrintWriter(sw));
        return sw.toString();
    }
    public static void printStackTrace(StackTraceElement[] stackTrace, PrintWriter pw) {
        for(StackTraceElement stackTraceEl : stackTrace) {
            pw.println(stackTraceEl);
        }
    }
}

のインスタンスを作成せずに現在のスレッドスタックトレースを出力する場合に便利ですが、Throwable新しいThrowableスタックトレースを作成してそこから取得する方が、実際にはを呼び出すよりも高速で安価ですThread.getStackTrace


11

コトリン

Throwableクラスを拡張すると、Stringプロパティが得られますerror.stackTraceString

val Throwable.stackTraceString: String
  get() {
    val sw = StringWriter()
    val pw = PrintWriter(sw)
    this.printStackTrace(pw)
    return sw.toString()
  }

10
private String getCurrentStackTraceString() {
    StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
    return Arrays.stream(stackTrace).map(StackTraceElement::toString)
            .collect(Collectors.joining("\n"));
}

1
eddyrkokrありがとうございます!それは私のすべてのクラスに最適です。ベースのTestNGクラスに追加したばかりで、すべてのテストからスタックトレースを1つずつ収集します。
Krzysztof Walczewski、

9

コメントの最初のセットでの巧妙な狙いは非常に面白いですが、それはあなたが何をしようとしているのかに本当に依存しています。正しいライブラリがまだない場合は、3行のコード(D. Wroblewskiの回答のように)が最適です。OTOH、(ほとんどの大規模プロジェクトと同様に)apache.commonsライブラリがすでにある場合、Amarの答えは短くなります。わかりました。ライブラリを取得して正しくインストールするのに10分かかる場合があります(何をしているかわかっている場合は1分未満です)。しかし、時計は刻々と過ぎています。そのため、時間に余裕がないかもしれません。JarekPrzygódzkiには興味深い警告がありました-「ネストされた例外が必要ない場合」。

しかし、ネストされたすべての完全なスタックトレース必要な場合はどうなりますか?その場合、秘密はapache.commonのgetFullStackTraceを使用することです(http://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/exception/ExceptionUtils.htmlを参照)#getFullStackTrace%28java.lang.Throwable%29

それは私のベーコンを救った。ヒントをありがとう、アマール!


9

Apache Commons Lang 3.4JavaDoc)のコード:

public static String getStackTrace(final Throwable throwable) {
    final StringWriter sw = new StringWriter();
    final PrintWriter pw = new PrintWriter(sw, true);
    throwable.printStackTrace(pw);
    return sw.getBuffer().toString();
}

他の回答との違いは、で使用 autoFlushすることPrintWriterです。


8

java.io.*それなしでは、このようにすることができます。

String trace = e.toString() + "\n";                     

for (StackTraceElement e1 : e.getStackTrace()) {
    trace += "\t at " + e1.toString() + "\n";
}   

そして、trace変数はスタックトレースを保持します。出力には初期原因も含まれています。出力はprintStackTrace()

例、printStackTrace()利回り:

java.io.FileNotFoundException: / (Is a directory)
    at java.io.FileOutputStream.open0(Native Method)
    at java.io.FileOutputStream.open(FileOutputStream.java:270)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:213)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:101)
    at Test.main(Test.java:9)

traceに印刷したときの文字列は、保持していますstdout

java.io.FileNotFoundException: / (Is a directory)
     at java.io.FileOutputStream.open0(Native Method)
     at java.io.FileOutputStream.open(FileOutputStream.java:270)
     at java.io.FileOutputStream.<init>(FileOutputStream.java:213)
     at java.io.FileOutputStream.<init>(FileOutputStream.java:101)
     at Test.main(Test.java:9)

5

Scalaバージョン

def stackTraceToString(e: Exception): String = {
  import java.io.PrintWriter
  val sw = new StringWriter()
  e.printStackTrace(new PrintWriter(sw))
  sw.toString
}

5

Java 8を使用している場合は、これを試してください

Arrays.stream(e.getStackTrace())
                .map(s->s.toString())
                .collect(Collectors.joining("\n"));

あなたはとしてgetStackTrace()提供さThrowable.javaれる関数のコードを見つけることができます:

public StackTraceElement[] getStackTrace() {
    return getOurStackTrace().clone();
}

の場合StackTraceElement、それは次のように提供さtoString()れます:

public String toString() {
    return getClassName() + "." + methodName +
        (isNativeMethod() ? "(Native Method)" :
         (fileName != null && lineNumber >= 0 ?
          "(" + fileName + ":" + lineNumber + ")" :
          (fileName != null ?  "("+fileName+")" : "(Unknown Source)")));
}

したがってStackTraceElement、 "\ n"で結合します。


このソリューションは、スタックトレースタブのインデントを尊重しません。
krizajb 2018

4

例外の原因も含まれるGalaの回答の拡張:

private String extrapolateStackTrace(Exception ex) {
    Throwable e = ex;
    String trace = e.toString() + "\n";
    for (StackTraceElement e1 : e.getStackTrace()) {
        trace += "\t at " + e1.toString() + "\n";
    }
    while (e.getCause() != null) {
        e = e.getCause();
        trace += "Cause by: " + e.toString() + "\n";
        for (StackTraceElement e1 : e.getStackTrace()) {
            trace += "\t at " + e1.toString() + "\n";
        }
    }
    return trace;
}

4

解決策は、配列のstackTraceを文字列データ型に変換することです。次の例を参照してください。

import java.util.Arrays;

try{

}catch(Exception ex){
    String stack = Arrays.toString(ex.getStackTrace());
    System.out.println("stack "+ stack);
}

4

Java 8 Stream APIを使用すると、次のようなことができます。

Stream
    .of(throwable.getStackTrace())
    .map(StackTraceElement::toString)
    .collect(Collectors.joining("\n"));

スタックトレース要素の配列を取得して文字列に変換し、複数行の文字列に結合します。


2
この解決策はメッセージを削除し、すべての親トレースを無視しています
judovana

3

スタックトレースを囲まれた複数行の文字列に変換するためのワンライナー:

Stream.of(e.getStackTrace()).map((a) -> a.toString()).collect(Collectors.joining("\n", "[", "]"))

「そのまま」ロガーに渡すのは簡単です。


あなたはprintStackTrace()こことは異なる何かを手に入れます:1)スローされた例外。2)原因とそのスタックトレース
バリホン2018

変換はprintStackTrace()問題の一部だったので、違いはかなり予想されます。
Andrey

2

外部ライブラリを使用せず、Android向けに開発ていない場合は、次のような「拡張」メソッドを作成できます。

public static String getStackTraceString(Throwable e) {
    return getStackTraceString(e, "");
}

private static String getStackTraceString(Throwable e, String indent) {
    StringBuilder sb = new StringBuilder();
    sb.append(e.toString());
    sb.append("\n");

    StackTraceElement[] stack = e.getStackTrace();
    if (stack != null) {
        for (StackTraceElement stackTraceElement : stack) {
            sb.append(indent);
            sb.append("\tat ");
            sb.append(stackTraceElement.toString());
            sb.append("\n");
        }
    }

    Throwable[] suppressedExceptions = e.getSuppressed();
    // Print suppressed exceptions indented one level deeper.
    if (suppressedExceptions != null) {
        for (Throwable throwable : suppressedExceptions) {
            sb.append(indent);
            sb.append("\tSuppressed: ");
            sb.append(getStackTraceString(throwable, indent + "\t"));
        }
    }

    Throwable cause = e.getCause();
    if (cause != null) {
        sb.append(indent);
        sb.append("Caused by: ");
        sb.append(getStackTraceString(cause, indent));
    }

    return sb.toString();
}

2

古い質問ですが、すべてのスタックを印刷したくない特別なケースを追加したいと思いますですが、特定のクラスやパッケージを除いて、実際には関係のない部分を削除することで、ます。

PrintWriter使用の代わりにSelectivePrintWriter

// This filters out this package and up.
String packageNameToFilter = "org.springframework";

StringWriter sw = new StringWriter();
PrintWriter pw = new SelectivePrintWriter(sw, packageNameToFilter);
e.printStackTrace(pw);
String sStackTrace = sw.toString(); 
System.out.println(sStackTrace);

どこSelectivePrintWriterのクラスは、次式で与えられます。

public class SelectivePrintWriter extends PrintWriter {
    private boolean on = true;
    private static final String AT = "\tat";
    private String internal;

    public SelectivePrintWriter(Writer out, String packageOrClassName) {
        super(out);
        internal = "\tat " + packageOrClassName;
    }

    public void println(Object obj) {
        if (obj instanceof String) {
            String txt = (String) obj;
            if (!txt.startsWith(AT)) on = true;
            else if (txt.startsWith(internal)) on = false;
            if (on) super.println(txt);
        } else {
            super.println(obj);
        }
    }
}

このクラスは、Regex containsまたはその他の基準でフィルターで除外するように簡単に調整できることに注意してください。また、Throwable実装の詳細に依存することにも注意してください(変更される可能性は低いですが、それでも変わりません)。


1
はい、これはうまく機能し、実際には非常に便利なアイデアです。
gil.fernandes 2017年

2
 import java.io.PrintWriter;
import java.io.StringWriter;

public class PrintStackTrace {

    public static void main(String[] args) {

        try {
            int division = 0 / 0;
        } catch (ArithmeticException e) {
            StringWriter sw = new StringWriter();
            e.printStackTrace(new PrintWriter(sw));
            String exceptionAsString = sw.toString();
            System.out.println(exceptionAsString);
        }
    }
}

プログラムを実行すると、出力は次のようになります。

java.lang.ArithmeticException: / by zero
at PrintStackTrace.main(PrintStackTrace.java:9)

1

なぜ誰も言及しなかったのかしら ExceptionUtils.getStackFrames(exception)

私にとっては、スタックトレースをすべての原因とともに最後までダンプするのに最も便利な方法です。

String.join("\n", ExceptionUtils.getStackFrames(exception));

0

警告:これは少し外れたトピックかもしれませんが、まあ...;)

元のポスターの理由がそもそもスタックトレースを文字列として必要とした理由がわかりません。スタックトレースがSLF4J / Logback LOGに出力されるはずなのに、例外がスローされなかった場合、またはスローされるべきではない場合は、次のようにします。

public void remove(List<String> ids) {
    if(ids == null || ids.isEmpty()) {
        LOG.warn(
            "An empty list (or null) was passed to {}.remove(List). " +
            "Clearly, this call is unneccessary, the caller should " + 
            "avoid making it. A stacktrace follows.", 
            getClass().getName(),
            new Throwable ("Stacktrace")
        );

        return;
    }

    // actual work, remove stuff
}

外部ライブラリを必要としないため、私はそれが好きです(もちろん、とにかくほとんどの場合に配置されるロギングバックエンド以外)。


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