実運用を見据えたログ設計の観点
—⁠—5つの設計指針と運用面での活用戦略

Software Design 2026年3月号の第1特集「再考・ログ設計」から第3章「実運用を見据えたログ設計の観点」を公開します。第1特集のほかの章では、構造化ログの基本やAWS環境でのログ設計の指針などについても解説しています。ぜひ本誌にてご確認ください。

効果的なログ設計は、信頼性が高いアプリケーションの開発・運用に不可欠です。本章では主要な設計原則を整理し、実効性を重視した具体的な指針と実装の勘所を提示します。クラウドネイティブな運用とオブザーバビリティの観点から、従来の設計を見直してみましょう。

はじめに

アプリケーションログは、システムの動作状況を外部から把握し、意図したとおりに処理が行われているかを確認するための重要な情報源です。本章では、まずはOWASP(Open Web Application Security Project)やクラウドプロバイダー、オブザーバビリティSaaSが公開しているガイドラインやベストプラクティス[1]をベースに、効果的なログ設計を行うための具体的な指針を説明します。

ログの設計において核となるのは、運用や調査において「そのログがどのように役立つか」という視点を持つことです。そこで本章の後半では、収集したログを監視に活用する手法や、メトリクスやトレースといったほかのテレメトリデータとログを関連付けることで、システム全体の状態をより多角的に理解する方法についても紹介します。

本稿を通じて、日々の開発に組み込める現実的かつ効果的なログ設計のあり方を検討する一助となれば幸いです。

アプリケーションログ設計のベストプラクティス

まず、次のようなアプリケーションログの設計原則を掘り下げ、ベストプラクティスを実現するための設計方針について考えます。

  • いつ何をログに記録するかを決め、継続的に見直す
  • 構造化ログを使用する
  • イベントをカテゴリで分類する
  • 読み手にとって有用な情報を含める
  • 機密データを記録しない

いつ何をログに記録するかを決め⁠継続的に見直す

最も重要な原則は、アプリケーションログを「何に、誰が、どのように使用するのか」を見据えたうえで、⁠どのイベントやアクションをどのタイミングで収集するのか」という戦略を立てることです。ユースケースの代表的なものとしては、運用(デバッグ、各種監視⁠⁠、監査・セキュリティ要件、分析(ビジネス固有の要件を含む)が挙げられます。

方針を決める際には、⁠ログ不足」「過剰なログ」の両方に注意する必要があります。ログが少なすぎるとインシデント発生時の調査を困難にしてしまうため、一般的には、不足するよりは必要最低限よりも多い量のログを出力することが優先されます。一方で、不要なログデータはアプリケーションのパフォーマンス悪化、ストレージ容量の増加、ログ検索の遅延を引き起こすため、過剰になりすぎるのも問題です。

ロギングの方針を定めず開発を進めると、重要な異常を検知できなかったり、逆にノイズが増えてインシデント対応に時間がかかったりするなど、ログの不足と過剰両方のデメリットを抱える状況になる傾向があります。アプリケーションの設計段階など、できるだけ早いタイミングで方針を定めたうえで、システムに異常がない場合にも継続的に見直し改善するようにしましょう。

実装の観点では、重複した、もしくは冗長なログを出さないよう、ソースコード上のどこでログを記録するかを決めておくとよいでしょう。たとえばStripeのメインAPIの実装では、リスト1のように、ミドルウェア層でリクエストあたり1つのログを記録しているそうです。AmazonやStripeでは、リクエストやキューからのメッセージの処理など、作業ごとの単位あたり1つのログエントリのみを出力する習慣があり、StripeはこのようなログをCanonical(標準的な、規準的な)log lineと命名しています[2]

リスト1 APIのミドルウェア実装の疑似コード
関数 Canonical log line出力ミドルウェア(リクエスト, コンテキスト):
  # ミドルウェア内でコンテキストに情報を付与しておくことも可能

  # アプリケーション実行中に、属性がコンテキストに蓄積される
  レスポンス = アプリケーション実行(リクエスト, コンテキスト)

  # ログ出力で例外が発生しても、異常終了しないよう実装する
  Canonical log line出力(レスポンス, コンテキスト)

  return レスポンス

ミドルウェアから渡したコンテキストオブジェクトにアプリケーションの処理を実行する過程でデータを追加していくことで、ログの出力時に使用するコンテキストには必要なすべての情報が含まれた状態になります。

本来、こうした横断的関心事は、ミドルウェアなどのコンポーネントで一括処理するのがアーキテクチャ上の定石です。しかし筆者は、アプリケーションの状況によっては、必要な情報を関数の戻り値として伝播させ、レイヤードアーキテクチャの上位層の、アプリケーションの処理の完結点にできるだけ近い場所でログを記録する、という方針を採用することがあります。具体的には、たとえばAPIサーバの実装において、⁠ハンドラ関数内で実行した関数の戻り値を使用して、return直前で一度だけログを記録する」というルールが、チームにとって直感的で保守しやすい場合です。

ロギングの方針が未決定で、重複したログを出してしまっているような状態のアプリケーションの場合は、まずは実装しやすい方針を立ててログをまとめて記録するようにしたうえで、必要な情報を洗い出してから実装を洗練させていく手もあります。

リクエストもしくは処理1件あたりのログにすべての情報を詰め込む方針は、インシデント対応をすばやく行うという点で特に有用です。一方でオブザーバビリティの観点では、処理の流れを追うために必要なマイルストーンとなる処理の前後で随時処理の進行状況を記録することで、分析がしやすくなる可能性があります。そのため、⁠ほかのテレメトリデータを使った相関分析を前提にしている場合は、任意のタイミングでログを出力してよい」という複合的な方針にすることも考えられます(詳細は後述します⁠⁠。

セキュリティの観点では、OWASPが推奨するように、外部からの入力値の検証や認証、その他リスクの高い操作については確実にログが出力されることを確認しておきましょう。

いつ、そして何を、ソースコード上のどこでログとして記録すべきかは、一概に決められるものではありません。ですが、その時点でわかっているログのユースケースを網羅できる必要な詳細情報が十分に含まれるよう決定する必要があります。一方で、組織やアプリケーションの状況は日々変化するため、実際にどのような情報が必要になるかを詳細に知ることは現実的には困難です。そのため、アプリケーションを運用する中で継続的に方針を見直す必要があります。

構造化ログを使用する

ログを活用しやすい状態にするため、構造化ログを使用しましょう。構造化ログをサポートするロギングライブラリを使用するか、ロギングフレームワークを実装するのがよいでしょう。構造化ログの意義や特徴は第2章で詳細に説明されているため、本章では割愛します。

イベントをカテゴリで分類する

イベントの種類と重大性(ログレベル⁠⁠、用途を示すラベルやフィルタリング条件などで、ログを分類しましょう。分類は、構造化ログの1つのフィールド(ディメンション)によって表現されます。高ディメンションのログほど複雑な状況でも多面的に洞察を得ることができ、フィールドが持つ値が高カーディナリティであるほど必要なログを絞り込みやすくなります。

カテゴリの代表的なものが、環境の健全性を示すログレベルです。ログレベルはクラウドサービスや使用するツールによって決められた分類が存在するため、使用できるレベルの意味を理解し、一貫した戦略を持ってログレベルを設定することが大切です。

ログレベルは、一般的には重大度が低い順にDEBUG/INFO/WARN/ERROR/FATALのように定義されており図1⁠、レベルごとの一般的な意味も定義されています(意味については第1章をご覧ください⁠⁠。しかし、実際の処理においてどの状況がどのレベルに当たるかは、一概に決められません。アプリケーションにより判断する必要があります。

図1 ログレベルとアラーム

たとえば、外部APIの呼び出しが失敗した場合、必ずしもERRORレベルのログを記録するのがよいわけではありません。処理をリトライしたり、データのキャッシュを使用したりするなどの代替手段でリカバリできる場合には、WARNレベルのログを記録するのが適切な可能性があります。

ログベースの監視の詳細については後述しますが、WARN以上のレベルのログは、アプリケーションでアラーム(モニタリングしている値が一定を超えると送信される通知)を発生させる可能性があります。一方で、ERROR以上のレベルのログが、必ずしもアラームの発火条件になるわけではありません。ログレベルの戦略は、監視の方針と併せて開発初期段階から検討し、継続的にノイズの多さなどを点検しつつ基準を調整するとよいでしょう。

一般的に、ロギングライブラリは出力するログレベルの閾値しきいちを設定できます。そのため、⁠開発中は出力するログレベルをDEBUGに設定し、本番環境ではINFO以上のレベルに設定する」などの運用方針にすることで、開発環境では詳細な調査を行う一方で、コストを抑えつつ本番環境での調査時の検索性を向上させることができます。

実装時の注意点として、事前にカテゴリを表現するフィールド名を決めておき、チームもしくは組織内でフィールドの規約を決めておくとよいでしょう。フィールド名の揺らぎを防止でき、イベント同士を関連付けやすくなります。

クラウドサービスで決められた規約やOpen Telemetry Protocol(OTLP)などの特定のプロトコルを使用する場合、各言語のライブラリやSDK[3]が、定められた規約やデータモデル[4]に則ったフィールド名を自動で付与します。そのため、何を使うかを定めれば、フィールド名のルールについては一部自動的に決まります。

構造化ログは、アプリケーションコード上でフィールドを上書きできてしまいます。そのため、独自のフィールドを定義する場合には、フィールド名と指定するバリューをenumもしくは定数として定義して、不用意に使用されないよう管理するなどの工夫をするとよいでしょう。

読み手にとって有用な情報を含める

ここでの「読み手」は、開発運用の担当者に加えて、ログの解析サービスやオブザーバビリティツールなどの、ログを活用するシステムを含みます。

必要十分な情報を付与する

各ログには、少なくとも次の情報を含める必要があります。

  • タイムスタンプ
  • ログレベル
  • 各種識別子(リクエストID、ユーザーIDなど)
  • 説明的なメッセージ

ロギングライブラリやログルーターなどが自動で付与する情報もあります。

必要な情報を、構造化ログのフィールドもしくはメッセージの文字列のどちらに含めるかという点では、次のようなことをふまえ、処理に関連する情報はできる限りフィールドとして付与しましょう。

  • ログ管理・分析サービスにおいてログのインデックスには一般的にメッセージ以外のフィールドが使用される
  • ログメッセージの文字列はアプリケーションコード上で意図せず修正されるリスクが高い

OpenTelemetryや各種オブザーバビリティツールを利用する際には、ライブラリやSDKを使用することにより、規約に準拠した形式にデータをマッピングしてくれることがあります。ですが、ユーザーやビジネスロジックに関係するアプリケーション特有のデータモデルについては、固有のフィールドを定め、開発者全体で共有しておくとよいでしょう。

最低限、システムのユーザーが「いつ、どこで、誰が、何をしたか」という情報を含めると、多くの用途で使用される可能性が高いと言えます。これに加えて、次のような、ログを活用する読み手にとって必要な情報を洗い出して含める必要があります。

  • 調査時にイベントや根本原因を正確に特定するために必要なメタデータ
  • 監視のためのメトリクスを抽出するためのフィルターとして指定される識別子

監査と分析のために必要な一般的なデータについては、OWASPのロギングチートシートAWSの規範ガイダンスなどが参考になります。

コンテキストを同じくする多くのログで都度情報を出力するよりは、フィールドを多く持ちデバッグや調査に必要な情報をすべて含むログを少数出力するほうが、読み手にとってははるかに有用となり得ることも覚えておきましょう。構造化ログは、必要なフィールドを簡単に抽出することができるため、ログ1つあたりの情報が多くなったとしても、読み手が困ることはほとんどありません。

オブザーバビリティの観点では、多くの情報を保持する構造化されたイベントはワイドイベントと呼ばれますリスト2⁠。ワイドイベントはアプリケーションログやスパンなどで表現され、多様な条件でフィルタリングできます。そのため、未知の事象にも対処しやすく、情報の凝集度を高めた結果として記録回数が少なくて済むという利点があります。

リスト2 ワイドイベントのログのイメージ
# イベントごとに出力されたログ
{"timestamp": "2026-01-12T20:40:00Z", "level": "INFO",ュ
"request_id": "req-123", "msg": "Start orderュ
processing"}
{"timestamp": "2026-01-12T20:40:01Z", "level": "INFO",ュ
"request_id": "req-123", "msg": "User validated",ュ
"user_id": "u-456"}
{"timestamp": "2026-01-12T20:40:02Z", "level": "INFO",ュ
"request_id": "req-123", "msg": "Payment success",ュ
"amount": 5000}
{"timestamp": "2026-01-12T20:40:03Z", "level": "INFO",ュ
"request_id": "req-123", "msg": "Order completed"}

# ワイドイベントのログ
{
 "timestamp": "2026-01-12T20:40:03Z",
 "duration_ms": 3000,
 "trace_id": "t-789",
 "request_id": "req-123",
 "service_name": "order-service",
 "user": {
  "id": "u-456",
  "tier": "premium",
  "region": "tokyo"
 },
 "order": {
  "id": "ord-999",
  "amount": 5000,
  "item_count": 3,
  "coupon_used": true
 },
 "payment": {
  "gateway": "stripe",
  "status": "success",
  "latency_ms": 450
 },
 "app_version": "v2.1.0",
 "env": "production",
 "outcome": "success"
}

意義のあるログメッセージにする

ログメッセージは、アプリケーションの実行プロセスで何が起きたか、読み手が正確に理解できる文字列にしましょう。エラーを上位レイヤに伝播する場合には、受け取ったエラーをラップしたり文字列を追加したりすることで、ソースコード上でのコンテキスト情報を付加できます。

また、インシデント対応時に最初に見ることになるエラーログのメッセージは、事象を伝えるだけではなく、アクションを促す内容にすると、対応がスムーズになる場合があります。たとえば、⁠外部APIへのリクエストがタイムアウトしました」というメッセージに続けて、⁠外部サービスXXXの管理画面を確認し、トランザクションが実行されていることを確認してください」といったメッセージを追加しておきます。これにより、対応方法を思い出したり、手順書を探したりする手間が省けます。ただし、メッセージが冗長にならないよう、簡潔に書くよう配慮しましょう。

ログメッセージをアプリケーションコードと同期させることも重要です。コードのリファクタリングを行うときなどに、既存のログメッセージの内容を修正し忘れ、ログメッセージが現実に即していない状態になってしまうことがよくあります。そのため、⁠ログメッセージに関数名を使用せず状況の説明を書くようにする」といった方針を決めておくのもよいでしょう。

機密データを記録しない

ユーザーの個人情報や企業の機密情報など、流出した場合に悪用され得るデータは、アプリケーションログに含めないようにしましょう。機密情報の定義は組織で決められている場合もありますが、それでもアプリケーション開発時のログへの出力は見落とされやすいです。ログ設計の方針を決定する際に必ず確認し、開発者が意識できるようにしましょう。

万が一機密データがログに出力されてしまった場合に備えて、データ加工の機能を備えたログ転送ツールや、Amazon CloudWatch LogsやDatadogのようなログを保管するサービスにおいて、機密情報を削除もしくはマスキングすることも可能です。しかし、偶発的な漏洩リスクを最小限に抑えるためにも、ログの生成箇所であるアプリケーションコードでサニタイズすることが望ましいです。

実装面では、⁠ロギングライブラリの出力関数をオーバーライドして値をマスキングする」など、出力時に都度考慮せずとも一律で対応できるようにすることで安全性を向上させることができます。

システム運用におけるアプリケーションログの活用

アプリケーションログのユースケースのうち、開発チームが最も関係するのがシステム運用です。以降では、近年のアプリケーション運用においてアプリケーションログをどのように活用できるのか説明しつつ、ログ設計に関係する次の観点を確認します。

  • フィルタリングの活用
  • ログベースの監視
  • テレメトリの統合とログの計装

運用におけるフィルタリングの活用

クラウドでホストされるアプリケーションのログは、ログ収集・管理用のストレージに送信され、システムログなどの異なる種類のログと一元管理されることが一般的です。そのため、フィルタリングによって不要なログをストレージに送信しないようにしたり、調査時に分析ツールで条件を指定したフィルタリングを行って必要なログのみを抽出したりするなどの作業が必要になります。

ひとくちにフィルタリングと言ってもさまざまな使い方があります。運用時の最も基本的な使い方は、Amazon CloudWatch LogsやAmazon Athenaのようなログ分析機能を備えたツールを用いた、エラー発生時のログの絞り込みによる状況調査です。構造化ログの「リクエストID」⁠ユーザーID」といったフィールドをフィルタ条件に指定して、関連する一連のログを即座に引き出し、時系列に並べ替えて、次のような経緯を明らかにします。

  • 異常発生の直前にどのような操作が行われていたのか
  • そのエラーがなぜ発生したのか

近年のクラウドサービスが提供するマネージドなコンピューティング環境(AWS LambdaやGoogle CloudのCloud Run Functionsなど)においては、コンソール画面に実行単位ごとのログを表示してくれるケースも増えています。ですが、ログの一元管理の必要性や、分散トレーシングにおける相関分析などの観点から、アプリケーションログに含めるべき情報量は変わりません。

また、ログ分析ツールのクエリ生成機能に生成AIが搭載されることによって、フィルタリング条件を知らなくても自然言語で分析できる場合もあります。しかし、分析対象であるログ自体に構造化された情報がそろい、かつログ同士が関連していなければ、インサイトを得ることはできません。アクセスが少ない、もしくは複雑度が低いシステムでは、方針を定めずとも運用に支障がないこともありますが、システムの改修に伴いログの認知負荷が増加していけば、フィルタリングの難易度が上がり、いずれ調査ができない状態になります。

フィルタリングは、調査のみならず、条件に合うログの件数をカウントすることでメトリクスを生成するためにも使用されます。多くのモニタリングサービスでは、フィルタを作成してメトリクスを生成し、ダッシュボードでグラフ化できます。アプリケーションログをメトリクス(数値)化することで、アプリケーションの処理の異常を早期検知したり、時系列データとして傾向分析を行ったりできます。

ログベースの監視

ログベースの監視は、一般的に次のステップで構成されます。

  1. ログの収集:アプリケーションからログを出力し、ログ基盤に集約する
  2. ログのメトリクス化もしくはフィルタリング:ログの特定のキーワードやパターンをフィルタリングして検知する。もしくは条件に該当するログの件数をカウントする
  3. 監視条件と通知の設定:条件に該当するログが見つかる。もしくはメトリクスの値が閾値を超えた場合にアラームを通知する

たとえば、Amazon CloudWatch Logs等のログストレージに集約されたデータを利用する場合、メトリクスフィルター機能を用いて特定の条件のログをメトリクス化(数値化)し、Amazon CloudWatch Alarms等の監視サービスでメトリクスの閾値および通知先を定義できます。

また、Datadog等のオブザーバビリティツールは、アプリケーションやインフラから収集される標準メトリクスおよびカスタムメトリクスに対し、高度な監視・アラート機能を備えています。通知先としてPagerDuty等のインシデント管理ツールを使用することで、電話やチャット、プッシュ通知といった最適なチャネルを介して、担当者へ迅速に異常を報知することが可能となります。

アラート発生時には、多くの統合監視プラットフォームにおいて、トリガーとなったメトリクスにひも付くログが自動的にフィルタリングされた状態で提示されます。これにより、運用担当者は異常を検知したらすぐに関連するログデータを確認し、迅速に初動調査を開始できます。なお、事象に対して定型的な復旧手順が存在する場合は、担当者への通知に代わり、AWS LambdaやGoogle Cloud Run等のコンピューティングサービスで手順を自動化することもできます。自律的なリカバリを試みる構成は、運用負荷を下げるために有用です。

ログベースの監視を設計する際にも、アラームへの対応方法をある程度想定したうえで方針を考える必要があります。最もわかりやすいのは、⁠エラーが発生したことを示すエラーログが1件でも記録されたらアラームを通知する」という方針です。

しかしシステムの設計によっては、必ずしも人が対応する必要がないエラーも存在します。たとえば、複数のサービスをキューを用いて連携させるような疎結合なアーキテクチャにおいては、あるサービスにおいて処理が失敗したとしても、そのサービスにリクエストを送信したキューがリクエストのリトライを試行してくれる場合があります。そこで、たとえば「一定時間内に同じエラーが複数回発生したら通知する」というアラームの閾値条件を設定することにします。

それでも、ログインの異常な頻度の失敗など、攻撃などの問題を示すログパターンの場合は、即座に検知したいこともあります。このように、1つのレベルのログに対して複数の条件で監視を行いたい場合には、監視の条件を柔軟に設計するために、ログレベル以外のデータを組み合わせて使用する必要があります。

具体的にどう監視を設計するかはチームしだいです。筆者は「イベントに対する対応の要否とその温度感によって運用上必要な監視の分類を定め、監視用のカテゴリとしてログのフィールドに付与する」という方針を定めることが多いです。このとき、監視条件をログメッセージに依存させず、監視のポリシーに対応する専用のフィールドを作成することが重要です。ログメッセージはアプリケーションの実装において比較的簡単に変更できるものなので、ログメッセージに含まれる文字列を監視条件に指定すると、意図しない監視の無効化につながり、障害発生に気づけない状況を生み出すため危険です。

テレメトリの統合とログの計装戦略

フィルタリングによるログ調査は、既知の事象に対する証跡確認には有効ですが、予測困難な相互作用が発生する分散システムでは限界があります。そのようなシステムにおいては、依存関係にある他サービスの障害や遅延が自システムへ波及した際にもその因果関係を即座に特定できるよう、システム横断的なオブザーバビリティの確保が不可欠です。

ここでは、オブザーバビリティを構成するシグナルとなる主要なテレメトリデータであるメトリクス、トレース、ログの関係性から、アプリケーションログの設計を考察します。

メトリクスとトレース

メトリクスはCPU使用率、エラー率、キューの長さといった、システムのパフォーマンスや健全性を定量的に示す数値です。主に傾向分析やパフォーマンスの確認のために使用されます。従来のモノリシックなシステムのように構成が比較的単純なシステムでは、メトリクスとログだけで計測とトラブルシューティングをカバーできます。

トレースは、システム全体を横断する単一のリクエストやトランザクションのライフサイクルを追跡する処理時間とメタデータを保持します。トレースはより細かい処理単位であるスパンを複数持ち、スパン同士も親子関係を持ちます。コンテキストにトレースIDやスパンIDを持たせてシステムをまたいで伝播し、それらのIDをキーとして各所で発生する複数のシグナルを相関させることで、オブザーバビリティバックエンドで一連のイベントとして可視化・分析できます。

たとえば、マイクロサービスアーキテクチャにおいて上流サービスを担当するチームが、トレースを介して下流サービス内部で発生しているデータベースアクセスの詳細や処理遅延を、あたかも自サービス内の事象であるかのように可視化できます。複数のシステムを経由する処理をトレースとスパンによって監視するしくみを分散トレーシング、テレメトリデータを出力し外部に送信するための実装を計装と言います。

トレースおよびスパンの収集において、APM(Application Performance Monitoring)エージェント等を用いた自動計装は標準的なデータの取得を可能にしますが、アプリケーションコード内でカスタム計装を行うことで、固有のビジネスロジックやコンテキストを反映した柔軟な定義が可能となります。

相関分析の流れ

統合オブザーバビリティプラットフォームであるDatadogを使って、アプリケーションの状況を確認する流れの一例を見てみましょう。

Metrics Explorerで、trace.http.requestのカウントのメトリクスを指定すると、HTTPリクエストの件数を示す折れ線グラフが表示されます。エラーが大量に発生しているような状態の場合、このメトリクス画面でエラー件数の傾向を確認できます。

任意の時点のグラフにカーソルを合わせ、右クリックから[View traces]を選択すると、APMのTraces画面に遷移します。グラフでクリックした時間帯前後のトレースの一覧が表示されるので、その中から確認したいトレースを選択すると、図2に示すような詳細画面(トレースビュー)を確認できます[5]

図2 トレースビュー

やや見にくいため、画面上部のヘッダー付近を図3に切り出しました。GET /coffeehouseのAPI実行が200を返していることがわかります。この1APIリクエスト単位でトレースが作成されています。

図3 画面上部のヘッダー付近

画面上半分は、1つのトレースに含まれるスパンをグラフ化しています図4⁠。横軸が時間、縦軸がスパンの親子関係を表し、複数のシステム間でどのような処理経路をたどって、どの処理でどの程度時間がかかっていて、問題が発生した箇所がどこなのかを視覚的に特定できます。下に行くほど詳細な処理へとドリルダウンされており、エラーの発生箇所には棒グラフに「!」マークの赤いラベルがついています。グラフにはオペレーション名やリソース名、レイテンシー情報が記載されており、マウスオーバーしたりクリックするとより詳細な情報を見ることができます。

図4 スパンのグラフ部分

図4のエラーラベルがついたスパンのうち、上(上から4つ目のスパン)はcoffeeHouse.getOrder、下(上から8つ目のスパン)はcall_external_web_serviceと書かれています。これらのスパンが親子関係にあることから、注文取得処理の中で外部サービスへのアクセスに失敗しているという状況を視覚的に把握できます。

このエラー発生時の状況をより詳しく調査するため、上から3つ目のOpenTracingBrew Infoというスパンをクリックすると、画面下半分にスパンのメタデータ(スパン属性など)が表示されます。Logsのタブをクリックすると、図5のようにスパンにひも付くログの一覧に切り替わります。ログの左側にはログレベルに応じた色のバーがついており、エラーレベルのログが赤く表示され、その前後の時系列のログが並んでいます。上から順番に追っていくと、認証に成功し、MongoDBへの接続に成功したのち、上から3つ目のログでJavaでの外部呼び出しがタイムアウトしていることがわかります。

図5 スパンにひも付いているログ一覧部分

このように、メトリクスで異常の兆候や全体的な傾向を、トレースで一連の処理のなかでのボトルネックやエラー発生箇所を特定したうえで、アプリケーションログによって事象の具体的な原因を特定します。

テレメトリデータの活用方針

このような相関分析は、次のように活用できます。

  • エラーの根本原因調査
  • リソース消費の要因調査
  • パフォーマンスの最適化
  • ユーザー体験の問題調査(ユーザーからの問い合わせへの対応など)

複数種類のテレメトリデータを用いた相関分析を行いたい場合には、トレースやスパンなどをどのように設定し、ログを効果的にひも付けるためにどう設計したらよいか検討する必要があります。異常が発生していない処理についても状況を把握できるようにしておきたい場合には、本番環境でもINFOレベルのログをスパンと関連付けて都度出力することが有用な場合があります。ただし、AWSの規範ガイダンスでは、本番環境でINFO以下のレベルを無効にしてログ生成量を削減することを推奨しており、アプリケーションログのベストプラクティス[6]では、時間の経過に伴う傾向はログではなくトレース情報で確認すべきとしています。

これらをふまえると、次のような方針を検討してもよいでしょう。

  • 処理が正常に実行されているという事実は、ログではなく、アトリビュートにコンテキスト情報を持たせたスパンで表現する
  • 異常が起きたときにのみWARN以上のレベルのログを出力し、状況の詳細がわかるようにする

ただし、長時間実行されるワークフローやバッチ処理などの場合は、進捗状況の把握や処理速度の要因調査のため、ある程度のマイルストーンで区切ってINFOレベルのログを複数記録することが有用です。

メトリクス、トレースに加えて、昨今主要なオブザーバビリティプラットフォームやクラウドプロバイダーが提供している継続的なプロファイリング(Continuous Profiling)機能を併用することで、ソースコードのどの行がリソースを消費しているかまで、リアルタイムに分析・可視化できます。各種テレメトリデータの使い分けをどうするかは組織によりますが、テレメトリデータを多角的に活用する効率的なオブザーバビリティが確立されれば、従来のように開発者がデバッグ目的でログ出力を仕込む必要性は減少し、アプリケーションログはより本質的なビジネスイベントの記録を担うようになるでしょう。

最後に、オブザーバビリティプラットフォームの導入範囲については、コスト等の制約から本番環境のみに限定されるケースも少なくありません。しかし、開発環境でも導入することができれば、開発工程のフィードバックループを高速化し、開発の品質向上と効率化に大きく役立つ可能性があります。たとえば、特定のロジックにどの程度時間がかかり、それによって処理全体がどのように変わるかを把握できるトレースを作成しておけば、機能を改修する際に、開発環境で動作確認をすると同時に、その改修内容がシステム全体に与える影響を即座に分析できるようになります。

まとめ

アプリケーションログを設計する際には、情報量が多く情報密度の高いログを、ユースケースをカバーするために必要な分だけ出力する一貫した方針を策定しましょう。構造化ログの採用は近年ではデファクトスタンダードになっている印象ですが、どのような情報を含めいつ記録すべきかはアプリケーションによって大きく異なるうえ、すべての条件を網羅して把握することは困難です。システムを開発、運用するなかで、組織にとって最適なアプリケーションログがどのようなものなのか再考を続けることで、結果としてシステムの安定性とトラブルシューティングなどの調査効率を向上させることができます。

日々事業成果を追求するなかでアプリケーションログについて考えるために時間を確保するのは難しいものですが、状況に合った戦略がなければ徐々に運用負荷が上がります。障害が発生していないときこそ、ロギングの方針を定期的に見直しましょう。

最近の話題として、アプリケーション開発に必要なオブザーバビリティデータの変化と、オブザーバビリティプラットフォームの進化が注目を集めています[7]。本稿では具体的な実装方法や各種ツールについて詳細には踏み込んでいませんが、導入を検討する際には、観測したいデータをモデル化してどのテレメトリデータで何を表現するかを決め、アプリケーションログの方針についても併せて検討しなおすようにしましょう。

各種ベストプラクティスをふまえると、ある程度複雑なシステムを開発する組織であれば、次のようなアプローチが1つの最適解となり得ます。

  • メトリクスやトレースを活用し、システムで発生するイベントを可視化する
  • アプリケーションログには、相関分析に必要な各種IDとより深い洞察を得るために必要十分なデータを付与する
  • アプリケーションログは、サービスの処理単位で1回もしくはマイルストーンとなる最低限の回数記録する

最後に、近年ではさまざまなサービスやツールにおいて、ログをフィルタリングもしくはサンプリングしたり、情報を加工したりする機能もあります。ですが、そのようなしくみや設定の導入は、オペレーショナルコストを増やすことがあります。便利なツールを使うにしても、最も重要なのはアプリケーションにおける規律あるエンジニアリングであることは変わりません。

参考資料

おすすめ記事

記事・ニュース一覧