L-01: java.util.logging 基本
Java 標準のロギング API である java.util.logging の使い方を解説します。 ログレベルの使い分け・ハンドラーの設定・例外のログ記録方法と、e.printStackTrace() を使ってはいけない理由を学びましょう。
いつ使うか
- バッチ処理の開始・終了・処理件数を記録するとき
- 例外が発生したときにスタックトレースをファイルに保存するとき
- 外部ライブラリを使えない組み込みシステムやシンプルなアプリケーションでログを出力するとき
- デバッグ時だけ詳細ログを出力し、本番では INFO 以上だけ出力するよう切り替えるとき
ログレベル一覧(重要度の高い順)
| レベル | 数値 | 用途 |
|---|---|---|
SEVERE | 1000 | システム障害・即時対応が必要なエラー |
WARNING | 900 | 想定外の状況だが処理は継続できる |
INFO | 800 | 正常な業務ログ(処理開始・終了など) |
FINE | 500 | デバッグ情報(通常は出力しない) |
FINER | 400 | より詳細なデバッグ情報 |
FINEST | 300 | 最も詳細なトレース情報 |
サンプルコード
java.util.logging はデフォルトで java.util.logging.config.file システムプロパティで設定ファイルを指定できます。コード内で直接設定する場合は、ルートロガーのデフォルトハンドラーを一度削除してから追加すると重複出力を防げます。
よくあるミス・注意点
⚠️ e.printStackTrace() は使用禁止
e.printStackTrace() には3つの問題があります。①標準エラー出力(System.err)にしか出力されないためログファイルに記録されない、 ②ログレベルを設定できないため重要度が分からない、③ログフォーマットが統一されず検索・集計がしにくい。 必ず logger.log(Level.SEVERE, "メッセージ", e) を使ってください。
⚠️ FINE/FINER/FINEST ログの文字列結合は isLoggable() で事前チェック
logger.fine("値: " + obj.heavyCalc()) のように書くと、FINE レベルが無効でもメソッドが呼ばれて文字列結合が実行されます。 ホットパスでは if (logger.isLoggable(Level.FINE)) で事前チェックしてください。
⚠️ ロガー名はクラス名にする
Logger.getLogger("myLogger") のように任意の文字列でもロガーは取得できますが、ベストプラクティスは Logger.getLogger(MyClass.class.getName()) です。クラス名をロガー名にすることで、ログ出力元が一目で分かり、クラス階層に合わせてログレベルを細かく設定できます。
⚠️ 実務では SLF4J + Logback/Log4j2 が一般的
java.util.logging は外部ライブラリが使えない環境向けです。Spring Boot 等の実務プロジェクトでは SLF4J をロギングファサードとして使い、 バックエンドに Logback や Log4j2 を採用するのが一般的です。 API を SLF4J に統一することで、ロギングライブラリを後から変更しても呼び出し元のコードを修正せずに済みます。
テストする観点
- 各ログレベルのメソッドを呼び出したとき、設定したレベル以上のみ出力されること
- 例外オブジェクトを渡した場合、スタックトレースがログレコードに含まれること
- ハンドラーを設定していない状態でもログ呼び出しで例外が発生しないこと(境界値)
isLoggable()が設定レベルより低いレベルには false を返すこと- ロガー名が正しく設定されていること(クラス名と一致すること)