awesome-hacks
Docs

ログシステムの構成:ログ出力・収集・ローテーション

ログ出力とログ収集の違い、ログを実現するシステム全体の構成、ログファイルのローテーションの仕組みをゼロから解説

最終更新:2026/06/16

TL;DR

  • ログ出力はアプリが書き出す行為、ログ収集はそれを別の場所に集める行為。役割が異なる
  • ログシステムは「アプリ → 出力 → 収集・転送 → 蓄積 → 検索・可視化」の流れで構成される
  • ログローテーションとはログファイルが無限に大きくなるのを防ぐ仕組み。一定サイズ・日時で古いファイルを切り替える
  • Fluentd はログ収集の代表ツール。ファイルやソケットからログを受け取り、変換して複数の転送先に送れる
  • 本番環境では単体サーバーで完結させず、専用のログ基盤(ELK(Elasticsearch・Logstash/Filebeat・Kibanaの頭文字をとったログ基盤スタック)、CloudWatch など)に集約するのが一般的

目的

アプリ単体でログを出力するだけでは、現実の運用では不十分になる。

  • サーバーが複数台あると、各サーバーのログが別々のファイルに分散する
  • ログファイルを放置すると、ディスクが満杯になってサーバーが停止する
  • ログがテキストファイルのままでは「特定ユーザーのエラーだけを素早く検索する」ができない

この記事では、ログを「出力するだけ」で終わらせず、実際の運用に耐えるシステムとして構築するための全体像を説明する。


ログ出力とログ収集の違い

この2つは別の役割を担う。

ログ出力ログ収集
誰が行うかアプリケーション自身収集ツール(Fluentd、Logstash など)またはクラウドサービス
何をするかログをファイルや標準出力に書き出す出力されたログを読み取って別の場所へ転送する
場所アプリが動くサーバー内アプリとは独立したプロセスやサービス

ログ出力(アプリの仕事)

アプリはログライブラリを使って、設定した出力先にログを書き出すだけ。
「あとでどこかに送る」という責任はアプリは持たない。

アプリ → /var/log/app/app.log(ファイルに書き出す)
アプリ → 標準出力(コンソールに書き出す)

ログ収集(インフラの仕事)

アプリが出力したログを、収集ツールが拾い上げて転送する。
これによってアプリは「書き出す」だけに集中できる。

/var/log/app/app.log → [Fluentd] → Elasticsearch(全サーバーのログを1か所に集める)
標準出力            → [CloudWatch Agent] → AWS CloudWatch Logs

Fluentdとは

Fluentd はログ収集の代表的なツール。「ログを受け取る → 加工する → 送り出す」の3ステップを担う。

基本的な仕組み

Fluentd はプラグインという拡張機能の組み合わせで動作する。

[Input プラグイン]  →  [Filter プラグイン]  →  [Output プラグイン]
ログを受け取る         内容を変換・加工する      転送先へ送り出す
プラグイン種別役割
Inputログを読み込むファイルを監視 / HTTP で受信 / syslog 受信
Filterログを変換・加工するJSON にパース / フィールドを追加 / 不要な行を除外
Outputログを送り出すElasticsearch へ送信 / S3 へ保存 / 別のサーバーへ転送

設定ファイルの例

Fluentd の設定は fluent.conf という設定ファイルで記述する。

# ① Inputプラグイン:アプリのログファイルを監視する
<source>
  @type tail                          # ファイルを末尾から追いかけて読む
  path /var/log/app/app.log           # 監視するファイル
  pos_file /var/log/td-agent/app.pos  # どこまで読んだかを記録するファイル
  tag app.log                         # このログに付けるタグ名
  <parse>
    @type json                        # JSONフォーマットとして解析する
  </parse>
</source>

# ② Filterプラグイン:フィールドを追加する
<filter app.log>
  @type record_transformer
  <record>
    hostname "#{Socket.gethostname}"  # サーバーのホスト名を自動で付加する
  </record>
</filter>

# ③ Outputプラグイン:Elasticsearchへ転送する
<match app.log>
  @type elasticsearch
  host elasticsearch.example.com
  port 9200
  index_name app-logs
  <buffer>
    flush_interval 5s   # 5秒ごとにまとめて送信(リアルタイムではなくバッファリング)
  </buffer>
</match>

上記の設定で行われることを順番に追うと:

  1. /var/log/app/app.log に新しい行が追記されるたびに Fluentd が検知する
  2. 各行を JSON としてパースし、hostname フィールドを追加する
  3. 5秒ごとにまとめて Elasticsearch へ送信する

バッファリング(まとめて送る仕組み)

Fluentd は受け取ったログを1行ずつ即座に転送するのではなく、一定量・一定時間ためてからまとめて送信する(バッファリング)。

これにより:

  • ネットワーク通信の回数を減らしてパフォーマンスを上げられる
  • 転送先(Elasticsearch など)が一時的に落ちても、ログをバッファに保持して後から再送できる

複数の転送先に同時に送ることもできる

# 同じログを Elasticsearch と S3 の両方へ送る
<match app.log>
  @type copy
  <store>
    @type elasticsearch
    host elasticsearch.example.com
    ...
  </store>
  <store>
    @type s3
    s3_bucket my-log-bucket
    ...
  </store>
</match>

Fluentdとよく似たツールとの違い

ツール特徴
Fluentdプラグインが豊富。設定の自由度が高い。Ruby 製
Fluent BitFluentd の軽量版。コンテナ・組み込み向け。C 製でメモリ消費が少ない
FilebeatElastic 社製の軽量エージェント。ELKスタックとの親和性が高い
LogstashElastic 社製。変換・加工の表現力が高いが、重い

Kubernetes 環境では Fluent Bit を各ノードに DaemonSet として配置し、Fluentd に集約するという構成がよく使われる。


ログを実現するシステム全体の構成

全体像

graph TD
    App["アプリ<br/>(NestJS / Spring Boot など)"]
    File["ログファイル<br/>/var/log/app/app.log"]
    Agent["収集エージェント<br/>Fluentd / Filebeat / CloudWatch Agent"]
    Storage["ストレージ<br/>Elasticsearch / CloudWatch Logs / S3"]
    UI["可視化 UI<br/>Kibana / Grafana / CloudWatch Insights"]

    App -->|ログ出力| File
    File -->|読み取り| Agent
    Agent -->|転送| Storage
    Storage -->|検索・可視化| UI

    subgraph appserver ["アプリサーバー"]
        App
        File
        Agent
    end

    subgraph loginfra ["ログ基盤(別サーバー)"]
        Storage
        UI
    end

各コンポーネントの役割

役割具体例説明
アプリNestJS, Spring Boot, Djangoログを出力する
収集エージェントFluentd, Filebeat, CloudWatch Agentログを読み取って転送する
ストレージElasticsearch, CloudWatch Logs, BigQueryログを蓄積・検索できる形で保存する
可視化Kibana, Grafana, CloudWatch Insightsダッシュボードで確認・検索する

代表的な構成パターン

ELKスタック(オンプレ・自前構築向け)

graph LR
    App["アプリ"] --> FB["Filebeat / Logstash<br/>(収集・転送)"]
    FB --> ES["Elasticsearch<br/>(蓄積・検索)"]
    ES --> Kibana["Kibana<br/>(可視化)"]
  • Elasticsearch: ログを全文検索できる形で蓄積するデータベース
  • Logstash / Filebeat: 収集・転送エージェント
  • Kibana: Elasticsearch のログを検索・グラフ表示する UI

AWSの場合(マネージドサービス)

graph LR
    App["アプリ<br/>(ECS / Lambda)"] -->|標準出力| CWL["CloudWatch Logs<br/>(自動収集)"]
    CWL --> Insights["CloudWatch Insights<br/>(検索・分析)"]
    CWL -->|必要なら| S3["S3<br/>(長期保存)"]

ECSやLambdaの場合、標準出力に書くだけで CloudWatch Logs が自動でログを収集してくれる。
アプリ側に収集エージェントを置く必要がない。


ログファイルのローテーションとは

問題:ログファイルは放置すると巨大化する

ログを1つのファイルに書き続けると、時間とともにファイルが数GB・数十GBに膨れ上がる。
ディスクが満杯になるとサーバーが停止したり、新しいログが書けなくなったりする。

解決策:ローテーション(定期的にファイルを切り替える)

ログローテーションとは、古いログファイルを「切り替える」仕組み。

app.log        ← 現在書き込み中のファイル
app.log.1      ← 昨日のログ(1世代前)
app.log.2      ← 一昨日のログ(2世代前)
app.log.3      ← 3世代前
...(設定した世代数を超えたら削除)

ローテーションのトリガー

トリガー説明
日時ベース毎日0時など、決まった時刻にファイルを切り替えるapp-2026-06-16.log のように日付をファイル名に含める
サイズベースファイルが一定サイズを超えたら切り替える100MB を超えたら新しいファイルに切り替える
組み合わせどちらかの条件を満たしたら切り替える多くの設定でよく使われる

ローテーションを行うツール

ツール説明
logrotateLinux の標準ツール。設定ファイルでローテーションルールを定義する
ログライブラリ内蔵機能Winston の DailyRotateFile など、ライブラリ自身がローテーションを担う
クラウドサービスCloudWatch Logs などはストレージ上限や保持期間を設定するだけでよい

linuxのlogrotate設定例

/var/log/app/app.log {
  daily              # 毎日ローテーション
  rotate 14          # 14世代(14日分)保持
  compress           # 古いファイルを gzip 圧縮
  missingok          # ファイルがなくてもエラーにしない
  notifempty         # ファイルが空ならローテーションしない
  create 0640 app app  # 新しいファイルを作成するパーミッション設定
}

Winston(Node.js)でのローテーション設定例

import DailyRotateFile from 'winston-daily-rotate-file';

const transport = new DailyRotateFile({
  filename: '/var/log/app/app-%DATE%.log',
  datePattern: 'YYYY-MM-DD',   // 日付ごとにファイルを切り替え
  maxSize: '100m',             // 100MB を超えたら切り替え
  maxFiles: '14d',             // 14日分を保持(それ以前は削除)
  zippedArchive: true,         // 古いファイルを gzip 圧縮
});

システム構成の選び方

アプリが1台の場合(小規模)

ローテーション付きのファイルに書き出すだけでも十分なケースがある。

アプリ → ファイル(logrotate でローテーション)

ただし、検索はファイルを grep する形になるため、量が増えると辛くなる。

複数サーバー・本番環境(標準的)

各サーバーのログをクラウドや専用のログ基盤に集約する。

graph LR
    A["サーバーA のアプリ"]
    B["サーバーB のアプリ"]
    C["サーバーC のアプリ"]
    Log["ログ基盤<br/>CloudWatch Logs / Elasticsearch"]
    Search["検索・分析<br/>(全サーバーを横断)"]

    A --> Log
    B --> Log
    C --> Log
    Log --> Search

複数サーバーのログが1か所に集まることで「全サーバーを横断して特定ユーザーのエラーを検索する」ができるようになる。

コンテナ環境(Docker / Kubernetes)

コンテナは「ファイルに書く」よりも「標準出力に書く」が基本。
コンテナ管理システムが標準出力を自動収集してくれる。

graph LR
    App["アプリ(コンテナ)"] -->|標準出力| Driver["Docker / Kubernetes<br/>ログドライバー"]
    Driver --> Log["ログ基盤"]

よくある落とし穴

ローテーションを設定せずにログを放置する

ディスク満杯でサーバーが止まる典型的な障害パターン。
アプリを本番環境に置くときは必ずローテーション設定を確認する。

ログファイルを直接アプリサーバー上だけで見ようとする

tail -f /var/log/app/app.log でリアルタイム確認はできるが、検索・フィルタリングには向かない。
また、サーバーが壊れるとログも失われる。本番では必ずログ基盤に転送して永続化する。

アプリが直接ログ基盤に書きに行く設計にする

ログ基盤が落ちたときにアプリの処理がブロックされるリスクがある。
アプリはローカルのファイルか標準出力に書き、転送は収集エージェントに任せる設計が安全。


関連