この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:3
ページ更新者:T
更新日時:2026-06-11 07:07:02

タイトル: 例外を文字列で出力する方法
SEOタイトル: 例外を文字列で出力する方法(PHP / Java / Python のスタックトレース文字列化)

この記事の要点
  • PHP / Java / Python で例外(Exception / Throwable)をログ用に文字列化する方法のまとめ
  • PHP: $e->getMessage() / $e->getTraceAsString() / (string)$e
  • Java: ExceptionUtils.getStackTrace(e) (commons-lang3) / Throwables.getStackTraceAsString(e) (Guava) / StringWriter + PrintWriter
  • Python: traceback.format_exc() / traceback.format_exception(type, value, tb)
  • ロガー使用時は例外オブジェクトを直接渡すのがベストプラクティス(logger.error("msg", e)

共通の考え方

例外を文字列化する目的は主に 3 つ:

  • ログファイルに残す: 後から原因調査するため
  • エラー通知に含める: Slack / メール / Sentry へ送信
  • API レスポンスで返す(開発時のみ): 本番では絶対にしない

どの言語でも、含めるべき情報は メッセージ + スタックトレース + 原因例外(cause chain)の 3 点セットです。

PHP の例外文字列化

getMessage();
    // → something broke

    // 2. 場所
    echo $e->getFile() . ':' . $e->getLine();
    // → /var/www/index.php:5

    // 3. スタックトレース(文字列)
    echo $e->getTraceAsString();
    /*
    #0 /var/www/index.php(10): foo()
    #1 {main}
    */

    // 4. すべて入りの最も標準的な形(__toString)
    echo (string) $e;
    /*
    RuntimeException: something broke in /var/www/index.php:5
    Stack trace:
    #0 /var/www/index.php(10): foo()
    #1 {main}
    */

    // 5. 配列のスタックトレース(要素ごとにアクセス可能)
    $trace = $e->getTrace();
    foreach ($trace as $i => $frame) {
        printf("#%d %s:%d %s%s%s()\n",
            $i,
            $frame['file'] ?? '?',
            $frame['line'] ?? 0,
            $frame['class'] ?? '',
            $frame['type'] ?? '',
            $frame['function']);
    }

    // 6. 原因例外チェーン
    $cur = $e;
    while ($cur) {
        error_log(get_class($cur) . ': ' . $cur->getMessage());
        $cur = $cur->getPrevious();
    }
}

Monolog でログ出力(PHP 標準)

pushHandler(new StreamHandler('/var/log/app.log', Logger::WARNING));

try {
    // ...
} catch (\Throwable $e) {
    // Monolog は exception を context に入れると自動展開
    $log->error('処理失敗', ['exception' => $e]);
}

// Laravel の場合
report($e);  // app/Exceptions/Handler.php の report() を呼ぶ
\Log::error('処理失敗', ['exception' => $e]);

Java の例外文字列化

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

try {
    throw new RuntimeException("something broke",
        new IllegalArgumentException("inner cause"));
} catch (Exception e) {

    // 1. メッセージのみ
    System.out.println(e.getMessage());
    // → something broke

    // 2. 例外クラス + メッセージ
    System.out.println(e.toString());
    // → java.lang.RuntimeException: something broke

    // 3. スタックトレースを標準エラーへ
    e.printStackTrace();

    // 4. スタックトレースを文字列で取得(標準 API)
    StringWriter sw = new StringWriter();
    e.printStackTrace(new PrintWriter(sw));
    String stack = sw.toString();
    System.out.println(stack);
    /*
    java.lang.RuntimeException: something broke
        at com.example.Foo.bar(Foo.java:10)
        at com.example.Main.main(Main.java:5)
    Caused by: java.lang.IllegalArgumentException: inner cause
        ...
    */

    // 5. スタックトレース要素を配列で
    for (StackTraceElement el : e.getStackTrace()) {
        System.out.printf("%s.%s(%s:%d)%n",
            el.getClassName(),
            el.getMethodName(),
            el.getFileName(),
            el.getLineNumber());
    }

    // 6. 原因例外チェーンを辿る
    Throwable cur = e;
    while (cur != null) {
        System.err.println(cur.getClass().getName() + ": " + cur.getMessage());
        cur = cur.getCause();
    }
}

commons-lang3 / Guava を使う場合(ワンライナー)

// Maven: org.apache.commons:commons-lang3
import org.apache.commons.lang3.exception.ExceptionUtils;

String stack = ExceptionUtils.getStackTrace(e);
String root  = ExceptionUtils.getRootCauseMessage(e);
Throwable[] chain = ExceptionUtils.getThrowables(e);

// Maven: com.google.guava:guava
import com.google.common.base.Throwables;

String stack2 = Throwables.getStackTraceAsString(e);
Throwable root2 = Throwables.getRootCause(e);

SLF4J / Logback でログ出力

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

private static final Logger log = LoggerFactory.getLogger(Foo.class);

try {
    // ...
} catch (Exception e) {
    // ★ 例外オブジェクトを最後の引数で渡すと自動展開される
    log.error("処理失敗 user={}", userId, e);
}

// Spring Boot は標準で SLF4J + Logback
// application.yml で出力フォーマット調整
// logging.pattern.console: '%d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n%ex'

Python の例外文字列化

import traceback
import sys
import logging

try:
    raise RuntimeError("something broke") from ValueError("inner cause")
except Exception as e:

    # 1. メッセージのみ
    print(str(e))
    # → something broke

    # 2. 型 + メッセージ
    print(repr(e))
    # → RuntimeError('something broke')

    # 3. スタックトレース文字列(最も汎用)
    stack = traceback.format_exc()
    print(stack)
    # Traceback (most recent call last):
    #   File "x.py", line 4, in 
    #     raise RuntimeError("something broke") from ValueError("inner cause")
    # RuntimeError: something broke

    # 4. 個別取得
    exc_type, exc_value, exc_tb = sys.exc_info()
    lines = traceback.format_exception(exc_type, exc_value, exc_tb)
    print(''.join(lines))

    # Python 3.10+ は例外オブジェクトだけで OK
    print(''.join(traceback.format_exception(e)))

    # 5. 標準エラー出力
    traceback.print_exc()

    # 6. 原因チェーン
    cur = e
    while cur:
        print(type(cur).__name__, str(cur))
        cur = cur.__cause__ or cur.__context__

logging モジュールで自動展開

import logging

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s %(levelname)s %(name)s - %(message)s',
)
logger = logging.getLogger(__name__)

try:
    # ...
    pass
except Exception:
    # ★ exc_info=True でスタックトレース自動付与
    logger.error("処理失敗", exc_info=True)

    # logger.exception は ERROR レベル + exc_info=True と同じ
    logger.exception("処理失敗")

言語横断の比較表

用途PHPJavaPython
メッセージのみ$e->getMessage()e.getMessage()str(e)
型 + メッセージget_class($e).': '.$e->getMessage()e.toString()repr(e)
スタックトレース文字列$e->getTraceAsString()ExceptionUtils.getStackTrace(e)traceback.format_exc()
全文出力(標準形)(string) $ee.printStackTrace()traceback.print_exc()
ログ自動展開Monolog の ['exception' => $e]SLF4J log.error(msg, e)logger.exception(msg)
原因チェーン$e->getPrevious()e.getCause()e.__cause__ / __context__

セキュリティと運用の注意

  • 本番でユーザーにスタックトレースを返さない。ファイルパス / DB クエリが漏れる
  • 例外メッセージにパスワードやトークンを含めない(マスク処理を入れる)
  • ログにはリクエスト ID / ユーザー IDを必ず付与(後追い可能に)
  • 大量例外を生む箇所は Sentry / Datadog で集約・重複排除
  • PII(個人情報)が含まれる例外はマスク or 別ログへ

FAQ

Q: PHP で「Stack trace #0 {main}」しか出ない
A: 例外が投げられた直後でキャッチした場合は浅いです。debug_backtrace() を併用するか、より深い場所で投げ直す(rethrow)してください。

Q: Java で printStackTrace() がログに混ざらない
A: printStackTrace() は標準エラーに直接書き出すのでロガーの整形を経由しません。必ず log.error("msg", e) を使ってください。

Q: Python の例外チェーンが見づらい
A: raise X from Y で意図的にチェーンを付けると The above exception was the direct cause of the following exception という綺麗な形式で出ます。