OTEP-0143: OpenTelemetryクライアントにおけるバージョニングと安定性
OpenTelemetryは、厳格な互換性要件を持つ大規模なプロジェクトです。 この提案では、OpenTelemetryクライアントが提供する安定性の保証を定義し、それらの要件をどのように満たすかを定めるバージョニングとライフサイクルの提案を示します。
各言語の実装は、言語やパッケージマネージャーの慣習が大きく干渉しない限り、この提案に正確に従うことが期待されます。 実装は、この言語横断的な提案を踏まえて、これらの要件をどのように満たすかを詳述した言語固有の提案を作成しなければなりません。
注記: このドキュメントでは、「OpenTelemetry」という用語は特にOpenTelemetryクライアントを指します。 仕様書やCollectorを指すものではありません。
デザインゴール
エンドユーザーが最新リリースに追従し続けられるようにする。 すべてのユーザーがOpenTelemetryの最新バージョンに追従し続けられることを望んでいます。 古いバージョンに取り残されるような、いかなる種類のサポートの断絶も生み出したくありません。 コンパイルエラーやランタイムエラーを発生させることなく、常にOpenTelemetryの最新のマイナーバージョンにアップグレードできなければなりません。
異なるバージョンのOpenTelemetryに依存するパッケージ間で依存関係の競合を発生させない。安定した公開APIの破壊を避ける。 後方互換性は厳格な要件です。 計装APIは決してバージョンの競合を発生させてはなりません。 そうでなければ、OpenTelemetryをWebフレームワークのような広く共有されるライブラリに組み込むことができなくなってしまいます。 古いバージョンのAPIに対して書かれたコードは、それより新しいすべてのバージョンのAPIで動作しなければなりません。 APIの推移的な依存関係がバージョンの競合を発生させてはなりません。 OpenTelemetry APIは、何らかのライブラリやアプリケーションが「foo」の異なる非互換なバージョンを必要とする可能性が少しでもあるなら、「foo」に依存することはできません。 OpenTelemetryを使用するライブラリが、OpenTelemetryの依存関係の一つにおけるバージョンの競合が原因で、他のライブラリと非互換になることは決してあってはなりません。 理論的にはAPIを非推奨にして最終的に削除することは可能ですが、これは数年単位で計測されるプロセスであり、私たちにはそれを行う計画はありません。
同一リリース内で複数レベルのパッケージ安定性を許容する。 安定したAPIと並行して、新しい実験的なAPIを開発するための明確なプロセスをメンテナーに提供します。 同一リリース内の異なるパッケージが、異なるレベルの安定性を持つことがあります。 つまり、今日安定したトレーシングをリリースしたい実装は、メトリクスAPIへの破壊的変更がトレースAPIパッケージを不安定化させないよう、実験的なメトリクスが確実に切り分けられていることを確認しなければならないということです。
関連するアーキテクチャ

もっとも高いアーキテクチャレベルでは、OpenTelemetryはシグナルという単位で構成されています。 それぞれのシグナルは、特定の形式のオブザーバビリティを提供します。 たとえば、トレーシング、メトリクス、バゲッジは3つの独立したシグナルです。 シグナル同士はコンテキスト伝搬という共通のサブシステムを共有していますが、それぞれが独立して機能します。
各シグナルは、ソフトウェアが自身を記述するための仕組みを提供します。 APIハンドラーやデータベースクライアントのようなコードベースは、自身を記述するためにさまざまなシグナルに依存します。 その後、OpenTelemetryの計装コードは、そのコードベース内の他のコードに混ぜ込まれます。 これによってOpenTelemetryは横断的関心事(cross-cutting concern)、すなわち価値を提供するために多くの他のソフトウェアに混ぜ込まなければならないソフトウェアになります。 横断的関心事は、その性質上、関心の分離という中心的な設計原則に反します。 その結果、OpenTelemetryは、これらの横断的なAPIに依存するコードベースに問題を生じさせないよう、特別な注意を払う必要があります。
OpenTelemetryは、各シグナルのうち横断的関心事としてインポートしなければならない部分を、独立して管理できる部分から分離するように設計されています。 また、OpenTelemetryは拡張可能なフレームワークとなるようにも設計されています。 これらの目標を達成するため、各シグナルは4種類のパッケージから構成されます。
API - APIパッケージは、計装に使用される横断的な公開インターフェース群から構成されます。 サードパーティのライブラリやアプリケーションコードが依存するOpenTelemetryの部分は、すべてAPIの一部とみなされます。 異なるレベルの安定性を管理するため、各シグナルは独立したAPIパッケージを持ちます。 これらの個々のAPIは、利便性のために共有のグローバルAPIへとまとめられることもあります。
SDK - APIの実装です。 SDKはアプリケーションのオーナーによって管理されます。 SDKには、横断的関心事とはみなされないため、APIパッケージの一部とはみなされない追加の公開インターフェースが含まれることに注意してください。 これらの公開インターフェースは、コンストラクターとプラグインインターフェースとして定義されます。 プラグインインターフェースの例には、SpanProcessor、Exporter、Samplerインターフェースがあります。 コンストラクターの例には、設定オブジェクト、環境変数、SDKビルダーがあります。 アプリケーションのオーナーはSDKのコンストラクターとやりとりし、プラグインの作者はSDKのプラグインインターフェースとやりとりします。 計装の作者は、いかなる種類のSDKパッケージも直接参照してはならず、APIのみを参照しなければなりません。
セマンティック規約 - シグナルが観測する一般的な概念や操作を記述する属性を定義するスキーマです。 APIやSDKとは異なり、すべてのシグナルの安定した規約は、異なるシグナル間でしばしば有用であるため、同一のパッケージに配置されることに注意してください。
Contrib – APIやSDKのインターフェースを利用するものの、OTelを実行するために必要なコアパッケージの一部ではないプラグインや計装です。 「contrib」という用語は、SDKの外側でOpenTelemetry組織によってメンテナンスされるプラグインと計装を特に指します。 どこか他の場所でホストされているサードパーティのプラグインや、OTLP ExporterやTraceContext Propagatorのような、SDKリリースの一部として必須とされるコアプラグインを指すものではありません。 API ContribはAPIのみに依存するパッケージを指し、SDK ContribはSDKにも依存するパッケージを指します。
シグナルのライフサイクル
OpenTelemetryはシグナルを中心に構成されています。 各シグナルは、一貫した独立した機能の集合を表します。 各シグナルはライフサイクルに従います。

ライフサイクルの段階
実験的(Experimental) – 破壊的変更やパフォーマンスの問題が発生する可能性があります。 コンポーネントは機能として完成していないかもしれません。 実験は破棄されることもあります。
安定(Stable) – コンポーネントの種類(API、SDK、規約、Contrib)に基づく安定性の保証が適用されます。 これらのパッケージに対して、長期的な依存を取ることができるようになります。
非推奨(Deprecated) – このシグナルは置き換えられていますが、同じ安定性の保証を引き続き保持しています。
削除(Removed) - 非推奨のシグナルはもはやサポートされず、削除されます。
すべてのシグナルのコンポーネントは、一括で安定化することも、次の順序で1つずつ安定化することもできます。 API、セマンティック規約、API Contrib、SDK、SDK Contrib、という順序です。
実験的から安定へ、安定から非推奨へと移行する際、パッケージはユーザーによるインポートのされ方を移動させたり、他の形で壊したりするべきではありません。 「experimental」というディレクトリ名やパッケージのサフィックスを使用しないでください。
オプションとして、パッケージのバージョン番号には、安定パッケージと実験的パッケージを区別するために、-alpha、-beta、-rc、-experimentalなどのサフィックスを含めてもかまいません(MAY)。
安定性
シグナルコンポーネントが一度安定としてマークされると、そのシグナルの存在が終わるまで以下のルールが適用されます。
APIの安定性 - メジャーバージョン番号がインクリメントされない限り、APIへの後方非互換な変更は許可されません。 既存のすべてのAPI呼び出しは、同じメジャーバージョンのすべての将来のマイナーバージョンに対して、コンパイルおよび動作し続けなければなりません。 APIのABI互換性は、言語ごとに個別に提供されることがあります。
SDKの安定性 - SDKの公開部分は後方互換性を維持しなければなりません。 これには2つのカテゴリーがあります。プラグインインターフェースとコンストラクターです。 プラグインの例には、SpanProcessor、Exporter、Samplerインターフェースがあります。 コンストラクターの例には、設定オブジェクト、環境変数、SDKビルダーがあります。
SDKのプラグインインターフェースとコンストラクターのABI互換性は、言語ごとに個別に提供されることがあります。
セマンティック規約の安定性 - セマンティック規約は、一度安定になると削除できません。 古い規約の利用を置き換えるために新しい規約を追加することはできますが、古い規約が削除されることはなく、新しい規約を優先して非推奨としてマークされるだけです。
Contribの安定性 - プラグインと計装は最新の状態に保たれ、APIの最新リリースと同時に(あるいはその直後に)リリースされます。 その目的は、ユーザーが最新バージョンのOpenTelemetryにアップデートでき、依存しているプラグインによって足止めされないようにすることです。
contribパッケージの公開部分(コンストラクター、設定、インターフェース)は後方互換性を維持しなければなりません。 contribパッケージのABI互換性は、言語ごとに個別に提供されることがあります。
contribの計装によって生成されるテレメトリーも、アラートやダッシュボードを壊さないよう、安定していて後方互換性を保たなければなりません。 つまり、既存のデータはメジャーバージョンの引き上げなしに変更・削除されることはないということです。 データを追加することはできます。 これはスパン、メトリクス、リソース、属性、イベント、その他OpenTelemetryが送出するあらゆるデータ型に適用されます。
非推奨化
理論上、シグナルは置き換え可能です。 これが起きた場合、それらは非推奨としてマークされます。
コードは、置き換えとなるものが安定になったときにのみ非推奨としてマークされます。 非推奨のコードは、安定コードと同じサポート保証に引き続き従います。 非推奨のAPIは、安定していて後方互換性を持ち続けます。
削除
パッケージは、リリースから削除されることによって終了(end-of-life)します。 その際、リリースはメジャーバージョンを引き上げます。
現時点で、シグナルを非推奨にしたり、v1.0を超えるメジャーバージョンを作成したりする計画はありません。
念のため補足すると、実際にv2.0に移行してサポートを打ち切ることなく、既存の種類のシグナルに対して新しい後方非互換なバージョンを作成することは依然として可能です。 説明させてください。
新しくより優れたトレーシングAPIを開発するとします。仮にこれをAwesomeTraceと呼びましょう。 私たちは現在のトレーシングAPIをAwesomeTraceへと変化させることは決してしません。 代わりに、AwesomeTraceは、現在のトレーシングシグナルと共存し相互運用する、まったく新しいシグナルとして追加されます。 これにより、AwesomeTraceの追加はマイナーバージョンの引き上げとなり、v2.0にはなりません。 v2.0は、現在のトレーシングのサポート終了を意味するものであり、AwesomeTraceの追加を意味するものではありません。 そして、できることなら、そのサポートを終了させたくはありません。
これは実際、理論上の例ではありません。 OpenTelemetryはすでにOpenTelemetryとOpenTracingという2つのトレーシングAPIをサポートしています。 私たちは新しいトレーシングAPIを発明しましたが、古いものも引き続きサポートしています。
バージョン番号
OpenTelemetryはSemVer 2.0の規約に、以下の点を除いて従います。
OpenTelemetryクライアントは、API、セマンティック規約、SDK、Contribという4つのコンポーネントを持ちます。
バージョニングの目的上、Contribを除くすべてのコンポーネント内のコードは、あたかも単一のパッケージであるかのように扱われ、同じバージョン番号でバージョニングされます。 Contribは個別にバージョニングされるパッケージの集合となることがあります。
- API内のすべてのパッケージは同じバージョン番号を共有します。 すべてのシグナルのAPIパッケージは、全シグナルを通じて一緒にバージョニングされます。 シグナルごとに個別のバージョン番号を持つことはありません。 そのバージョン番号でラベル付けされたAPIリリースに含まれるすべてのシグナルに適用される、単一のバージョン番号が存在します。
- SDK内のすべてのパッケージは同じバージョン番号を共有します。 すべてのシグナルのSDKパッケージは、全シグナルを通じて一緒にバージョニングされます。 そのバージョン番号でラベル付けされたSDKリリースに含まれるすべてのシグナルに適用される、単一のバージョン番号が存在します。
- すべてのセマンティック規約は、単一のバージョン番号を持つ単一のパッケージに含まれます。
- 各contribパッケージは独自のバージョンを持ちます。
- API、SDK、セマンティック規約、contribの各コンポーネントは、バージョン番号を共有する必要はありません。
たとえば、
opentelemetry-python-apiの最新バージョンがv1.2.3である一方で、opentelemetry-python-sdkの最新バージョンがv2.3.1であってもかまいません。 - 異なる言語実装のバージョン番号が一致している必要はありません。
たとえば、
opentelemetry-java-apiがv1.3.2であるときに、opentelemetry-python-apiがv1.2.8であってもかまいません。 - 言語実装は、それが実装している仕様書のバージョンと一致している必要はありません。
たとえば、
opentelemetry-python-apiのv1.8.2が、仕様書のv1.1.1を実装していてもかまいません。
例外: 言語によっては、パッケージマネージャーが0.Xより高いバージョンを持つ実験的なパッケージにうまく対応できないことがあります。 このような場合、言語固有の回避策が必要です。 Go、Ruby、JavaScriptがその例です。
メジャーバージョンの引き上げ メジャーバージョンの引き上げは、安定したインターフェースへの破壊的変更、または非推奨シグナルの削除があった場合にのみ発生します。
OpenTelemetryは長期サポートを重視します。 最初のパッケージ群が安定であると宣言された時点で、v1.0にバージョニングすることが期待されています。 その後、OpenTelemetryは何年もの間v1.0のままであり続けます。 現時点でOpenTelemetryのv2.0の計画はありません。 メトリクスやログのような追加の安定パッケージは、マイナーバージョンの引き上げとして追加されます。
マイナーバージョンの引き上げ OpenTelemetryへのほとんどの変更は、マイナーバージョンの引き上げをもたらします。
- いずれかのコンポーネントへの後方互換性のある新機能の追加。
- SDKの内部コンポーネントへの破壊的変更。
- 実験的シグナルへの破壊的変更。
- 新しい実験的パッケージの追加。
- 実験的パッケージが安定になること。
パッチバージョンの引き上げ パッチバージョンでは、再コンパイルを必要としたり、アプリケーションコードを壊す可能性のある変更は行いません。 以下はパッチ修正の例です。
- 上記のルールでマイナーバージョンの引き上げを必要としないバグ修正。
- セキュリティ修正。
- ドキュメント。
現時点で、OpenTelemetryにはバグ修正やセキュリティ修正を以前のマイナーバージョンにバックポートする計画はありません(NOT)。 セキュリティ修正とバグ修正は、最新のマイナーバージョンにのみ適用されます。 私たちは、エンドユーザーがOpenTelemetryの最新バージョンに追従し続けられるようにすることに尽力しています。
長期サポート

APIサポート
APIのメジャーバージョンは、次のメジャーAPIバージョンのリリース後、最低3年間サポートされます。 サポートは以下の領域を対象とします。
上記で定義されたAPIの安定性が維持されます。
APIの最後のメジャーバージョンをサポートするバージョンのSDKは、この期間中引き続きメンテナンスされます。 バグ修正とセキュリティ修正はバックポートされます。 追加の機能開発は保証されません。
APIがバージョニングされた時点で利用可能だったcontribパッケージは、この期間中引き続きメンテナンスされます。 バグ修正とセキュリティ修正はバックポートされます。 追加の機能開発は保証されません。
SDKサポート
上記で定義されたSDKの安定性は、次のメジャーSDKバージョンのリリース後、最低1年間維持されます。
Contribサポート
上記で定義されたContribの安定性は、contribパッケージの次のメジャーバージョンのリリース後、最低1年間維持されます。
OpenTelemetry GA
「OpenTelemetry GA」という用語は、少なくとも3つの言語で、トレーシングとメトリクスの両方の安定バージョンがリリースされた時点を指します。