Java | 例外階層 × ロギング設計ベストプラクティス

Java Java
スポンサーリンク

では以下に、
「例外階層 × ロギング設計ベストプラクティス」
〜例外種別に応じたログレベル設計・運用テンプレート〜
を、実務教材スタイル(クラス構造+設計思想+コード表+運用方針表) でまとめます。


1. 全体像:例外階層 × ロギング方針の考え方

アプリ全体で例外とログを統一管理する目的は:

  • 異常の重要度を可視化(INFO / WARN / ERROR)
  • スタックトレースを必要なものだけ残す
  • 開発・運用・監視ツール(例:CloudWatch, ELK, Datadog)に正しい粒度で送信
  • チーム全員が統一ルールで例外・ログを扱える

基本設計思想:例外階層ツリー

AppException (業務共通例外 - abstract)
├── BusinessException        // 業務ロジック上の異常(想定内)
│    ├── ValidationException // 入力・チェック系
│    └── DomainException     // 業務ルール違反
│
└── SystemException          // システム的異常(想定外)
     ├── InfrastructureException // DB/外部API/ネットワーク
     └── FatalException           // 致命的(プログラミングバグ等)

2. ログレベル設計マッピング表

例外クラス発生原因の性質ログレベルログ出力方針
ValidationException想定内(ユーザー入力ミス)INFOUIで通知、スタックトレース不要
BusinessException想定内(業務ルール違反)WARN原因を業務ログに出力(例:注文在庫なし)
SystemException想定外(システム異常)ERRORスタックトレース+アラート通知
InfrastructureException想定外(外部依存失敗)ERROR再試行・フォールバック設計も検討
FatalException致命的バグ・NullPointerなどFATAL即時停止、通知システム連携(例:Slack, PagerDuty)

3. コード構造テンプレート(実務標準)

Exception階層構造(Java実装例)

// 抽象基底クラス(全例外の親)
public abstract class AppException extends RuntimeException {
    private final String errorCode;

    public AppException(String message, String errorCode) {
        super(message);
        this.errorCode = errorCode;
    }

    public String getErrorCode() { return errorCode; }
}
Java
// 想定内の業務例外
public class BusinessException extends AppException {
    public BusinessException(String message, String errorCode) {
        super(message, errorCode);
    }
}

// 想定外のシステム例外
public class SystemException extends AppException {
    public SystemException(String message, String errorCode, Throwable cause) {
        super(message, errorCode);
        initCause(cause);
    }
}
Java

4. ロギング設計テンプレート(SLF4J)

業務層での例外ハンドリング例

@Service
public class OrderService {

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

    public void placeOrder(OrderRequest request) {
        try {
            validate(request);
            executeOrder(request);
        } catch (ValidationException e) {
            log.info("入力エラー: {}", e.getMessage());
            throw e; // 想定内 → ログは INFO
        } catch (BusinessException e) {
            log.warn("業務エラー: {}", e.getMessage());
            throw e; // WARN
        } catch (SystemException e) {
            log.error("システムエラー: {}", e.getMessage(), e);
            throw e; // ERROR
        } catch (Exception e) {
            log.error("致命的エラー: {}", e.getMessage(), e);
            throw new FatalException("致命的エラー発生", "E9999", e);
        }
    }
}
Java

5. 運用テンプレート(アプリ共通)

障害レベルログ出力通知先対応例
INFOローカル/アクセスログのみユーザー操作ログ
WARNファイル+監視システム担当チーム(翌営業日)想定内異常
ERROR監視システム+Slack/PagerDuty当日対応システム異常
FATAL監視+緊急通知全開発者サービス停止級異常

6. 実務Tips:例外×ロギングの落とし穴

アンチパターン問題点修正指針
catch(Exception e){} で無視原因を握りつぶす最低限ログ出力する
想定内の異常を ERROR で出力アラート過多・誤検知業務異常は WARN まで
同じ例外を複数階層でログ出力二重ログ・冗長最上位層でのみログ
全例外を System.out.println運用で解析不可ロガー統一 (SLF4J/Logback)

7. まとめ:例外階層 × ロギング早見表

例外種別       ─┬─> ログレベル   ─┬─> 通知優先度
Validation      │     INFO         │ 低
Business        │     WARN         │ 中
System          │     ERROR        │ 高
Infrastructure  │     ERROR        │ 高
Fatal           │     FATAL        │ 緊急

Java
スポンサーリンク
シェアする
@lifehackerをフォローする
スポンサーリンク
タイトルとURLをコピーしました