web-dev-qa-db-ja.com

スタックトレースを文字列に変換する方法

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

1364
ripper234

ExceptionスタックトレースをStringに変換するために以下のメソッドを使うことができます。このクラスは Apache commons-langで利用可能です。これは多くの一般的なオープンソースを持つ最も一般的な依存ライブラリです

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

921
amar

スタックトレースを適切なライターに送信するには 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);
2033
Brian Agnew

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

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

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)
193
Vicky Kapadia

グアバの Throwables クラス

実際のThrowableインスタンスがある場合は、 Google GuavaThrowables.getStackTraceAsString() があります。

例:

String s = Throwables.getStackTraceAsString ( myException ) ;
110
stumbav

警告:原因は含まれていません(通常は便利です)

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

私にとって最もクリーンで簡単な方法は次のとおりです。

import Java.util.Arrays;
Arrays.toString(e.getStackTrace());
84
Vladas Diržys
public static String getStackTrace(Throwable t) {
    StringWriter sw = new StringWriter();
    t.printStackTrace(new PrintWriter(sw));
    return sw.toString();
}
29
Akira Yamamoto

次のコードを使用すると、log4JやJava.util.LoggerなどのAPIを使用せずに、stackTrace全体をString形式で取得できます。

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

これは、コードに直接コピーペースト可能なバージョンです。

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());
}
19
rouble

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

// ...

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

    System.out.println(str);
}
11
Baked Inhalf

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

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
private String getCurrentStackTraceString() {
    StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
    return Arrays.stream(stackTrace).map(StackTraceElement::toString)
            .collect(Collectors.joining("\n"));
}
10
eddyrokr
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});
10

コトリン

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

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

コメントの最初のセットを巧妙に狙撃するのはとても面白かったです、しかしそれは本当にあなたがやろうとしていることによります。 あなたがまだ正しいライブラリを持っていなければ、(D. Wroblewskiの答えのように)3行のコードで完璧です。すでにApache.commonsライブラリを持っているなら、大部分のプロジェクトではそうなるでしょうが、Amarの答えはもっと短くなります。そうですね、ライブラリを入手して正しくインストールするのに10分かかることがあります(行っていることがわかっていれば1未満)。しかし、時計は刻々と過ぎているので、暇がないかもしれません。 JarekPrzygódzkiには興味深い警告がありました - 「入れ子にした例外が必要ない場合」。

しかし、もし私がdoに完全なスタックトレースを入れ子にして、全部必要としたらどうでしょうか。その場合、秘密は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

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

9
Tihamer

Apache Commons Lang 3.4 JavaDoc )からのコード:

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

他の答えとの違いは、autoFlushPrintWriterを使うことです。

9
IvanRF

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)
6
Gala

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

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

throwable.Javaによって提供されるgetStackTrace()関数のコードは、次のとおりです。

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

だから単に "\ n"でStackTraceElementに参加してください

5
Pengcheng Zhang

例外の原因も含まれる、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
ido flax

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

import Java.util.Arrays;

try{

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

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

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

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

3

もしあなたが外部ライブラリを使いたくなくて、あなたが を開発していないのであれば Android用 - /あなたは 'extension'メソッドを作成することができます

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
Kapé
 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)
2
Prakhar Nigam

昔の質問ですが、スタック全体を印刷したくない、という特別な場合を追加したいと思います。またはパッケージ。 

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の実装の詳細に依存することにも注意してください(変更される可能性は低いですが、それでもまだ)。

2
MarcG

Scalaのバージョン

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

私はしばらく前にこれのためにいくつかの方法を書きました、それで私はなぜこれに私の2セントを投げないかと考えました。

/** @param stackTraceElements The elements to convert
 * @return The resulting string */
public static final String stackTraceElementsToStr(StackTraceElement[] stackTraceElements) {
    return stackTraceElementsToStr(stackTraceElements, "\n");
}

/** @param stackTraceElements The elements to convert
 * @param lineSeparator The line separator to use
 * @return The resulting string */
public static final String stackTraceElementsToStr(StackTraceElement[] stackTraceElements, String lineSeparator) {
    return stackTraceElementsToStr(stackTraceElements, lineSeparator, "");
}

/** @param stackTraceElements The elements to convert
 * @param lineSeparator The line separator to use
 * @param padding The string to be used at the start of each line
 * @return The resulting string */
public static final String stackTraceElementsToStr(StackTraceElement[] stackTraceElements, String lineSeparator, String padding) {
    String str = "";
    if(stackTraceElements != null) {
        for(StackTraceElement stackTrace : stackTraceElements) {
            str += padding + (!stackTrace.toString().startsWith("Caused By") ? "\tat " : "") + stackTrace.toString() + lineSeparator;
        }
    }
    return str;
}

/** @param stackTraceElements The elements to convert
 * @return The resulting string */
public static final String stackTraceCausedByElementsOnlyToStr(StackTraceElement[] stackTraceElements) {
    return stackTraceCausedByElementsOnlyToStr(stackTraceElements, "\n");
}

/** @param stackTraceElements The elements to convert
 * @param lineSeparator The line separator to use
 * @return The resulting string */
public static final String stackTraceCausedByElementsOnlyToStr(StackTraceElement[] stackTraceElements, String lineSeparator) {
    return stackTraceCausedByElementsOnlyToStr(stackTraceElements, lineSeparator, "");
}

/** @param stackTraceElements The elements to convert
 * @param lineSeparator The line separator to use
 * @param padding The string to be used at the start of each line
 * @return The resulting string */
public static final String stackTraceCausedByElementsOnlyToStr(StackTraceElement[] stackTraceElements, String lineSeparator, String padding) {
    String str = "";
    if(stackTraceElements != null) {
        for(StackTraceElement stackTrace : stackTraceElements) {
            str += (!stackTrace.toString().startsWith("Caused By") ? "" : padding + stackTrace.toString() + lineSeparator);
        }
    }
    return str;
}

/** @param e The {@link Throwable} to convert
 * @return The resulting String */
public static final String throwableToStrNoStackTraces(Throwable e) {
    return throwableToStrNoStackTraces(e, "\n");
}

/** @param e The {@link Throwable} to convert
 * @param lineSeparator The line separator to use
 * @return The resulting String */
public static final String throwableToStrNoStackTraces(Throwable e, String lineSeparator) {
    return throwableToStrNoStackTraces(e, lineSeparator, "");
}

/** @param e The {@link Throwable} to convert
 * @param lineSeparator The line separator to use
 * @param padding The string to be used at the start of each line
 * @return The resulting String */
public static final String throwableToStrNoStackTraces(Throwable e, String lineSeparator, String padding) {
    if(e == null) {
        return "null";
    }
    String str = e.getClass().getName() + ": ";
    if((e.getMessage() != null) && !e.getMessage().isEmpty()) {
        str += e.getMessage() + lineSeparator;
    } else {
        str += lineSeparator;
    }
    str += padding + stackTraceCausedByElementsOnlyToStr(e.getStackTrace(), lineSeparator, padding);
    for(Throwable suppressed : e.getSuppressed()) {
        str += padding + throwableToStrNoStackTraces(suppressed, lineSeparator, padding + "\t");
    }
    Throwable cause = e.getCause();
    while(cause != null) {
        str += padding + "Caused by:" + lineSeparator + throwableToStrNoStackTraces(e.getCause(), lineSeparator, padding);
        cause = cause.getCause();
    }
    return str;
}

/** @param e The {@link Throwable} to convert
 * @return The resulting String */
public static final String throwableToStr(Throwable e) {
    return throwableToStr(e, "\n");
}

/** @param e The {@link Throwable} to convert
 * @param lineSeparator The line separator to use
 * @return The resulting String */
public static final String throwableToStr(Throwable e, String lineSeparator) {
    return throwableToStr(e, lineSeparator, "");
}

/** @param e The {@link Throwable} to convert
 * @param lineSeparator The line separator to use
 * @param padding The string to be used at the start of each line
 * @return The resulting String */
public static final String throwableToStr(Throwable e, String lineSeparator, String padding) {
    if(e == null) {
        return "null";
    }
    String str = padding + e.getClass().getName() + ": ";
    if((e.getMessage() != null) && !e.getMessage().isEmpty()) {
        str += e.getMessage() + lineSeparator;
    } else {
        str += lineSeparator;
    }
    str += padding + stackTraceElementsToStr(e.getStackTrace(), lineSeparator, padding);
    for(Throwable suppressed : e.getSuppressed()) {
        str += padding + "Suppressed: " + throwableToStr(suppressed, lineSeparator, padding + "\t");
    }
    Throwable cause = e.getCause();
    while(cause != null) {
        str += padding + "Caused by:" + lineSeparator + throwableToStr(e.getCause(), lineSeparator, padding);
        cause = cause.getCause();
    }
    return str;
}

例:

try(InputStream in = new FileInputStream(file)) {
    ...
} catch(IOException e) {
    String exceptionToString = throwableToStr(e);
    someLoggingUtility.println(exceptionToString);
    ...
}

プリント:

Java.io.FileNotFoundException: C:\test.txt (The system cannot find the file specified)
    at Java.io.FileInputStream.open0(Native Method)
    at Java.io.FileInputStream.open(Unknown Source)
    at Java.io.FileInputStream.<init>(Unknown Source)
    at com.gmail.br45entei.Example.main(Example.Java:32)
0
Brian_Entei

警告:これは少し話題が異なるかもしれませんが、まあまあ...;)

最初のポスター reason が最初にスタックトレースを文字列として欲しかったのかわかりません。スタックトレースが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
}

それは外部ライブラリを必要としないので(私はそれが好きです(もちろんあなたのロギングバックエンドを除いて、もちろんとにかくほとんどの場所にあるでしょう)).

0

いくつかの選択肢

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

  2. Google Guava lib String stackTrace = Throwables.getStackTraceAsString ( myException ) ; を使用する

  3. org.Apache.commons.lang.exception.ExceptionUtils.getStackTrace(Throwable)

0
Eric