OpenTelemetryクライアント設計原則

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

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

このドキュメントは、使いやすく、サポートするすべての言語間で統一されており、かつ言語固有の表現力のために十分な柔軟性を持つOpenTelemetryクライアントを設計者が作成する上で役立つ、共通の原則を定義します。

OpenTelemetryクライアントは、標準で(out of the box)フル機能を提供し、拡張性を通じて革新と実験を可能にすることが期待されています。

OpenTelemetryの基本的なアーキテクチャを理解するため、まず概要を読んでください。

このドキュメントは、OpenTelemetryクライアントAPIの詳細や機能を説明しようとするものではありません。APIの仕様についてはAPI仕様を参照してください。

OpenTelemetryクライアントの作者への注記: OpenTelemetryの仕様書、APIおよびSDKの実装ガイドラインは策定中です。不完全な情報や欠落した情報、矛盾、一貫性のないスタイル、その他の不備に気づいた場合は、このリポジトリでissueを立てるか、Slackに投稿して仕様書の作者に知らせてください。仕様書の実装者であるみなさんは、仕様書をどのように改善できるかについて、貴重な知見をお持ちのことがよくあります。Specification SIGおよびTechnical Committeeのメンバーは、みなさんの意見を高く評価し、フィードバックを歓迎します。

要求事項

  1. OpenTelemetry APIは明確に定義され、実装から明確に分離されていなければなりません。これにより、エンドユーザーは実装を消費せずにAPIのみを消費できます(これが重要である理由については項目2と3を参照してください)。

  2. 自身のコードに計装を追加するサードパーティのライブラリやフレームワークは、OpenTelemetryクライアントのAPIのみに依存します。サードパーティのライブラリやフレームワークの開発者は、最終的なアプリケーションでOpenTelemetryのどの実装が使われるかを気にしませんし(そして知ることもできません)。このような明確な分離を可能にするため、OpenTelemetryのAPIとSDKのライブラリは独立したアーティファクトとして提供されなければなりません(MUST)。

  3. 最終的なアプリケーションの開発者が、通常はOpenTelemetry SDKの設定方法や使用する拡張機能を決定します。アプリケーションやそのライブラリがすでに計装されていても、開発者はOpenTelemetryの実装をまったく使わないという選択を自由に行えるべきです。その理由は、OpenTelemetryで計装されたサードパーティのライブラリやフレームワークが、OpenTelemetryを使いたくないアプリケーションでも完全に利用可能でなければならないという点にあります(これにより、フレームワーク開発者は自身のフレームワークの「計装済み」版と「計装なし」版を用意する必要がなくなります)。

  4. SDKは、バッチ処理やプロセス情報によるタグの拡充などの共通ロジックを実装する、ワイヤープロトコルに依存しない部分と、プロトコルに依存するテレメトリーエクスポーターとに明確に分離されなければなりません。テレメトリーエクスポーターは最小限の機能のみを持たなければならず、これによりベンダーは自社固有のプロトコルへのサポートを容易に追加できます。

  5. SDKの実装には、以下のエクスポーターを含めるべきです。

    • ログ、メトリクス、トレース
      • OTLP(OpenTelemetry Protocol)。
      • デバッグとテスト、および各種ログプロキシツールへの入力として使う標準出力(またはロギング)。
      • テレメトリーデータをローカルメモリに蓄積し、それを検査できるインメモリ(モック)エクスポーター(単体テストなどで有用)。
    • メトリクス
      • Prometheus。
    • トレース
      • Zipkin。

    注:これらの一部は複数のプロトコル(gRPC、Thriftなど)をサポートします。エクスポーターに実装すべきプロトコルの正確な一覧は今後決定されます。

    その他のベンダー固有のエクスポーター(ベンダー独自のプロトコルを実装するエクスポーター)は、OpenTelemetryクライアントに含めるべきではなく、別の場所に配置すべきです(ベンダー固有のエクスポーターを保管・保守する具体的な方法は今後定義されます)。

OpenTelemetryクライアントの汎用設計

以下は、OpenTelemetryクライアントの汎用的な設計です(矢印は呼び出しを示します)。

OpenTelemetry client Design Diagram

想定される使い方

OpenTelemetryクライアントは、パッケージと呼ばれる4種類の要素、すなわちAPIパッケージ、SDKパッケージ、セマンティック規約パッケージ、そしてプラグインパッケージ(Contribなど)から構成されます。APIとSDKをシグナル種別ごとに複数のパッケージへ分割するかどうか(例えばapi-trace用とapi-metric用、sdk-trace用とsdk-metric用に分けるなど)は、APIのアーティファクトとSDKのアーティファクトが分離されている限り、実装の詳細とみなされます。

OpenTelemetryで計装したいライブラリ、フレームワーク、アプリケーションは、APIパッケージのみに依存します。これらのサードパーティライブラリの開発者は、テレメトリーデータを生成するためにAPIを呼び出します。

OpenTelemetry APIで計装されたサードパーティライブラリを使うアプリケーションは、SDKをインストールしてテレメトリーデータを生成するかどうかを制御します。SDKがインストールされていない場合、API呼び出しはno-opとなり、オーバーヘッドを最小限にとどめるべきです。

テレメトリーを有効にするには、アプリケーションはOpenTelemetry SDKに依存しなければなりません。また、テレメトリーが正しく生成され、選択した分析ツールへ配信されるように、エクスポーターやその他のプラグインを設定しなければなりません。プラグインを有効化・設定する方法の詳細は言語ごとに異なります。

APIと最小実装

APIパッケージは自己完結した依存関係です。つまり、エンドユーザーのアプリケーションやサードパーティのライブラリがAPIパッケージのみに依存し、フルのSDK実装を組み込まない場合でも、アプリケーションは失敗せずにビルド・実行できます。ただし、テレメトリーデータが実際にテレメトリーバックエンドへ配信されることはありません。

この自己完結性は、次のようにして実現されます。

APIの依存関係には、APIの最小実装が含まれます。アプリケーションに他の実装が明示的に含まれない場合、テレメトリーデータは収集されません。この場合、有効なコンポーネントは次のようになります。

Minimal Operation Diagram

このAPIの最小実装から返される値が有効であり、呼び出し元に追加のチェックを要求しないことが重要です(例えばcreateSpan()メソッドは失敗すべきではなく、有効な非nullのSpanオブジェクトを返すべきです)。呼び出し元は、最小実装が有効になっているという事実を知る必要も気にする必要もないようにすべきです。これにより、計装対象のコード内でのボイラープレートやエラー処理を最小限に抑えられます。

また、最小実装によるパフォーマンスへの悪影響を可能な限り小さくすることも重要です。これにより、OpenTelemetryで計装されたサードパーティのフレームワークやライブラリは、OpenTelemetryを使いたくないそれらのライブラリの利用者に対しても、無視できる程度のオーバーヘッドしか課さなくなります。

SDKの実装

SDKの実装は、別個の(オプションの)依存関係です。SDKが組み込まれると、APIパッケージに含まれる最小実装が置き換えられます(具体的な置き換えの仕組みは言語に依存します)。

SDKは、API呼び出しをエクスポート可能な状態のテレメトリーデータへ変換するために必要なコア機能を実装します。SDKが有効な場合、OpenTelemetryのコンポーネントは次のようになります。

Full Operation Diagram

SDKはExporterインターフェースを定義します。テレメトリーデータをバックエンドへ送信する責務を持つ、プロトコル固有のエクスポーターは、このインターフェースを実装しなければなりません。

SDKには、必要に応じて組み合わせて追加機能を実現できる、オプションのヘルパーエクスポーターも含まれます。

ライブラリの設計者は、この汎用的な仕様に基づいて、言語固有のExporterインターフェースを定義する必要があります。

プロトコルエクスポーター

テレメトリーバックエンドのベンダーは、Exporterインターフェースを実装することが期待されます。Export()関数を通じて受け取ったデータは、ベンダー固有の方法でシリアライズされ、バックエンドへ送信されるべきです。

ベンダーは、プロトコル固有のエクスポーターをできるだけシンプルに保ち、キューイングやリトライといった望ましい追加機能は、SDKが提供するヘルパーを使って実現することが推奨されます。

エンドユーザーには、自身のアプリケーションにとって最も適切なキューイング、リトライ、タグ付け、バッチ処理の機能について、多くの決定を行える柔軟性が与えられるべきです。例えば、可用性が保証されないリモートバックエンドへテレメトリーデータを配信しなければならないアプリケーションでは、エンドユーザーは永続的なローカルキューと、失敗時に再送するExporterを選ぶことが考えられます。これに対して、ローカルで動作するAgentデーモンへテレメトリーを送信するアプリケーションでは、エンドユーザーはリトライやキューイングのないよりシンプルなエクスポート設定を好む場合があります。

SDK向けの追加のエクスポーターを別のライブラリとして提供する場合、そのライブラリ名には、各技術の命名規則に従って「OpenTelemetry」と「Exporter」という語をプレフィックスとして付けるべきです。

例を示します。

  • PythonとJava:opentelemetry-exporter-{vendor_name}
  • JavaScript:@opentelemetry/exporter-{vendor_name}

リソース検出

クラウドベンダーは、環境からリソース情報を検出するパッケージを提供することが推奨されます。これらはSDKの外部で実装されなければなりません(MUST)。詳細はリソースSDKを参照してください。

代替実装

エンドユーザーのアプリケーションは、代替実装に依存することを選ぶ場合があります。

SDKは、多くの実装で利用できる柔軟性と拡張性を提供します。代替実装を開発する前に、OpenTelemetryが提供する拡張ポイントを確認してください。

代替実装の使用例の一つが、自動テストです。自動テストの実行中に、モック実装を組み込むことができます。例えば、生成されたすべてのテレメトリーデータをメモリに保存し、それを検査する機能を提供できます。これにより、テストはテレメトリーが正しく生成されていることを検証できます。OpenTelemetryクライアントの作者は、こうしたモック実装を提供することが推奨されます。

SDK全体を入れ替える必要はなく、SDKとモックのExporterを使うことでもモックが可能である点に注意してください。

選択するモックの手法は、テストの目的や、テスト中にテレメトリーデータの経路のどの時点で介入するのが望ましいかによって決まります。

バージョンラベリング

APIパッケージとSDKパッケージは、セマンティックバージョニングによる番号付けを使わなければなりません。APIパッケージのバージョン番号とSDKパッケージのバージョン番号は分離されており、異なっていても構いません(さらに、両者ともそれらが実装する仕様書のバージョン番号とも異なっていて構いません)。APIパッケージとSDKパッケージは、それぞれ独自のバージョン番号を付けなければなりません(MUST)。

このようにバージョン番号を分離することで、OpenTelemetryクライアントの作者は、仕様書とバージョン番号を調整・一致させる必要なく、APIパッケージとSDKパッケージのリリースを独立して行えます。

APIパッケージとSDKパッケージのバージョン番号が分離されているため、APIパッケージとSDKパッケージのすべてのリリースは、それらが実装する仕様書のバージョン番号を明確に記載しなければなりません(MUST)。さらに、SDKパッケージの特定バージョンが特定バージョンのAPIパッケージとのみ互換性がある場合、この互換性情報もOpenTelemetryクライアントの作者によって公開されなければなりません。OpenTelemetryクライアントの作者は、この情報をリリースノートに含めなければなりません(MUST)。例えば、SDKパッケージのリリースノートには「SDK 0.3.4はAPI 0.1.0と併用し、OpenTelemetry Specification 0.1.0を実装する」のように記載する場合があります。

TODO:計装にOpenTelemetryを使うサードパーティライブラリの作者は、エンドユーザーが正しいSDKパッケージを見つけられるよう、どのように案内すべきか?

パフォーマンスとブロッキング

API実装が満たすべきパフォーマンスの期待値、その期待値を満たすための戦略、そして実装が高負荷時の挙動をどのように文書化すべきかについては、パフォーマンスとブロッキングの仕様を参照してください。

並行性とスレッド安全性

API実装が提供すべき並行性の安全性と、その文書化の方法については、各APIの仕様を参照してください。