OpenTelemetryのログ

この記事は英語の原文を日本語に翻訳したものです。原文: https://opentelemetry.io/docs/specs/otel/logs/

翻訳元: open-telemetry/opentelemetry-specification v1.60.0(コミット 29ae8c7

はじめに

すべてのテレメトリーシグナルの中で、おそらくログが最も大きな遺産を持っています。ほとんどのプログラミング言語には、組み込みのロギング機能や、広く使われている定評のあるロギングライブラリがあります。

メトリクスとトレースについては、OpenTelemetryは白紙から設計するアプローチを取り、新しいAPIを規定し、複数の言語でこのAPIの完全な実装を提供しています。

ログに対するOpenTelemetryのアプローチはやや異なります。ロギングの分野でOpenTelemetryが成功するには、既存のログとロギングライブラリの遺産を支援しつつ、可能な範囲でオブザーバビリティ全体との統合を改善する必要があります。

これがOpenTelemetryのログサポートの根底にある考え方です。既存のロギングソリューションを取り込み、OpenTelemetryが既存のロギングライブラリやログ収集・処理ソリューションとうまく連携するようにします。

非OpenTelemetryソリューションの限界

残念ながら、既存のロギングソリューションは他のオブザーバビリティシグナルとの統合が弱いのが現状です。ログは、トレーシングツールやモニタリングツールにおいて、利用可能ながらしばしば不完全な相関情報(時刻や発生元の属性など)を使ったリンクという形でしか対応されていません。属性はログ・トレース・メトリクスに異なる手段(例えば異なる収集エージェント)で付与されることが多いため、この相関は脆くなりがちです。ログの発生元や発生源(アプリケーションや、アプリケーションが実行されている場所・インフラストラクチャーなど)に関する情報を、トレースやメトリクスと統一的な形で含める標準化された方法はなく、すべてのテレメトリーデータを正確かつ確実に相関させることができません。

同様に、ログにはリクエストの実行コンテキストを伝搬・記録する標準化された方法がありません。分散システムでは、これによりシステムの異なるコンポーネントから収集されたログの集合がばらばらになってしまうことがよくあります。

これが、今日の典型的な非OpenTelemetryのオブザーバビリティ収集パイプラインの姿です。

個別収集の図

異なるライブラリと異なる収集エージェントが、異なるプロトコルとデータモデルを使い、テレメトリーデータが互いにうまく連携できないさまざまなバックエンドに行き着くことがよくあります。

OpenTelemetryのソリューション

分散トレーシングは、トレースコンテキスト伝搬という概念を導入しました。

しかし基本的には、ログが同じコンテキスト伝搬の概念を採用することを妨げるものは何もありません。記録されたログにトレースコンテキストの識別子(トレースIDやスパンID、ユーザー定義のバゲージなど)が含まれていれば、ログとトレースの間、さらには分散システムの異なるコンポーネントが発したログの間でも、はるかに豊かな相関が実現します。これにより、ログは分散システムにおいてはるかに価値の高いものになります。

これはオブザーバビリティツールにおける有望な進化の方向の一つです。ログとトレース・メトリクスの相関を標準化し、ログの分散コンテキスト伝搬のサポートを追加し、ログ・トレース・メトリクスの発生元帰属を統一することで、レガシーシステムと最新のシステムの両方において、オブザーバビリティ情報の個別および統合的な価値が高まります。これが、ログ・トレース・メトリクスの収集に関するOpenTelemetryのビジョンです。

統一収集の図

OpenTelemetryのデータモデルに準拠した形でログ・トレース・メトリクスを発行し、OpenTelemetry Collectorを通してデータを送信することで、統一的な方法でデータをエンリッチ・加工できます。例えば、CollectorはKubernetesのPodから来るすべてのテレメトリーデータに対して、Podを記述するいくつかの属性を、アプリケーション側で特別な対応をせずにk8sattributesprocessorを使って自動的に付与できます。特に重要なのは、このようなエンリッチメントが3つのシグナルすべてにおいて完全に統一されている点です。Collectorは、ログ・トレース・メトリクスが、それらの発生元であるKubernetes Podを記述する属性名と値を正確に同じ形で持つことを保証します。これにより、バックエンドでPodによるシグナルの正確かつ一意な相関が可能になります。

トレースとメトリクスについて、OpenTelemetryはアプリケーション開発者がトレースとメトリクスを発行するために使う新しいAPIを定義しています。

ログについては、同じ道を選びませんでした。ロギングの分野には、はるかに大きく多様な遺産があることを認識したからです。さまざまな言語に多数の既存のロギングライブラリがあり、それぞれが独自のAPIを持っています。多くのプログラミング言語には、特定のロギングライブラリを使うための確立された標準があります。例えばJavaの世界には、Log4jやLogbackのような、非常に人気があり広く使われているロギングライブラリがいくつも存在します。

特定のフォーマットでログを発行する既存の構築済みアプリケーションやシステムも数多く存在します。こうしたアプリケーションの運用者は、ログの発行方法についてまったく制御できないか、限られた制御しかできません。OpenTelemetryはこうしたログをサポートする必要があります。

以上のようなロギング分野の現状を踏まえ、次のアプローチを採用しました。

  • OpenTelemetryはログデータモデルを定義します。このデータモデルの目的は、LogRecordが何であるか、ロギングシステムによって記録・転送・保存・解釈されるべきデータは何かについて、共通の理解を持つことです。

  • 新しく設計されるロギングシステムは、OpenTelemetryのログデータモデルに従ってログを発行することが期待されます。詳細は後述します。

  • 既存のログフォーマットは、OpenTelemetryのログデータモデルに一意にマッピングできます。OpenTelemetry Collectorはこうしたログを読み取り、OpenTelemetryのログデータモデルに変換できます。

  • OpenTelemetryは、LogRecordを発行するためのログAPIを定義します。これは主に、既存のロギングライブラリとOpenTelemetryのログデータモデルの間を橋渡しするログアペンダーをライブラリ作者が構築するために設計されました。ログAPIはアプリケーションから直接使うこともでき、これは特に次の場合に重要です。

    • 計装ライブラリが特定のロギングライブラリへの結合を避けるため。
    • 構造化イベントの発行を、既存のロギングライブラリが構造化データやイベント名を指定できない場合でも、セマンティック規約に従って行うため。
    • 中間のロギングライブラリを介さずにログ発行を直接制御する必要があるシナリオのため。

    なお、既存のロギングライブラリは一般に、OpenTelemetryで定義されている機能よりもはるかに豊富な機能セットを提供しています。とはいえ、言語によっては直接使う際の開発者体験を高めるために、エルゴノミックなAPIを提供することもあります。

  • OpenTelemetryはAPISDK実装を定義しており、これによりLogRecordの処理エクスポートを設定できます。

このアプローチにより、OpenTelemetryは既存のシステムログやアプリケーションログを読み取れるようになり、新しく構築されるアプリケーションが豊かで構造化されたOpenTelemetry準拠のログを発行する手段を提供し、最終的にすべてのログが統一されたログデータモデルに従って表現され、バックエンドがそのモデルの上で動作できるようになります。

本ドキュメントの以降では、さまざまなログ発生源がどのように扱われるかをさらに詳しく議論しますが、まずログの相関という重要な概念をより詳しく説明する必要があります。

ログの相関

ログは、いくつかの軸で他のオブザーバビリティデータと相関させられます。

  • 実行時刻によるものです。ログ・トレース・メトリクスは、実行が行われた瞬間や時間範囲を記録できます。これは最も基本的な相関の形です。

  • 実行コンテキスト(トレースコンテキストとも呼ばれる)によるものです。スパンに実行コンテキスト(トレースID・スパンIDおよびユーザー定義のコンテキスト)を記録するのは標準的な手法です。OpenTelemetryは可能な限りこの手法をログにも拡張し、LogRecordにTraceIdSpanIdを含めます。これにより、同じ実行コンテキストに対応するログとトレースを直接相関させられます。また、特定のリクエスト実行に関与した分散システムの異なるコンポーネントからのログを相関させることもできます。

  • テレメトリーの発生元(リソースコンテキストとも呼ばれる)によるものです。OpenTelemetryのトレースとメトリクスには、発生元のリソースに関する情報が含まれます。この手法をログにも拡張するため、LogRecordにResourceを含めます。

この3つの相関は、強力なナビゲーション・フィルタリング・クエリ・分析機能の基盤となり得ます。OpenTelemetryは、こうした相関を可能にする形でログを記録・収集することを目指しています。

レガシーおよびモダンなログ発生源

レガシーおよびモダンなログ発生源にはいくつかの種類があることを区別することが重要です。第一に、これはログへのアクセス方法や収集方法に直接影響します。第二に、これらのログがどのように生成されるか、そしてログに含める情報を修正できるかについて、私たちが持つ制御の度合いは発生源ごとに異なります。

以下では、こうしたログのカテゴリーをいくつか挙げ、各カテゴリーについてオブザーバビリティソリューションでより良い体験を得るために何ができるかを説明します。

システムログ

これはオペレーティングシステムが生成するログで、私たちには制御できません。フォーマットを変更したり、含まれる情報に影響を与えたりすることはできません。システムフォーマットの例としては、SyslogやWindowsイベントログがあります。

システムログはホストレベル(物理・仮想・コンテナ化されたものいずれもあり得ます)で書き込まれ、あらかじめ定義されたフォーマットと内容を持ちます(アプリケーションも標準のシステムログにレコードを書き込める場合があります。このケースは以下のサードパーティアプリケーション節で扱います)。

システムログに記録されるシステム操作は、リクエストの実行結果である場合があります。しかしシステムログには、トレースコンテキストに関するデータがまったく含まれていないか、含まれていても非常に特殊な形式であることが多く、識別・解析・利用が難しいのが実情です。このため、システムログに対してトレースコンテキストの相関を行うことはほぼ不可能です。しかし、収集時に利用可能なホストに関する情報として、システムログをリソースコンテキストで自動的にエンリッチすることはできますし、そうすべきです。これにはホスト名、IPアドレス、コンテナ名やPod名などを含められます。この情報は、収集されたログデータのResourceフィールドに追加されるべきです。

OpenTelemetry Collectorはシステムログを読み取り(リンクは今後追加予定)、resourcedetectionプロセッサーを使ってリソース情報を自動的に付与できます。

インフラストラクチャーログ

これは、Kubernetesイベントのような各種インフラストラクチャーコンポーネントが生成するログです。システムログと同様に、インフラストラクチャーログにはトレースコンテキストがなく、ノード・Pod・コンテナなどに関するリソースコンテキストでエンリッチできます。

OpenTelemetry Collectorや他のエージェントを使って、一般的なインフラストラクチャーコントローラーからログをクエリできます。

サードパーティアプリケーションのログ

アプリケーションは通常、標準出力・ファイル・その他の専用メディア(アプリケーション向けのWindowsイベントログなど)にログを書き込みます。これらのログはさまざまなフォーマットで、次のような範囲にわたるバリエーションがあります。

  • 構造化データを自動的かつ信頼性の高い方法で解析する手段がない、自由形式のテキストフォーマット。

  • 構造化データを抽出するために解析できる、よりきちんと規定されカスタマイズも可能なフォーマット(ApacheログやRFC5424 Syslogなど)。

  • 明確に構造化されたフォーマット(明確に定義されたスキーマを持つJSONファイルやWindowsイベントログなど)。

収集システムは、よく使われるアプリケーションを検出し、これらのログを構造化フォーマットに変換できるパーサーを備える必要があります。システムログやインフラストラクチャーログと同様に、アプリケーションログもリクエストコンテキストを欠くことが多いものの、ホストやインフラストラクチャーを記述する属性、およびアプリケーションレベルの属性(アプリケーション名、バージョン、DBMSであればデータベース名など)でエンリッチできます。

OpenTelemetryは、Collectorのfilelogレシーバーを使ってアプリケーションログを収集することを推奨します。あるいは、FluentBitのような別のログ収集エージェントでログを収集し、OpenTelemetry Collectorへ送信して、そこでさらに処理・エンリッチすることもできます。

レガシーなファーストパーティアプリケーションのログ

これは自社内で作成されたアプリケーションです。ログ収集インフラストラクチャーの構築を担当する人々は、ログの書き込み方や含める情報を変更するために、こうしたアプリケーションを修正できる場合があります。例えば、アプリケーションのログフォーマッターを再設定してプレーンテキストの代わりにJSONを出力させ、それによってログ収集の信頼性を高めるといったことです。

こうしたアプリケーションへのより大きな変更は、開発者が手作業で行うこともできます。例えばすべてのログステートメントにトレースコンテキストを追加するといったことですが、必要な労力を考えると、これはほとんど行われないでしょう。

手作業による対応とは対照的に、アプリケーションが使っているロギングライブラリを変更して、すべてのログステートメントにトレースIDやスパンIDなどのトレースコンテキストを自動的に出力させる、完全または半自動の計装ソリューションを提供することで、より手間の少ない方法でアプリケーションログを「アップグレード」できる興味深い機会があります。トレースコンテキストは、W3C TraceContextのような標準準拠のリクエスト伝搬が使われていれば、受信するリクエストから自動的に抽出できます。さらに、アプリケーションから送出されるリクエストにも同じトレースコンテキストデータを注入すれば、アプリケーションを通したコンテキスト伝搬が実現し、この方法で計装できるすべてのアプリケーションから収集されるログに、完全なトレースコンテキストを持たせる機会が生まれます。

一部のロギングライブラリは、比較的容易にこの方法で拡張できるように設計されています。ライブラリ自体を変更する必要はなく、代わりにそうしたライブラリのために「ログアペンダー」や「ログブリッジ」コンポーネントを実装し、追加のLogRecordエンリッチメントをこれらのコンポーネントで実装できます。

これらのアプリケーションからログを収集する方法は、通常2つあります。

ファイルまたは標準出力ログ経由

最初の方法は、ログがファイルまたは標準出力に書き込まれることを前提に、ファイルログを読み取り、末尾追跡し、ログローテーションが使われている場合も正しく動作し、必要に応じてログを解析してより構造化されたフォーマットに変換する機能を要求します。解析には異なるパーサー種別のサポートが必要で、カスタムフォーマットを解析するための設定やカスタムパーサーの追加もできる必要があります。パーサーがサポートすべき一般的なフォーマットの例としては、CSV、Common Log Format、Labeled Tab-separated Values(LTSV)、キー・バリュー形式、JSONなどがあります。この方法をサポートするため、OpenTelemetryはOpenTelemetryCollectorを使ってログを収集することを推奨します。

アプリケーションからファイルログへの図

代わりに、Collectorに必要なファイル読み取り・解析機能がない場合は、FluentBitのような別のログ収集エージェントでログを収集し、OpenTelemetry Collectorへ送信することもできます。

アプリケーションからファイルログへの図

中間メディアを使う利点は、アプリケーションによるログの生成方法や書き込み先の変更が不要または最小限で済むことです。欠点は、しばしば煩雑になりがちなログファイルの読み取りと解析機能が必要になることです。出力フォーマットが明確に定義されていない場合、解析の信頼性が低くなることもあります。トレースコンテキストの記録と解析の詳細については、非OTLPログフォーマットにおけるトレースコンテキストを参照してください。

Collectorへの直接送信

2つ目の方法は、アプリケーションを修正して、ネットワークプロトコル(例えばOTLP)経由でログを出力するようにすることです。これを実現する最も簡便な方法は、よく使われるロギングライブラリにアドオンや拡張機能を提供することです。アドオンはこうしたネットワークプロトコル経由の送信を実装し、通常はロギングの送信先を変更するためにアプリケーションコードへの小さく局所的な変更を必要とします。

アプリケーションからCollectorへの図

アプリケーションログは、サードパーティアプリケーションの場合と同様にリソースコンテキストでもエンリッチされるため、すべてのコンテキストの軸で完全な相関情報を持つ可能性があります。

この方法の欠点は、ログをローカルファイルに置くことの単純さ(ログファイルをローカルで簡単に確認できる利点など)が失われることと、OpenTelemetryのロギングアプローチへの完全な移行が必要になることです。この方法は、ログの配送先がOpenTelemetryが送信可能なネットワークプロトコル経由でログを受け取れる場合にのみ機能します。

この方法の利点は、明確に定義された、正式で高度に構造化されたフォーマットでログを発行できることと、パーサーやログの末尾追跡・ローテーションに関連するすべての複雑さを排除できることです。また、ログ収集エージェントを使わずにログをロギングバックエンドへ直接送信できる可能性も生まれます。

これら2つの方法を実現するため、OpenTelemetryはAPISDKを提供しています。これらは既存のロギングライブラリと組み合わせて使うことで、発行されるログへトレースコンテキストを自動的に注入し、OTLP経由でログを送信する簡単な手段を提供します。各ログステートメントを変更する代わりに、ログアペンダーがこのAPIを使って既存のロギングライブラリからOpenTelemetryのデータモデルへログを橋渡しし、SDKがログの処理・エクスポート方法を制御します。アプリケーション開発者は、アプリケーション起動時にアペンダーとSDKを設定するだけで済みます。

新しいファーストパーティアプリケーションのログ

これはグリーンフィールドの開発です。OpenTelemetryは、こうしたアプリケーションからログ(トレースやメトリクスと合わせて)を発行する方法について推奨事項とベストプラクティスを提供します。

アプリケーションがログを発行するには、いくつかの選択肢があります。

  1. OpenTelemetryのログアペンダーを備えた既存のロギングライブラリを使う方法: 対応する言語やフレームワークでは、自動計装またはロギングライブラリの簡単な設定によってOpenTelemetryのログアペンダーを使うのが、コンテキストで拡充されたログを発行する最も簡単な方法です。前述したように、手動計装のケースをサポートするために、いくつかの人気のロギングライブラリへの拡張機能を提供しています。この拡張機能は、ログへのトレースコンテキストの付加をサポートし、テキストファイルとして表現する必要をなくして、OTLPプロトコル経由でバックエンドやCollectorへログを送信できるようにします。

  2. OpenTelemetryログAPIを直接使う方法: アプリケーションはログAPIを直接使って構造化されたログとイベントを発行できます。この方法は、セマンティック規約に従ったイベントの発行によく適しており、異なるシグナル間で使われる属性の再利用も容易にします。なお、言語によってはより便利なエルゴノミックなAPIを提供できます。

どちらのアプローチでも、発行されたログはアプリケーション固有のリソースコンテキスト(プロセスID、プログラミング言語、ロギングライブラリ名とバージョンなど)で自動的に拡充されます。これらのログでは、すべてのコンテキストの軸にわたる完全な相関が利用可能になります。

これが、新しいアプリケーションがOpenTelemetryのAPI・SDKと既存のロギングライブラリを使う典型的な様子です。

アプリケーション・API・SDKの図

OpenTelemetry Collector

本仕様書に従ったログ収集を実現するため、OpenTelemetry Collectorを使います。

ログ収集を実現するため、次の機能があります。

  • ログデータモデルに基づいたログデータ型とログパイプラインのサポート。ログデータを操作できるattributesprocessorなどのプロセッサーが含まれます。

  • テキストファイルからログを読み取り、ファイルを末尾追跡し、一般的なログローテーションの仕組みを理解し、ログファイルの作成に対してディレクトリを監視し、ファイル位置をチェックポイントしてそこから再開する能力。この能力は、Collectorのfilelogレシーバー、または外部で動作するエージェント(FluentBitなど)を使って実装されます。

  • 一般的なテキストフォーマットでログを解析し、エンドユーザーが解析フォーマットをカスタマイズしたり必要に応じてカスタムパーサーを追加したりできる能力。Collectorのパーサー、または外部エージェントでの解析がこれに使われます。

  • Syslogのような一般的なログ向けネットワークプロトコル経由でログを受信し、本仕様書で定義されたセマンティック規約に従って解釈する能力。FluentBitや類似のエージェントがこれに使われます。この機能の一部は、時間の経過とともにCollectorへ直接移行される可能性があります。

  • Syslogのような一般的なログ向けネットワークプロトコル、またはベンダー固有のログフォーマット経由でログを送信する能力。Collectorには、この機能を直接実装するエクスポーターが含まれています。

既存のロギングの自動計装

最も一般的なロギングライブラリの多くに対して自動計装を提供できます。自動計装されたログステートメントは次のことを行います。

  • 受信したトレースコンテキストを読み取ります(これは自動計装ライブラリが行うより広範な計装の一部です)。

  • ロギングライブラリを設定して、リクエストコンテキストのトレースIDおよびスパンIDフィールドをロギングコンテキストとして使い、記録されるすべてのステートメントに自動的に含めます。

これは特定の言語(例えばJava)で実現可能であり、これを行う既存のオープンソースライブラリを再利用できます。

さらなる任意の変更として、ファイルや標準出力への書き込みに加えて、あるいはその代わりに、OTLP経由でバックエンドへログを直接送信するようにロガーを自動計装することも考えられます。

仕様

参考文献