C# Tips | ログ・例外・診断:ログレベル制御

C# C#
スポンサーリンク

はじめに:「ログレベル制御」は“どの声量でしゃべるか”を決める仕組み

ログは「全部出せばいい」わけではありません。
本番では重要なものだけ見たいし、調査中は細かい情報も欲しい。
この「どこまで細かくログを出すか」を切り替えるのが ログレベル制御 です。

同じコードでも、設定を変えるだけで

本番では Error と Warning だけ
検証環境では Information まで
ローカル開発では Debug や Trace まで

といった切り替えができます。

ここでは、初心者向けに

ログレベルの意味
ILogger とログレベルの関係
appsettings.json でのログレベル制御
「どのレベルで書くか」の実務的な判断基準

を、例を交えながらかみ砕いて説明します。


ログレベルとは何か

「どれくらい重要な出来事か」を段階で表す

代表的なログレベルは次のようなものです。

Trace
Debug
Information
Warning
Error
Critical

下に行くほど「重大」です。
ざっくりしたイメージはこうです。

Trace
 超詳細。ループの中の値など、通常は出さないレベル。
Debug
 開発・調査用の情報。ローカルや検証環境で有効にすることが多い。
Information
 正常系の重要な出来事。処理開始・終了、状態変化など。
Warning
 今は動いているが、将来問題になりそうな状態。想定内のエラーなど。
Error
 処理が失敗した。ユーザーにエラーを返した。
Critical
 システム全体に影響する致命的なエラー。プロセスが落ちるなど。

ここでの重要ポイントは、「レベルが高いほど“本番で必ず見たいログ”になる」ということです。
逆に Trace や Debug は「必要なときだけオンにする」イメージです。


ILogger とログレベル

LogInformation / LogError などは「レベル付きのログ出力」

ILogger には、レベルごとにメソッドが用意されています。

_logger.LogTrace("トレースログ");
_logger.LogDebug("デバッグログ");
_logger.LogInformation("情報ログ");
_logger.LogWarning("警告ログ");
_logger.LogError("エラーログ");
_logger.LogCritical("致命的エラーログ");
C#

これらは内部的には同じ仕組みで、
「どのレベルで出すか」だけが違います。

また、共通の Log メソッドにレベルを渡すこともできます。

_logger.Log(LogLevel.Information, "情報ログ");
C#

ここでの重要ポイントは、「コード側では“適切なレベルで書く”ことに集中し、どこまで出すかは設定で切り替える」ということです。
レベル制御は基本的に「設定ファイルの仕事」です。


appsettings.json でのログレベル制御

最低レベルを設定で決める

ASP.NET Core などでは、appsettings.json でログレベルを制御できます。

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  }
}

ここでのポイントは次の通りです。

Default が “Information”
 → Information 以上(Information, Warning, Error, Critical)が出力される。
 → Debug や Trace は無視される。

Microsoft が “Warning”
 → フレームワーク内部のログは Warning 以上だけ出る。

つまり、「どのカテゴリ(名前空間)のログを、どのレベルから出すか」を設定で決められます。

例えば、開発用の appsettings.Development.json ではこうできます。

{
  "Logging": {
    "LogLevel": {
      "Default": "Debug"
    }
  }
}

これで、開発環境では Debug 以上が出るようになります。

ここでの重要ポイントは、「同じコードでも、環境ごとに“どのレベルから出すか”を変えられる」ということです。
本番は Information 以上、開発は Debug 以上、などの切り替えが簡単にできます。


実務での「どのレベルで書くか」の判断基準

Error と Warning は「運用で監視する対象」

Error
 処理が失敗した。ユーザーにエラーを返した。
 → アラートの対象になりやすい。

Warning
 今は動いているが、異常な状態。
 例:リトライで復旧した、想定外の入力だが処理は続行した。

これらは「運用で見るログ」です。
本番環境では最低でも Warning 以上は出すことが多いです。

例えば、外部 API 呼び出しの例。

try
{
    await _externalApi.CallAsync();
}
catch (TimeoutException ex)
{
    _logger.LogWarning(ex, "外部APIタイムアウト。リトライします。");
    // リトライ処理
}
catch (Exception ex)
{
    _logger.LogError(ex, "外部API呼び出しに失敗しました。");
    throw;
}
C#

タイムアウトしてもリトライで復旧した場合は Warning。
どうにもならずに失敗した場合は Error。
というように、「ユーザー影響の大きさ」でレベルを分けます。

ここでの重要ポイントは、「Error は“何か対処が必要な状態”、Warning は“注意して見ておきたい状態”」という感覚を持つことです。

Information は「正常系の重要な出来事」

Information は、「正常に動いている中で、後から見返したいイベント」です。

処理開始・終了
重要な状態変化(ステータス変更など)
外部システムとの連携成功

例えば、バッチ処理。

_logger.LogInformation("バッチ開始 Job={JobName}", jobName);

// 処理

_logger.LogInformation("バッチ終了 Job={JobName}, Count={Count}", jobName, count);
C#

これで、「いつどのジョブが何件処理したか」を後から追えます。

ここでの重要ポイントは、「Information は“運用レポート的に見たい情報”を中心に書く」ことです。
全部を Information にするとノイズが増えるので、「後から本当に見たいか?」を意識します。

Debug / Trace は「調査用の虫眼鏡」

Debug
 開発中や不具合調査中に見たい情報。
Trace
 さらに細かいレベル。ループの中の値など。

これらは通常、本番では出しません。
必要なときだけ、設定でレベルを下げて有効にします。

_logger.LogDebug("入力値チェック開始 Input={@Input}", input);
C#

{@Input} のように書くと、オブジェクトの中身を展開してくれます。
ただし、出しすぎるとログ量が爆発するので、レベル制御とセットで使います。

ここでの重要ポイントは、「Debug / Trace は“いつでも出ていると困るが、欲しいときに出せると助かる”ログ」という位置づけです。


コード側で「今のレベル」を意識する

IsEnabled で「無駄な計算」を避ける

ログメッセージを組み立てるのに重い処理が必要な場合、
現在のログレベルを見て「そもそも出さないなら計算しない」という工夫もできます。

if (_logger.IsEnabled(LogLevel.Debug))
{
    var detail = BuildHeavyDebugInfo(); // 重い処理
    _logger.LogDebug("詳細情報: {Detail}", detail);
}
C#

Information 以上しか出さない設定なら、
この if の中は一切実行されません。

ここでの重要ポイントは、「“重いログ”は IsEnabled でガードする」ということです。
ただし、普通の文字列埋め込み程度なら、テンプレートログは内部で最適化されるので、そこまで気にしなくて大丈夫です。


実務でのログレベル制御ユーティリティ

「環境ごとのポリシー」を決めておく

プロジェクトとして、ざっくりこう決めておくと迷いにくくなります。

本番
 Default: Information
 アプリケーションコードは Information 以上
 フレームワーク系は Warning 以上

開発
 Default: Debug
 必要に応じて一時的に Trace まで下げる

さらに、「このカテゴリはうるさいからレベルを上げる」こともできます。

"Logging": {
  "LogLevel": {
    "Default": "Information",
    "MyApp.Data": "Warning"
  }
}
C#

これで、MyApp.Data 名前空間以下のログは Warning 以上だけ出るようになります。

ここでの重要ポイントは、「“どのレベルから出すか”はコードではなく設定で変える、という前提で設計する」ことです。
コード側は「適切なレベルで書く」ことに集中します。


まとめ:「ログレベル制御」は“ノイズを減らし、必要なときにだけ細かく見る”ためのスイッチ

ログレベル制御の本質は、

ログを全部出すのではなく、
環境や状況に応じて
「どこまで細かく見るか」を切り替える

ことです。

押さえておきたいポイントは次の通りです。

ログレベルは「重要度の段階」。Error や Critical は本番で最優先で見る対象。
コード側では LogInformation / LogWarning / LogError など、適切なレベルで書くことに集中する。
どのレベルから出すかは appsettings.json などの設定で制御する。
Debug / Trace は調査用。普段は切っておき、必要なときだけレベルを下げる。
重いログは IsEnabled でガードして、不要な計算を避ける。

ここまで腹落ちしていれば、
「とりあえず全部 LogInformation」から卒業して、
“運用と調査の両方で使えるログ設計”を意識して書けるようになります。

タイトルとURLをコピーしました