ログレベルには TRACE 、DEBUG 、INFO 、WARN 、ERROR 、FATAL などがあります。
名前は知っていても、実際の開発では判断に迷います。
- リトライで回復した失敗は
WARNかERRORか - HTTP 404は必ず
WARNなのか - 一部のレコードだけ処理できなかったバッチは
ERRORなのか -
FATALがないライブラリでは何を使うのか
この記事では、バックエンドアプリケーションを主な対象として、ログレベルを事象の印象ではなく、処理結果と運用上の意味から選ぶ基準を整理します。
先に結論を書くと、ログレベルを決める前に、次の問いへ答える必要があります。
- 何を一つの処理単位とするか
- その処理単位は最終的に成功したか
- 自動復旧や機能縮退が発生したか
- プロセスまたはサービスインスタンスを継続できるか
- 運用者による対応が必要か
この記事は2026年7月14日時点の公式資料をもとにしています。
ログレベルに完全に統一された定義があるわけではありません。以下の対応表と判断基準は、各公式資料を比較したうえで、バックエンド運用向けに整理したものです。
ライブラリ横断の対応表
最初に、意味上の区分を基準として、代表的な体系を並べます。
ここでの比較対象は、厳密な利用率ランキングではありません。バックエンドで選択肢になりやすい標準API、共通仕様、ロギングfacadeを中心にしています。
| 体系 | 詳細な追跡 | デバッグ | 通常の重要イベント | 継続可能な異常 | 処理単位の失敗 | インスタンス継続不能 |
|---|---|---|---|---|---|---|
| OpenTelemetry | TRACE |
DEBUG |
INFO |
WARN |
ERROR |
FATAL |
| Syslog / journald | △ debug |
debug |
info / notice
|
warning |
err |
△ crit / alert / emerg
|
| SLF4J | trace |
debug |
info |
warn |
error |
- |
| Microsoft.Extensions.Logging | Trace |
Debug |
Information |
Warning |
Error |
Critical |
Python logging
|
△ DEBUG |
DEBUG |
INFO |
WARNING |
ERROR |
CRITICAL |
Rust tracing
|
TRACE |
DEBUG |
INFO |
WARN |
ERROR |
- |
Go log/slog
|
- |
DEBUG |
INFO |
WARN |
ERROR |
- |
| Pino | trace |
debug |
info |
warn |
error |
fatal |
- 無印: 意味上おおむね対応する
-
△: 近いレベルだが、粒度や公式の定義が異なる -
-: 直接対応する標準レベルがない
Go log/slog は数値による独自レベルを定義できますが、標準の TRACE はありません。対応表では、拡張可能かどうかではなく、各体系が標準で提供するレベルを比較しています。
同じ行や列にあるレベルが、完全に同義という意味ではありません。
特にSyslogの notice 、crit 、alert 、emerg は、一般的な5〜6段階のライブラリより細かく分かれています。異なる体系へ変換するときは、文字列の一致ではなく事象の意味を確認する必要があります。
OpenTelemetryは、異なるログ形式を共通のデータモデルへ写すため、TRACE から FATAL までをSeverity Numberの範囲として定義しています。この記事では、この6区分を比較の基準として利用します。1
一般的なログレベルの定義
TRACE
関数内部、反復処理、プロトコルの詳細など、処理を細かく追跡するための情報です。
- ループの各要素
- 詳細な状態遷移
- 外部ライブラリとの細かなやり取り
- 障害箇所を絞るための一時的な追跡情報
通常運用では情報量が多すぎるため、既定では無効にすることが一般的です。
DEBUG
開発や障害調査に必要な内部状態です。
- 選択された処理経路
- キャッシュのヒット・ミス
- リトライ回数
- 重要な変数や設定値のうち、機密情報でないもの
TRACEより粗く、問題の再現や原因調査に使える粒度を想定します。
INFO
アプリケーションが正常に動いていることを理解するための、意味のあるイベントです。
- アプリケーションの起動・停止
- ジョブの開始・完了
- 設定やリーダーの切り替え
- 業務上意味のある状態遷移
正常な処理をすべてINFOへ出すのではなく、後から運用状況を理解する価値があるイベントに絞ります。
WARN
通常とは異なることが起きたものの、対象の処理は継続または成功した状態です。
- リトライで回復した
- 代替の依存先へ切り替えた
- 一部機能を縮退して応答した
- 非推奨の設定を検出した
- 容量や期限が閾値へ近づいた
WARNを増やしすぎると、本当に見るべき兆候が埋もれます。運用者が状況を把握する価値があるか、増加を監視したいかを基準にします。
ERROR
定義した処理単位が失敗した状態です。
- 1リクエストを完了できなかった
- 1ジョブが最終的に失敗した
- 必須データを保存できなかった
- 回復できずメッセージをデッドレターへ送った
.NETの公式定義も、Errorを「現在の実行フローが失敗で停止した状態」であり、アプリケーション全体の失敗ではないと説明しています。
ERRORを出したからといって、プロセスまで終了する必要はありません。別のリクエストやジョブを継続できる場合があります。
FATAL相当
現在のプロセスまたはサービスインスタンスを継続できない状態です。
- 必須設定を読み込めず起動できない
- 必須リソースを初期化できない
- 内部状態が壊れ、安全に処理を継続できない
- 回復不能なクラッシュが発生した
OpenTelemetryはFATALをアプリケーションやシステムのクラッシュなどとして定義し、.NETはCriticalを回復不能なクラッシュや即時対応が必要な壊滅的障害として説明しています。
ただし、SLF4J、Rust tracing 、Go log/slog のように、FATAL専用レベルを持たない体系もあります。この違いは後で扱います。
まず成功・失敗の単位を決める
ERRORを「処理単位の失敗」と定義しても、処理単位が曖昧では判断できません。
| 処理 | 成功・失敗を考える単位の例 |
|---|---|
| Web API | 1リクエスト |
| バッチ | バッチ全体、1ファイル、1レコード |
| メッセージ処理 | 1メッセージ |
| 常駐ワーカー | 1ジョブ |
| アプリケーション起動 | 1インスタンスの起動 |
たとえば、バッチで1レコードを処理できなかった場合を考えます。
- 1件でも欠ければ成果物全体が無効になる: バッチ全体を
ERROR - 不正レコードを隔離し、残りを処理する仕様: 個別の異常を
WARN、最終結果を仕様に沿って記録 - 不正レコードの除外が通常の入力検証:
INFO以下、またはメトリクスだけで把握
同じ事象でも、システムが定義する成功条件によってレベルは変わります。
状況からログレベルを選ぶ
処理単位を決めたら、次の流れで考えられます。
ログへ記録する事象
│
├─ 想定された通常動作
│ │
│ ├─ 関数内部や反復処理の詳細
│ │ └─ TRACE
│ │
│ ├─ 障害調査に必要な内部状態
│ │ └─ DEBUG
│ │
│ └─ 運用上意味のある状態遷移
│ └─ INFO
│
└─ 通常動作から外れた事象
│
├─ 処理単位としては成功
│ │
│ ├─ 自動復旧・再試行・機能縮退あり
│ │ └─ WARN
│ │
│ └─ 想定内の分岐
│ └─ INFO以下、または記録しない
│
└─ 処理単位として失敗
│
├─ プロセス・インスタンスは継続可能
│ └─ ERROR
│
└─ プロセス・インスタンスを継続不能
└─ FATAL相当
※ 終了・再起動はログとは別に制御する
これは絶対的な規則ではありませんが、単に「重大そうだからERROR」と決めるより、チーム内で判断を揃えやすくなります。
出力・監視・通知を分けて考える
ログレベルは、出力するか、集計して監視するか、人間へ通知するかを判断する材料になります。ただし、レベルだけで通知を決める必要はありません。
| レベル | 本番での出力 | 監視 | 通知 |
|---|---|---|---|
| TRACE | 通常は無効。限定的な調査時に有効化 | 原則不要 | 不要 |
| DEBUG | 通常は無効または限定的に出力 | 障害調査時に利用 | 不要 |
| INFO | 意味のあるイベントを出力 | 件数や状態遷移を必要に応じて確認 | 原則不要 |
| WARN | 出力する | 件数・割合・増加傾向を監視 | 閾値超過や継続時に通知 |
| ERROR | 出力する | エラー率、連続失敗、影響範囲を監視 | SLOや処理特性に応じて通知 |
| FATAL相当 | 出力する | 再起動回数、ヘルスチェック、利用不能状態を監視 | 原則として即時通知を検討 |
ERRORが1件出たら必ず即時通知する設計では、想定された単発エラーで通知疲れが起きます。ログ件数だけでなく、エラー率、継続時間、影響する利用者数、再起動回数などと組み合わせます。
リトライ途中と最終的な失敗を分ける
外部APIへの接続が一度失敗し、リトライで成功した場合、最終的な処理結果は成功です。
| 状況 | レベルの目安 |
|---|---|
| 想定内の一時失敗で再試行する |
DEBUG 、運用上追う必要があれば WARN
|
| 再試行で回復した | 劣化として追うなら WARN 、通常範囲なら DEBUG
|
| 代替処理へ切り替えて要求は成功した | WARN |
| 最大試行回数まで失敗し、要求やジョブが失敗した | 最終境界で ERROR
|
| 必須依存先へ接続できず、起動できない |
FATAL 相当 |
サーキットブレーカー、フェイルオーバー、グレースフル・デグラデーションなどは、カスケード障害を抑えてシステムを継続するための手段です。採用した手段そのものではなく、その結果、対象の処理が成功したか、縮退したか、失敗したかからレベルを判断します。
ERRORを記録する責任境界
同じ例外を各層でERRORとして記録すると、一つの失敗から複数のERRORが生まれます。
HTTPクライアント: ERROR
↓ 例外を再送出
サービス層: ERROR
↓ 例外を再送出
APIハンドラー: ERROR
これでは、ログから作ったエラー件数と実際の失敗件数が一致しません。
原則として、次のように責任を分けると整理しやすくなります。
- 下位層は例外へ必要な文脈を加えて上位へ返す
- 回復する層は、回復処理を
DEBUGまたはWARNとして記録する - 最終的に処理の失敗を確定する境界で、一度だけ
ERRORを記録する - 同じ例外を再び記録するなら、別の受け手や追加情報など、記録する目的を明確にする
利用者への応答と運用上の記録を分ける
HTTPステータスとログレベルは、目的も受け手も異なります。
| 情報 | 主な受け手 | 目的 |
|---|---|---|
| HTTPステータス | API利用者 | 要求の結果と次の行動を伝える |
| 終了コード | シェル、ジョブ管理、親プロセス | プロセスの成否を伝える |
| 例外 | 呼び出し元コード | 失敗を伝播し、回復判断を委ねる |
| ログ | 開発者、運用者 | 発生事象の調査・監視に使う |
| メトリクス | 監視システム、運用者 | 件数、割合、傾向を把握する |
| トレース | 開発者、運用者 | 処理経路と遅延・失敗箇所を追う |
たとえば、404を返したという理由だけでWARNにする必要はありません。存在しない任意リソースの検索が想定された利用方法なら、DEBUG以下または記録不要と判断できます。
同様に、入力検証による400、認証失敗の401、正常に機能したレート制限の429も、ステータスコードだけでログレベルを決めるものではありません。
ログ・メトリクス・トレースの役割
Observabilityの各シグナルは、異なる問いに答えます。
| シグナル | 主な問い | 例 |
|---|---|---|
| ログ | 何が起きたか | 認証失敗、設定読込失敗、リトライ実行 |
| メトリクス | どれくらい起きているか | エラー率、レイテンシ、キュー長 |
| トレース | どこで時間がかかり、どこで失敗したか | APIからDBまでの呼び出し経路 |
同じ事象を複数のシグナルで表しても構いません。API処理が失敗した場合は、ログへ文脈を記録し、メトリクスで失敗件数を加算し、対象spanへエラー状態を記録できます。
ERRORログを集計してメトリクスを作ることはできますが、すべてのメトリクスをログ集計だけで代用すると、コスト、欠損、集計遅延の問題が出やすくなります。
割合や時間変化を継続的に監視したい値は、メトリクスとして直接計測することも検討します。
ログレベルは制御フローではない
FATALやCRITICALを出力しても、多くのロギングAPIは自動的にプロセスを終了しません。逆に、プロセスを終了する例外だからといって、必ずFATAL専用レベルを使う必要もありません。
次は、それぞれ別の設計です。
| 観点 | 決めること |
|---|---|
| ログレベル | 事象をどう観測・通知するか |
| 例外処理 | どの層で回復し、どこまで伝播するか |
| 終了コード | 呼び出し元へ成否をどう伝えるか |
| リトライ | 自動復旧するか |
| 再起動 | systemdやオーケストレーターへ復旧を任せるか |
ログを出しただけで処理を止めたつもりにならず、終了、再試行、縮退、再起動は制御フローとして実装します。
severityと出力閾値を混同しない
「ログレベル」という言葉は、事象のseverityと出力閾値の両方に使われます。
- severity: その事象をどの重大度で記録したか
- 出力閾値: どのseverity以上を出力・保存するか
- 無効化・未指定: ログを止める、または親設定を継承するか
たとえば、Pinoの silent 、.NETの None 、Log4jの OFF / ALL 、Pythonの NOTSET は、通常のログ事象へ付ける重大度とは役割が異なります。
systemdの LogLevel= はsystemdマネージャー自身の出力閾値です。Unitの LogLevelMax= も、対象Unitから生成されるログをフィルタリングする設定です。一方、journaldが記録するpriorityはSyslog由来の emerg から debug を使います。
**DEBUG出力を無効にしても、コード上のDEBUG事象がINFOへ変わるわけではありません。**単に、その環境では出力対象外になるだけです。
FATALを持たない体系をどう考えるか
SLF4J、Rust tracing 、Go log/slog は、標準レベルとしてFATALを持ちません。この場合、継続不能な事象をERRORとして記録し、終了や再起動を別に制御できます。
ただし、これを単に「ERRORを出して終了すればよい」で終わらせると、現代的なバックエンドの障害設計を十分に表せません。
公式資料から確認できること
- OpenTelemetryはFATAL帯を定義している
- .NETとPinoには、Critical / fatalという専用レベルがある
- SLF4J、Rust
tracing、Golog/slogの標準レベルにはFATALがない - systemdはプロセス終了を監視し、Unitの
Restart=設定に応じて再起動できる - ログ出力と、終了・再起動・縮退処理は別の仕組みである
ここからは考察
FATALを持たない理由を、すべてのライブラリに共通する設計意図として断定することはできません。
一方、バックエンドや分散システムでは、「致命的」が何に対して致命的なのかを分けて考える必要があります。
- 1リクエストに対して致命的
- 1プロセスに対して致命的
- 1サービスインスタンスに対して致命的
- システム全体に対して致命的
一つのインスタンスが継続不能でも、ロードバランサーが切り離し、systemdやオーケストレーターが再起動すれば、システム全体はサービスを継続できる可能性があります。
この観点では、障害の重大度をFATALという一語だけで表すより、次を別々に観測する設計にも合理性があります。
- ERRORとして記録された事象
- プロセスの終了コード
- 再起動回数
- ヘルスチェックの状態
- エラー率や利用不能時間
- フォールバックや縮退の発生
FATALがないことをフォールトトレラント設計の直接的な証拠とは言えませんが、インスタンスの失敗とシステム全体の継続可否を分離して考える契機にはなると思います。
アクセスログ・監査ログは用途を分ける
同じ保存基盤へ送られていても、ログの目的は同じとは限りません。
| 種類 | 主な目的 |
|---|---|
| アプリケーションログ | 処理状態や異常の調査 |
| アクセスログ | 要求、応答、レイテンシの記録 |
| 監査ログ | 誰がいつ何を変更したかの追跡 |
| セキュリティログ | 認証失敗、不正操作、ポリシー違反の検知 |
正常なHTTPリクエストをすべてINFOとしてアプリケーションログへ混ぜると、重要な状態遷移が埋もれる可能性があります。また、監査ログはINFO相当でも、改ざん防止やアクセス制御が重要です。
ログレベルだけで用途を表そうとせず、logger名、category、event type、保存先なども使い分けます。
セキュリティとプライバシー
ログレベルを下げても、機密情報を記録してよいことにはなりません。
次のような情報は、TRACEやDEBUGであっても安易に出力しないようにします。
- パスワード、APIキー、アクセストークン
- セッションIDやCookie
- 個人情報
- リクエストやレスポンスの全文
- 機密情報を含む設定値やSQLパラメーター
「本番ではDEBUGを無効にしているから安全」ではなく、設定変更や障害調査で有効化される可能性まで考えます。必要な属性だけを構造化して記録し、マスキングやredactionを適用します。
その他の代表的なロギングAPI・ライブラリ
本文の対応表は、比較軸を簡潔にするため対象を絞りました。次のAPIやライブラリも、現在または既存システムで利用されています。
| 対象 | レベル体系と位置づけ |
|---|---|
| Log4j 2 |
TRACE 、DEBUG 、INFO 、WARN 、ERROR 、FATAL 。 OFF / ALL はイベントのレベルではなく設定用 |
| log4net |
DEBUG 、INFO 、WARN 、ERROR 、FATAL など。既存.NETアプリケーションで見かけることがある |
Rust log
|
TRACE 、DEBUG 、INFO 、WARN 、ERROR 。軽量なロギングfacadeとして利用できる |
| Winston | 既定のnpm levelsは error 、warn 、info 、http 、verbose 、debug 、silly 。Pinoとは粒度が異なる |
| loglevel |
TRACE 、DEBUG 、INFO 、WARN 、ERROR 。 SILENT は出力抑止 |
Go log
|
一般的なログ出力を提供するが、log/slog のようなseverityや構造化属性の標準体系は持たない |
Log4j 2、Rust log 、Winstonなどは、単純に「古いから補足」へ置いたわけではありません。SLF4JとLog4j 2のようにfacadeと実装で役割が異なるものもあり、用途によって現在も選択肢になります。
まとめ
ログレベルは、メッセージの語気や例外名だけで決めるものではありません。
判断を揃えるには、次の順番で考えると整理しやすくなります。
- 成功・失敗を判定する処理単位を決める
- 最終的に成功したか確認する
- 自動復旧や機能縮退が発生したか確認する
- プロセスまたはインスタンスを継続できるか確認する
- 出力・監視・通知を別々に設計する
意味上の目安は次の通りです。
-
TRACE: 処理を細かく追跡する -
DEBUG: 開発・障害調査に必要な内部状態 -
INFO: 正常系のうち、運用上意味のあるイベント -
WARN: 異常は発生したが、処理は継続または成功した -
ERROR: 定義した処理単位が失敗した -
FATAL相当: プロセスまたはサービスインスタンスを継続できない
そして、ログレベルは制御フローではありません。終了、再試行、縮退、再起動は別に実装し、ログはその判断と結果を運用者が理解できる形で記録します。
参考
共通仕様
言語・ライブラリ
- SLF4J user manual
- Microsoft.Extensions.Logging.LogLevel
- Python logging --- Logging facility for Python
- Rust tracing::Level
- Go log/slog
- Pino API
systemd / journald
補足で扱ったライブラリ
- Log4j 2 Log Levels
- Apache log4net Manual - Configuration
- Rust log::Level
- Winston - Logging levels
- loglevel
- Go log
-
数値の大小関係は体系ごとに異なります。Syslogは
0のemergが最重大、OpenTelemetryは数値が大きいほど重大です。Python、Golog/slog、Pinoも大きい値ほど重大ですが、Log4j 2は小さいpriorityほど重大です。数値を直接比較せず、変換時は各公式マッピングを確認してください。 ↩