迷わない!Javaログ設計|どこで記録して、どこで通知する?

こんにちは、さるまりんです 🐒🔧

Javaで開発をしていると、例外処理は避けて通れません。

前回は「try-catchは設計の話」というテーマで、
どこで例外を扱うべきかを整理しました。

では、その次に考えるべきことは何でしょうか?

それは、

「何が起きたのかを、あとから分かるようにすること」

です。

そのために必要なのが、ログ設計です。

ログは未来の自分へのメッセージ

ログはただ出せばいいものではありません。
本当によく思います。

  • エラーが起きたことを知る
  • 何が原因かを追える
  • 他の人でも調査できる

つまりログは、

未来の自分やチームへのメッセージ

です。

よくある落とし穴

最初はここから始まります。
こんなコード、見たことありませんか?

try {
    service.execute();
} catch (Exception e) {
    e.printStackTrace();
}

これでもエラーは出力されますが、

  • ログとして管理されない
  • 検索できない
  • 環境によっては消える

という問題があります。

さらに、

catch (Exception e) {
    logger.error("エラー発生");
}

これもよくあるのですが、

👉 情報が足りません

「なんのエラーよ?」ってなります。

ログに残すべき情報

最低限、次の情報は残しておきたいです。

  • 何が起きたか(メッセージ)
  • どの処理か
  • 入力情報(必要な範囲で)
  • 例外そのもの(stack trace)
try {
    service.execute(request);
} catch (Exception e) {
    logger.error("会員連携処理で例外が発生しました。requestId={}", requestId, e);
    throw e;
}

👉 ポイントは 例外オブジェクトをそのまま渡すこと

これでstack traceも含めて記録されます。

ログレベルの考え方

ログにはレベルがあります。

  • INFO:通常の処理
  • WARN:想定内だが注意が必要
  • ERROR:明確な問題

Loggingライブラリやツールによっては、

  • FATAL(致命的な問題)
  • TRACE(詳細な追跡用)

などもあります。

重要なのは、

👉 全部ERRORにしないこと

ERRORが多すぎると、本当に重要な問題が埋もれます。

どこでログを出すべきか?

ここは設計と深く関係する部分です。

基本は:

👉 例外を処理する場所でログを出す

  • 途中でcatchして握りつぶさない
  • 最終的にユーザーに返す直前で記録する

前回の記事ともつながるポイントです。

通知はログの代わりではない

ログを整えたうえで、必要なら通知を行います。
記録するだけでなく、「気づける」ことも大切ですよね。

ここで重要なのは:

👉 すべての例外を通知しないこと

です。

通知は、

  • サービス停止レベル
  • 重要な業務エラー

などに限定します。

やたらめったら通知していると、それ自体がうるさくなり、
本当に大切な通知を見逃してしまうこともあります。

JavaからSlackに障害通知する

以前、PHPでSlackに通知する方法を書きました。

同じように、JavaでもWebhookを使って通知できます。

ただし、

👉 通知は「短く」「分かりやすく」

が大切です。

サンプルコード

try {
    service.execute(request);
} catch (Exception e) {
    logger.error("会員連携処理で例外が発生しました。requestId={}", requestId, e);

    slackNotifier.notifyError(
        "会員連携処理で障害が発生しました",
        requestId,
        e
    );

    throw e;
}

通知メソッド

public void notifyError(String title, String requestId, Exception e) {
    String text = """
            %s
            requestId: %s
            exception: %s
            message: %s
            """.formatted(
            title,
            requestId,
            e.getClass().getName(),
            e.getMessage()
    );

    send(text);
}

stack traceはそのまま貼らない

stack traceをそのまま通知に載せると、

  • 長すぎる
  • 読みにくい
  • 本質が見えない

という問題があります。

そこでおすすめなのが、

👉 自分のコード部分だけを抜き出す

private String extractApplicationStackTrace(Throwable e, String packagePrefix) {
    return Arrays.stream(e.getStackTrace())
            .filter(element -> element.getClassName().startsWith(packagePrefix))
            .limit(5)
            .map(StackTraceElement::toString)
            .collect(Collectors.joining("\n"));
}

長いstack traceの中でも、
自分たちのコードに集中できると、原因特定がぐっと楽になります。

まとめ

ログは、

  • 出すためのものではなく
  • あとから分かるためのもの

です。

そして、

  • ログで記録する
  • 必要なものだけ通知する

このバランスがとても大切です。

例外処理の次に考えるべきは、
「どう残すか」。

開発の段階でここを意識しておくだけで、
運用の負担はぐっと軽くなります。

安全に、安心して、開発も運用も楽しむために。
少しずつ整えていきたいですね。

読んでくださってありがとうございました。
それではまた!