はじめに:「ファイルログ」は“あとから読み返せるブラックボックスレコーダー”
コンソールにログを出すだけだと、アプリを閉じた瞬間に全部消えます。
でも業務システムでは、数日後・数週間後に「そのとき何が起きていたか」を知りたいことが普通にあります。
そこで出てくるのが ファイルログ です。
ログをファイルに書き出しておけば、
夜中に動いていたバッチの様子
ユーザーから問い合わせがあった時間帯の動き
たまにしか起きないエラーの前後の状況
を、後からじっくり読み返せます。
ここでは、初心者向けに
ファイルログの基本イメージ
.NET でのシンプルなファイルログのやり方
ローテーション(ファイルを分割する)という考え方
実務で意識したい「書きすぎない・消しすぎない」のバランス
を、例題付きでかみ砕いて説明していきます。
ファイルログの基本イメージ
「1 行 1 イベント」のテキストファイル
一番シンプルなファイルログは、こんなテキストファイルです。
2026-04-17 10:00:01 [Information] アプリ起動
2026-04-17 10:00:05 [Information] ログイン成功 UserId=123
2026-04-17 10:01:10 [Error] 受注登録に失敗 OrderId=456 System.Exception: ...
ポイントは、
日時
レベル(Information / Error など)
メッセージ
必要なら追加情報(ユーザーID、注文IDなど)
が、1 行にまとまっていることです。
この「1 行 1 イベント」の形にしておくと、
後から検索したり、ツールで集計したりしやすくなります。
まずは「自前で書く」超シンプルなファイルログ
File.AppendAllText を使った最低限の実装
学習用として、まずは「自分でファイルに書く」パターンを見てみます。
using System;
using System.IO;
public static class SimpleFileLogger
{
private static readonly object _lock = new();
public static void Log(string level, string message)
{
var line = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} [{level}] {message}{Environment.NewLine}";
var path = "app.log";
lock (_lock)
{
File.AppendAllText(path, line);
}
}
public static void Info(string message) => Log("Information", message);
public static void Error(string message) => Log("Error", message);
}
C#使い方はこうです。
SimpleFileLogger.Info("アプリ起動");
SimpleFileLogger.Error("何かエラーが起きました");
C#ここでの重要ポイントは、「複数スレッドから同時に書かれても壊れないように lock をかけている」ことです。
業務アプリでは並列処理も普通にあるので、「ファイルに書くときの排他」は必須です。
ただし、この実装はあくまで「学習用」です。
実務では、フレームワークやライブラリのロガー(ILogger など)と連携させるのが基本になります。
ASP.NET Core でのファイルログ(拡張ライブラリ利用)
ILogger をそのまま使ってファイルに出す
ASP.NET Core の標準には「ファイルログ」が直接は入っていませんが、ILogger の仕組みを使って、ファイルに書き出すプロバイダを追加するのが一般的です。
代表的なのは Serilog や NLog などですが、ここではイメージだけ押さえます。
例えば Serilog を使う場合、Program.cs でこういう設定をします。
using Serilog;
var builder = WebApplication.CreateBuilder(args);
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.WriteTo.File(
path: "logs/app-.log",
rollingInterval: RollingInterval.Day,
retainedFileCountLimit: 7)
.CreateLogger();
builder.Host.UseSerilog();
var app = builder.Build();
C#これで、アプリ内の ILogger<T> から出したログが、logs/app-20260417.log のようなファイルに日ごとに出力されるようになります。
ここでの重要ポイントは、「アプリのコード側は ILogger を意識するだけで、“どこにどう出すか”は設定で差し替えられる」ことです。
コンソールだけに出すか、ファイルにも出すか、クラウドのログサービスにも送るか、などを後から変えられます。
ローテーション(ファイルを分割する)という考え方
1 ファイルに永遠に書き続けるのは危険
先ほどの自前実装だと、app.log 1 ファイルに延々と書き続けます。
これは学習用としてはいいのですが、実務では問題が出ます。
ファイルサイズがどんどん大きくなる
バックアップや転送が重くなる
古いログを消したいのに、1 ファイルに混ざっている
そこで出てくるのが ログローテーション です。
ざっくり言うと、
日ごとにファイルを分ける
サイズが一定を超えたら新しいファイルに切り替える
古いファイルは一定期間で削除する
といった運用です。
Serilog の例でいうと、先ほどの設定のここです。
.WriteTo.File(
path: "logs/app-.log",
rollingInterval: RollingInterval.Day,
retainedFileCountLimit: 7)
C#RollingInterval.Day
→ 日ごとにファイルを分ける(app-20260417.log など)retainedFileCountLimit: 7
→ 7 個より古いファイルは自動で削除する
ここでの重要ポイントは、「ファイルログは“分割する前提”で設計する」ことです。
「1 個の app.log に全部入れる」は、実務ではほぼ通用しません。
ログの中身をどう設計するか
日時・レベル・メッセージ・コンテキスト
ファイルログの 1 行には、最低限これを入れておくと実務で戦えます。
日時
ログレベル
メッセージ
コンテキスト情報(ユーザーID、リクエストIDなど)
ILogger のメッセージテンプレートを使うと、自然にこれができます。
_logger.LogInformation(
"受注登録開始 OrderId={OrderId}, UserId={UserId}",
orderId, userId);
C#ファイルに出ると、例えばこんな感じになります。
2026-04-17 11:00:01 [Information] 受注登録開始 OrderId=123, UserId=U001
ここでの重要ポイントは、「“後から検索したい情報”には必ず名前をつけてログに埋め込む」ことです。
OrderId や UserId を入れておくと、「この注文だけ」「このユーザーだけ」を追いかけられます。
実務でのファイルログの使いどころ
バッチ・サービス・デスクトップアプリなど「画面がない」もの
Web アプリはクラウドのログサービスに送ることも多いですが、
バッチや Windows サービス、デスクトップアプリなどでは、
「とりあえずファイルに出しておく」が今でも強い選択肢です。
夜間バッチの例をイメージしてみます。
public class NightlyJob
{
private readonly ILogger<NightlyJob> _logger;
public NightlyJob(ILogger<NightlyJob> logger)
{
_logger = logger;
}
public async Task RunAsync()
{
_logger.LogInformation("夜間バッチ開始");
try
{
await Step1Async();
await Step2Async();
_logger.LogInformation("夜間バッチ正常終了");
}
catch (Exception ex)
{
_logger.LogError(ex, "夜間バッチ異常終了");
throw;
}
}
}
C#これがファイルに残っていれば、
「何時に始まって、どこで落ちたか」が一目で分かります。
ここでの重要ポイントは、「“人が直接見に行くログ”として、ファイルログは今でも非常に強い」ということです。
特にオンプレ環境や閉じたネットワークでは、ほぼ必須です。
書きすぎない・消しすぎないのバランス
ログ量は「ディスク」と「読む人」の両方に効いてくる
ファイルログは、書けば書くほどディスクを食います。
そして、読む側からすると「ノイズが多いログ」はそれだけでつらいです。
なので、
本番では Information 以上だけファイルに出す
Debug や Trace は別の出力(コンソールだけ、開発環境だけ)にする
ローテーションで古いログは自動削除する
といったバランスが大事になります。
「とりあえず全部ファイルに出す」は、最初は安心感がありますが、
数ヶ月後に「ログが多すぎて誰も読まない」「ディスクが足りない」となりがちです。
ここでの重要ポイントは、「“本番で本当に読みたいログだけをファイルに残す”という意識を持つ」ことです。
それ以外の細かいログは、必要なときだけレベルを下げて出す、という運用に寄せていきます。
まとめ:「ファイルログユーティリティ」は“現場で一番頼りになる証拠箱”
ファイルログの本質は、
アプリの動きを
人間が後から読めるテキストとして
安全に・適量で・継続的に残しておく
ことです。
押さえておきたいポイントを整理すると、
ファイルログは「1 行 1 イベント」で、日時・レベル・メッセージ・コンテキストを入れる
自前で書くなら lock で排他しつつ AppendAllText などで追記する
実務では ILogger とファイルプロバイダ(Serilog など)を組み合わせるのが現実的
ローテーション(日時やサイズでファイルを分割し、古いものを削除)を前提に設計する
本番で本当に読みたいログだけをファイルに出し、細かいログはレベル制御でオンオフする
ここまで腹落ちしていれば、
「とりあえず Console.WriteLine」から一歩進んで、
“現場で本当に役に立つファイルログ”を設計できるようになります。
