21.

log4j で printStackTrace の内容をログ出力する方法(スタックトレース完全保存)

編集
この記事の要点
  • logger.error("メッセージ", e)第 2 引数に例外オブジェクトを渡すと、Log4j が自動でスタックトレース全体をログ出力する
  • e.printStackTrace()標準エラー (System.err) に出力されるだけで、Log4j の Appender には流れない
  • 文字列として取得したい場合は ExceptionUtils.getStackTrace(e) (commons-lang3) または StringWriter + PrintWriter
  • Log4j 2 では JsonLayout / PatternLayout の %ex でスタックトレースを構造化出力できる
  • Spring Boot (logback) でも logger.error(msg, e)API は同一。引数の渡し方を統一しておくと移行が楽

結論: 例外は logger の第 2 引数で渡す

結論から書くと、例外オブジェクトを Logger の第 2 引数に渡すだけで、Log4j が自動的に printStackTrace() 相当のスタックトレースをログに書き出します。

import org.apache.log4j.Logger;

public class UserService {
    private static final Logger logger = Logger.getLogger(UserService.class);

    public void register(User u) {
        try {
            repository.save(u);
        } catch (Exception e) {
            // ★ これだけで OK。第 2 引数に例外を渡す
            logger.error("ユーザー登録に失敗しました userId=" + u.getId(), e);
            throw e;
        }
    }
}

出力例:

2026-05-17 10:23:45 ERROR UserService - ユーザー登録に失敗しました userId=123
java.sql.SQLIntegrityConstraintViolationException: Duplicate entry '123' for key 'PRIMARY'
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:109)
    at com.example.UserRepository.save(UserRepository.java:42)
    at com.example.UserService.register(UserService.java:18)
    ... 35 more

なぜ printStackTrace() ではダメなのか

e.printStackTrace() はデバッグ用の便利メソッドですが、本番運用では致命的な欠陥があります:

項目e.printStackTrace()logger.error(msg, e)
出力先標準エラー (System.err) 固定log4j.properties で定義した Appender
ログレベル制御不能ERROR / WARN / INFO を選択可
タイムスタンプなし自動付与
クラス名・スレッド名なし%c / %t で出力可
ファイル分割・ローテート不可RollingFileAppender 等で可
本番サーバーでの追跡catalina.out に埋もれる専用ログファイルに集約

とくに Tomcat や WebLogic などのアプリサーバでは、System.err は catalina.outstderr.log に流れますが、業務ログと分離されておらず原因追跡が困難になります。

NG パターン: 例外を toString() してしまう

よくある間違いが次のコードです:

// ❌ ダメな書き方
logger.error("エラー: " + e);              // toString() しか出ない
logger.error("エラー: " + e.getMessage()); // メッセージだけ、スタックトレースなし
logger.error(e.toString());                // 同上

// ❌ さらにダメ
try {
    ...
} catch (Exception e) {
    e.printStackTrace();   // 標準エラーに出るだけで Log4j に流れない
}

上記のコードは例外発生箇所が特定できず、運用フェーズで詰む典型例です。必ず第 2 引数で例外を渡してください。

スタックトレースを文字列で取得したい場合

「DB のエラー履歴テーブルに保存したい」「メール本文に含めたい」など、文字列としてスタックトレースを取り出したい場合は次の方法を使います。

方法 1: Apache Commons Lang3

import org.apache.commons.lang3.exception.ExceptionUtils;

try {
    ...
} catch (Exception e) {
    String trace = ExceptionUtils.getStackTrace(e);
    logger.error("エラー詳細:\n" + trace);

    // DB に保存
    errorLogRepository.save(new ErrorLog(e.getMessage(), trace));
}

Maven 依存:


    org.apache.commons
    commons-lang3
    3.14.0

方法 2: 標準ライブラリの StringWriter

commons-lang3 を入れたくない場合は標準 API でも可能:

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

public static String getStackTrace(Throwable t) {
    StringWriter sw = new StringWriter();
    PrintWriter pw = new PrintWriter(sw);
    t.printStackTrace(pw);   // ★ PrintWriter を渡せば文字列化される
    return sw.toString();
}

// 使い方
catch (Exception e) {
    String trace = getStackTrace(e);
    logger.error("エラー:\n" + trace);
}

Log4j の設定例 (log4j.properties)

スタックトレースを綺麗に出すための定番設定:

# ルートロガー: INFO 以上をファイルとコンソールへ
log4j.rootLogger=INFO, FILE, CONSOLE

# コンソール
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c{1} - %m%n

# ファイル (日次ローテート)
log4j.appender.FILE=org.apache.log4j.DailyRollingFileAppender
log4j.appender.FILE.File=/var/log/app/application.log
log4j.appender.FILE.DatePattern='.'yyyy-MM-dd
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c - %m%n

%m%n%m がメッセージで、第 2 引数で渡した例外のスタックトレースも自動的に %m の後ろに付加されます。

Log4j 1.x はサポート終了。Log4j 2 / SLF4J への移行

Log4j 1.x は 2015 年 8 月にサポート終了しています。新規開発では Log4j 2 または SLF4J + Logback を推奨。

// Log4j 2 (パッケージは org.apache.logging.log4j)
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

private static final Logger logger = LogManager.getLogger(UserService.class);
logger.error("失敗 userId={}", userId, e);  // ★ プレースホルダ + 末尾に例外

// SLF4J + Logback (Spring Boot 標準)
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

private static final Logger logger = LoggerFactory.getLogger(UserService.class);
logger.error("失敗 userId={}", userId, e);  // ★ 末尾の Throwable は自動でスタックトレース化

SLF4J / Log4j 2 では {} プレースホルダの最後の引数が Throwable なら自動的にスタックトレース出力される仕組みになっています。文字列連結 + より高速かつ安全です。

Log4j 2 で JSON 構造化ログ

ELK / Datadog / CloudWatch Logs で扱いやすい JSON 出力:



    
        
            
        
    
    
        
            
        
    

出力例 (1 行 = 1 JSON):

{"timestamp":"2026-05-17T10:23:45.123Z","level":"ERROR","logger":"UserService","message":"失敗 userId=123","thrown":{"name":"SQLIntegrityConstraintViolationException","message":"Duplicate entry","extendedStackTrace":"..."}}

FAQ

Q: catch せず throws する場合は?
A: 上位の Filter / ControllerAdvice / try-catch 側で logger.error(msg, e) すれば OK。低レベルで catch して再 throw する場合、catch のたびにログを出すと重複するので注意。

Q: スタックトレースが「... 35 more」で省略される
A: Java の仕様で、同じフレームは省略表示されます。%ex{full} や Throwable#getStackTrace() で完全取得可能。実運用ではデフォルトの省略で問題ないことが多い。

Q: 個人情報が含まれる例外メッセージをマスクしたい
A: Log4j 2 の RegexFilter や独自 Layout で正規表現マスクを実装。パスワードを例外メッセージに入れないのが原則。

Q: log4j-over-slf4j を使っているプロジェクトは?
A: コード上は org.apache.log4j.Logger のまま動きますが、実体は SLF4J 経由で Logback に流れます。API は同じなので同じ書き方で OK

関連項目

  • Log4Shell (CVE-2021-44228) — Log4j 2.0〜2.14.1 の RCE 脆弱性。Log4j 2.17.1+ への更新必須
  • SLF4J — Java ロギングのファサード。実装を切り替え可能
  • Logback — SLF4J 純正実装。Spring Boot 標準
  • Sentry / Rollbar — 例外を外部サービスに自動収集する選択肢
編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. プラットホーム
  2. 環境構築
  3. 文法
  4. API
  5. Servlet(サーブレット)
  6. JSP
  7. Applet(アプレット)
  8. デザインパターン
  9. フレームワーク
  10. ライブラリ
  11. Androidアプリケーション
  12. Project Jigsaw
  13. エラー一覧
  14. 日付の加算、減算
  15. 文字列の数字チェック
  16. 改行コードの削除
  17. 先頭と末端の文字の削除
  18. warファイルの中身を確認する方法
  19. nullもしくは空文字の判定
  20. beanの中身を確認する方法
  21. org.apache.log4j.Logger のログ出力で printStackTrace() のエラー内容を出力する方法
  22. Javaのバージョン確認方法