ログ集約

分散システムの複数サービスから出力されるログを一元的に収集 / 検索 / 分析する仕組み

運用オブザーバビリティ

ログ集約とは

ログ集約 (Log Aggregation) は、分散システムの複数サービスから出力されるログを一元的に収集・保存し、横断的に検索・分析できるようにする仕組みである。マイクロサービスLambda 関数が数十〜数百に増えると、個別にログを確認するのは現実的でない。ログ集約により、1 つのリクエストが複数サービスを横断する際の全体像を追跡できる。

なぜ必要か

障害調査の第一歩は「どのサービスで壊れたか」の切り分けである。1 つのリクエストが通過する経路を並べると、切り分けに必要な情報がどれだけ散らばっているかが見える。

ユーザーのリクエスト
  → API Gateway (ログ)
  → Lambda A (ログ)
  → SQS → Lambda B (ログ)
  → DynamoDB (呼び出した Lambda B 側のログに残る)

経路上のすべての要素が自分でログを出すわけではない点に注意したい。データストアへのアクセスは呼び出し側のログに残るため、呼び出し側で所要時間や結果を記録していないと、そこだけ調査の空白になる。

エラーが発生した場合、どのサービスで何が起きたかを特定するには、全サービスのログを横断的に検索する必要がある。ログ集約がなければ、各サービスのログを個別に確認する作業が発生する。

AWS でのログ集約パターン

CloudWatch Logs (標準)

Lambda は実行ロールに CloudWatch Logs への権限があれば、呼び出しごとのログを自動で /aws/lambda/<関数名> へ送る。一方、ECSAPI Gateway は自動ではない。ECS はタスク定義で awslogs ログドライバーを指定して初めてコンテナのログが届き、Fargate では awslogs-stream-prefix の指定も必須になる。API Gateway はリージョンごとに CloudWatch へログを送るための IAM ロールをアカウントに設定した上で、ステージ単位に実行ログとアクセスログを有効化する必要がある。「ログが出ていない」の相談の大半は、この設定漏れが正体である。

検索は CloudWatch Logs Insights で行う。既定のクエリ言語はパイプでコマンドをつなぐ専用言語で、SQL とは構文が異なる。2026 年 8 月時点では OpenSearch の PPL と SQL も選択できるので、SQL で書きたい場合は言語を切り替える。

# CloudWatch Logs Insights クエリ
fields @timestamp, @message
| filter @message like /ERROR/
| sort @timestamp desc
| limit 50

コスト面の落とし穴として、ロググループは保持期間を設定しない限りログイベントが期限切れにならず、保存料金が積み上がり続ける。集約先を作る作業は、保持期間を決めるところまでで 1 セットと考える。

CloudWatch → Firehose → S3 → Athena (大規模)

ログ量が多い場合は、S3 に置いて Athena で SQL クエリを実行する方が安く済む。ここで取り違えやすいのが経路である。サブスクリプションフィルターの宛先に S3 は指定できない。指定できるのは同一アカウントの Kinesis データストリーム、Amazon Data Firehose の配信ストリーム、Lambda 関数、そしてクロスアカウント配信用の論理宛先である。継続的に S3 へ流し込むなら Firehose を挟む。

S3 へのエクスポートタスクも用意されているが、こちらは期間を指定して取り出すバッチ処理で、アカウントあたり同時に実行できるタスクは 1 つ、出力ファイル内でイベントが時刻順に並ぶ保証もない。AWS 自身も継続的なアーカイブ手段としては勧めておらず、その用途にはサブスクリプションを使うよう案内している。

OpenSearch Service (全文検索)

リアルタイムのログ検索とダッシュボードが必要な場合は Amazon OpenSearch Service を使う。2021 年 9 月に Amazon Elasticsearch Service から改称されたサービスで、可視化の入口も Kibana から OpenSearch Dashboards に置き換わっている。エンドポイントが /_plugin/kibana から /_dashboards に変わっているため、古い手順書のまま URL や IAM ポリシーを流用すると到達できない。

構造化ログとの組み合わせ

ログ集約の効果を最大化するには、構造化ログ (JSON 形式) が不可欠だ。

// ❌ 非構造化ログ: 検索・集計が困難
console.log('Order 123 processed for user 456 in 250ms');

// ✅ 構造化ログ: フィールドで検索・集計可能
logger.info({
  event: 'order_processed',
  orderId: '123',
  userId: '456',
  durationMs: 250,
  correlationId: 'req-abc',
});

構造化ログなら orderId = "123"durationMs > 1000 でフィルタリングできる。

相関 ID (Correlation ID)

1 つのリクエストが複数サービスを横断する際、相関 ID を全サービスのログに含めることで、リクエスト全体のログを追跡できる。

API Gateway: { correlationId: "req-abc", service: "api-gw", message: "Request received" }
Lambda A:    { correlationId: "req-abc", service: "order",  message: "Order created" }
Lambda B:    { correlationId: "req-abc", service: "payment", message: "Payment processed" }

CloudWatch Logs Insights で correlationId = "req-abc" を検索すれば、リクエストの全経路が表示される。

ログレベルの使い分け

ログレベルは「誰がいつ見るか」で決めると粒度がぶれない。ERROR は人を呼び出す前提の記録、INFO は後から業務の流れを再構成するための記録と割り切る。判断に迷う出力は DEBUG に落として、本番では出さない選択も含めて設計する。

レベル用途
ERROR即座に対応が必要未処理の例外、外部サービスの障害
WARN注意が必要だが動作は継続リトライ発生、レート制限に接近
INFO正常な業務イベント注文完了、ユーザー登録
DEBUG開発・デバッグ用関数の入出力、SQL クエリ

理論と実装の両面から学ぶなら関連書籍が参考になる。

この記事は役に立ちましたか?

関連用語

関連する記事