# Propagators API

> Source: https://www.ymotongpoo.com/works/otel-specs-ja/spec/context/api-propagators/


**ステータス**: 特記のない限り[Stable](../../document-status/)

## Overview

横断的関心事は、`Propagator`を使って自身の状態を次のプロセスに送信します。`Propagator`とは、アプリケーション間でやり取りされるメッセージに対してコンテキストデータを読み書きするために使われるオブジェクトとして定義されます。各関心事は、サポートされる`Propagator`の型ごとに`Propagator`の集合を作成します。

`Propagator`は、それぞれの横断的関心事（トレースや`Baggage`など）についてデータを注入・抽出するために`Context`を活用します。

伝搬は通常、ライブラリ固有のリクエストインターセプターと`Propagators`が連携することで実装されます。インターセプターが受信・送信リクエストを検出し、それぞれ`Propagator`のextract操作とinject操作を使います。

Propagators APIは、計装ライブラリを書くユーザーによって活用されることが想定されています。

## Propagator Types

`Propagator`の型は、特定のトランスポートによって課される制約を定義し、プロセス境界を越えてインバンドのコンテキストデータを伝搬するために、あるデータ型に束縛されます。

Propagators APIは現在、1つの`Propagator`型を定義しています。

- `TextMapPropagator`は、文字列のキーと値の組としてキャリアへ値を注入し、キャリアから値を抽出する型です。

### Carrier

キャリアとは、`Propagator`が値を読み書きするために使う媒体です。それぞれの特定の`Propagator`型は、文字列マップやバイト配列といった、期待されるキャリアの型を定義します。

[Inject](#inject)で使われるキャリアはミュータブルであることが期待されます。

### Operations

`Propagator`は、値をキャリアに書き込み、キャリアから値を読み込むために、それぞれ`Inject`操作と`Extract`操作をMUST定義するものとします。それぞれの`Propagator`型は、特定のキャリア型をMUST定義するものとし、追加のパラメータをMAY定義してもよいものとします。

#### Inject

値をキャリアに注入します。例えばHTTPリクエストのヘッダーへの注入です。

必須の引数:

- `Context`。Propagatorは、`SpanContext`、`Baggage`、その他の横断的関心事のコンテキストといった適切な値を、まず`Context`からMUST取得するものとします。
- 伝搬フィールドを保持するキャリア。例えば送信メッセージやHTTPリクエストです。

#### Extract

受信リクエストから値を抽出します。例えばHTTPリクエストのヘッダーからの抽出です。

キャリアから値をパースできない場合、その横断的関心事について、実装は例外をMUST NOTスローするものとし、既存の有効な値を保持するために`Context`へ新しい値をMUST NOT保存するものとします。

必須の引数:

- `Context`
- 伝搬フィールドを保持するキャリア。例えば受信メッセージやHTTPリクエストです。

引数として渡された`Context`から派生した新しい`Context`を返します。この新しい`Context`は抽出された値を含み、それは`SpanContext`、`Baggage`、その他の横断的関心事のコンテキストになり得ます。

## TextMap Propagator

`TextMapPropagator`は、プロセス境界をインバンドで越えて移動するキャリアに対して、横断的関心事の値を文字列のキーと値の組として注入・抽出を行います。

伝搬されるデータのキャリアは、クライアント側（インジェクター）とサーバー側（エクストラクター）の両方で、通常はHTTPリクエストです。

互換性を高めるため、キーと値の組は、[RFC 9110](https://datatracker.ietf.org/doc/html/rfc9110/#name-fields)に準拠した有効なHTTPヘッダーフィールドを構成するUS-ASCII文字のみでMUST構成されるものとします。

`Getter`と`Setter`は、それぞれ抽出と注入のために使われる任意のヘルパーコンポーネントであり、キャリアをラップする追加のインターフェース実装オブジェクトを必要とせずにその内容にアクセスできるようにするために、実行時のメモリー割り当てを避ける目的でキャリアとは別のオブジェクトとして定義されます。

`Getter`と`Setter`はステートレスでなければならず（MUST）、実行時のメモリー割り当てを効果的に避けるために定数として保存できなければなりません（MUST）。

### Fields

事前に定義された伝搬フィールドです。キャリアが再利用される場合、[Inject](#inject)を呼び出す前にここにあるフィールドを削除すべきです（should）。

フィールドは、キャリア内の形式固有のコンポーネントを識別する文字列キーとして定義されます。

例えば、キャリアが使い捨てまたは不変のリクエストオブジェクトである場合、以前に設定されたことがありえないため、フィールドをクリアする必要はありません。ミュータブルでリトライ可能なオブジェクトである場合、後続の呼び出しではまずこれらのフィールドをクリアすべきです。

これは以下のような用途で使われます。

- gRPC Metadataのようなシステムにおいてフィールドの事前割り当てを可能にする
- イテレーターの単一パスの走査を可能にする

`TextMapPropagator`によって使われるフィールドの一覧を返します。

一部の`Propagator`は、返される値に加えて、可変の名前を持つ追加のフィールドを定義する場合があることに注意してください。特定のキャリアオブジェクトに対するフィールドの完全な一覧を取得するには、[Keys](#keys)操作を使ってください。

### TextMap Inject

値をキャリアに注入します。必須の引数は、基本の[Inject](#inject)操作で定義されたものと同じです。

任意の引数:

- 伝搬用のキーと値の組を設定する`Setter`。Propagatorは、複数の組を設定するためにこれを複数回呼び出してもよいです（MAY）。これは、キャリアへのデータの注入を助けるために言語が自由に定義できる追加の引数です。

#### Setter argument

Setterは、指定されたフィールドに値を設定する`Inject`の引数です。

`Setter`は、`TextMapPropagator`が伝搬対象のフィールドをキャリアに設定できるようにします。

これを実装する1つの方法は、以下に説明する`Set`メソッドを持つ`Setter`クラスです。

##### Set

伝搬対象のフィールドを、指定された値で置き換えます。

必須の引数:

- 伝搬フィールドを保持するキャリア。例えば送信メッセージやHTTPリクエストです。
- フィールドのキー
- フィールドの値

使用するプロトコルが大文字・小文字を区別しない場合、実装は大文字・小文字を保持すべきです（SHOULD）（例えば`Content-Type`を`content-type`に変換すべきではありません）。それ以外の場合は大文字・小文字を保持しなければなりません（MUST）。

### TextMap Extract

受信リクエストから値を抽出します。必須の引数は、基本の[Extract](#extract)操作で定義されたものと同じです。

任意の引数:

- 取得対象の伝搬キーごとに呼び出される`Getter`。これは、キャリアからのデータの抽出を助けるために言語が自由に定義できる追加の引数です。

引数として渡された`Context`から派生した新しい`Context`を返します。

#### Getter argument

Getterは、指定されたフィールドから値を取得する`Extract`の引数です。

`Getter`は、`TextMapPropagator`が伝搬されたフィールドをキャリアから読み取れるようにします。

これを実装する1つの方法は、以下に説明する`Get`、`Keys`、`GetAll`メソッドを持つ`Getter`クラスです。言語によっては、代替の実装を選び、対応するメソッドをデリゲートなど他の方法で公開しても構いません。

##### Keys

`Keys`関数は、キャリア内のすべてのキーの一覧をMUST返すものとします。

必須の引数:

- 伝搬フィールドのキャリア。例えばHTTPリクエストです。

`Keys`関数は、指定されたキャリア内のすべてのキーを走査するために、可変のキー名を使う`Propagator`によって呼び出されることがあります。

例えば、[B3 Propagation: Multiple Headers](https://github.com/openzipkin/b3-propagation/blob/master/README.md#multiple-headers)で定義されているように、`X-B3-${name}`というパターンに従うすべてのキーを検出するために使えます。

##### Get

Get関数は、指定された伝搬キーの最初の値をMUST返すものとし、キーが存在しない場合はnullを返すものとします。

必須の引数:

- 伝搬フィールドのキャリア。例えばHTTPリクエストです。
- フィールドのキー

Get関数は、大文字・小文字の区別の処理を担います。GetterがHTTPリクエストオブジェクトに対応することを意図している場合、Getterは大文字・小文字を区別しないものでなければなりません（MUST）。

##### GetAll

多くの言語実装では、`GetAll`関数は`Getter`の安定版リリースの後に追加されます。これらの言語では、`Getter`の実装に`GetAll`を含めることを要求すると、以前は正しく動作していた計装が失敗するという破壊的変更になります。言語実装は、これを認識し、後方互換性を保つ方法で`GetAll`を追加すべきです。例えば、Getに基づくデフォルトの`GetAll`実装を提供する方法や、拡張された`Getter`型を作成する方法があります。

明示的に実装された場合、`GetAll`関数は指定された伝搬キーのすべての値をMUST返すものとします。キャリア内に現れる順序と同じ順序で返すべきです（SHOULD）。キーが存在しない場合、空のコレクションを返すべきです（SHOULD）。

必須の引数:

- 伝搬フィールドのキャリア。例えばHTTPリクエストです。
- フィールドのキー

`GetAll`関数は、大文字・小文字の区別の処理を担います。GetterがHTTPリクエストオブジェクトに対応することを意図している場合、Getterは大文字・小文字を区別しないものでなければなりません（MUST）。

## Injectors and Extractors as Separate Interfaces

言語は、`Propagator`型を、`Inject`と`Extract`メソッドを公開する単一のオブジェクトとして実装することも、責任をさらに個々の`Injector`と`Extractor`に分割することもできます。`Propagator`は、個々の`Injector`と`Extractors`を組み合わせて実装できます。

## Composite Propagator

実装は、異なる横断的関心事から得られる複数の`Propagator`をグループ化し、単一のエンティティとして活用できる機構をMUST提供するものとします。

複合Propagatorは、Propagatorのリストから、あるいはInjectorとExtractorのリストから構築できます。結果として得られる複合`Propagator`は、指定された順序で`Propagator`、`Injector`、`Extractor`を呼び出します。

各複合`Propagator`は、`TextMapPropagator`のような特定の`Propagator`型を実装します。異なる`Propagator`型は異なるデータ型を操作する可能性が高いためです。

以下の操作を実現するための関数がMUST存在するものとします。

- 複合Propagatorの作成
- 複合Propagatorからの抽出
- 複合Propagatorへの注入

### Create a Composite Propagator

必須の引数:

- `Propagator`のリスト、または`Injector`と`Extractor`のリスト

指定された`Propagator`を持つ新しい複合`Propagator`を返します。

### Composite Extract

必須の引数:

- `Context`
- 伝搬フィールドを保持するキャリア

`TextMapPropagator`の`Extract`実装が任意の`Getter`引数を受け付ける場合、以下の引数はREQUIREDであり、それ以外の場合はOPTIONALです。

- 取得対象の伝搬キーごとに呼び出される`Getter`のインスタンス

### Composite Inject

必須の引数:

- `Context`
- 伝搬フィールドを保持するキャリア

`TextMapPropagator`の`Inject`実装が任意の`Setter`引数を受け付ける場合、以下の引数はREQUIREDであり、それ以外の場合はOPTIONALです。

- 伝搬用のキーと値の組を設定する`Setter`。Propagatorは、複数の組を設定するためにこれを複数回呼び出してもよいです（MAY）。

## Global Propagators

OpenTelemetry APIは、サポートされる`Propagator`の型ごとにpropagatorを取得する方法をMUST提供するものとします。計装ライブラリは、すべてのリモート呼び出しでコンテキストを抽出・注入するためにpropagatorを呼び出すべきです（SHOULD）。Propagatorは、言語によって様々な依存性注入の手法を使って設定されたり、グローバルなアクセサーとして利用可能になったりすることがあります（MAY）。

**注:** これは推奨されない方法ですが、一部の計装ライブラリは独自のコンテキスト伝搬プロトコルを使う場合や、特定のプロトコルにハードコードされている場合があります。そのような場合、計装ライブラリは、API提供のpropagatorを使わずに、コンテキストの抽出と注入のロジックをハードコードすることを選んでも構いません（MAY）。

OpenTelemetry APIは、明示的に設定されない限りno-op propagatorをMUST使用するものとします。コンテキスト伝搬は、トレース・メトリクス・ロギングなど様々なテレメトリーシグナルに対して使われる可能性があります。したがって、コンテキスト伝搬はそれぞれ独立に有効化MAYされてもよいものとします。例えば、Span exporterが未設定のままであっても、ログやメトリクスをエンリッチするためにトレースコンテキストの伝搬が設定されることがあります。

ASP.NETのようなプラットフォームは、すぐに使えるpropagatorを事前設定していることがあります。事前設定されている場合、`Propagator`は、W3C Trace Context PropagatorとBaggage `Propagator`（[Baggage API](../../baggage/api/#propagation)で規定されているもの）を含む複合`Propagator`にデフォルトで設定すべきです（SHOULD）。これらのプラットフォームは、事前設定されたpropagatorを無効化または上書きできるようにもMUST許容するものとします。

### Get Global Propagator

このメソッドは、サポートされる`Propagator`の型ごとにMUST存在するものとします。

グローバルな`Propagator`を返します。通常これは複合インスタンスになります。

### Set Global Propagator

このメソッドは、サポートされる`Propagator`の型ごとにMUST存在するものとします。

グローバルな`Propagator`インスタンスを設定します。

必須のパラメータ:

- `Propagator`。通常これは複合インスタンスになります。

## Propagators Distribution

OpenTelemetry organizationによってMUST保守され、OpenTelemetryの[Core packages](https://opentelemetry.io/docs/specs/otel/overview/#core-packages)としてMUST配布されるべきpropagatorの公式な一覧です。

* [W3C TraceContext](https://www.w3.org/TR/trace-context/)。OpenTelemetry APIの一部として配布されてもMAY構いません。
* [W3C Baggage](https://www.w3.org/TR/baggage/)。OpenTelemetry APIの一部として配布されてもMAY構いません。
* [B3](https://github.com/openzipkin/b3-propagation)。

以下は、OpenTelemetryのCoreパッケージとして保守・配布されてもMAY構わない追加のpropagatorの一覧です。

* [Jaeger](https://www.jaegertracing.io/sdk-migration/#propagation-format)。**ステータス**: [Deprecated](../../document-status/)。代わりに[W3C TraceContext](https://www.w3.org/TR/trace-context/)を使用してください。
* [OT Trace](https://github.com/opentracing?q=basic&type=&language=)。OpenTracing Basic Tracersで使われる伝搬形式です。OpenTracingのエコシステムで広く採用されている形式ではないため、結果として得られるpropagatorの名前にMUST NOT`OpenTracing`を使用するものとします。**ステータス**: [Deprecated](../../document-status/)。代わりに[W3C TraceContext](https://www.w3.org/TR/trace-context/)を使用してください。
* [OpenCensus BinaryFormat](https://github.com/census-instrumentation/opencensus-specs/blob/master/encodings/BinaryEncoding.md#trace-context)。OpenCensusで使われる伝搬形式であり、span contextをバイナリ形式にフォーマットする方法を記述しますが、キーは規定しません。`grpc-trace-bin`という伝搬キーを使うOpenCensus gRPCで一般的に使われています。

AWS X-Ray trace headerプロトコルのようなベンダー固有のプロトコルを実装する追加の`Propagator`は、OpenTelemetryのCoreパッケージの一部としてMUST NOT保守または配布されるものとします。

### W3C Trace Context Requirements

W3C Trace Context propagatorは、[W3C Trace Context Level 2](https://www.w3.org/TR/trace-context-2/)で規定されているとおりに`traceparent`ヘッダーと`tracestate`ヘッダーをMUSTパース・検証するものとします。W3C Trace Context propagatorは、同じヘッダーを使って有効な`traceparent`の値をMUST伝搬するものとします。W3C Trace Context propagatorは、値が空の場合は`tracestate`ヘッダーを省略してもよいものとしつつ、それ以外は有効な`tracestate`をMUST伝搬するものとします。

トレースコンテキストをキャリアに注入・抽出する際、`SpanContext`から以下のフィールドが伝搬されます。

- TraceID（16バイト）
- SpanID（8バイト）
- TraceFlags（8ビット）
- TraceState（文字列。空の場合を除く）

### B3 Requirements

B3には単一ヘッダーとマルチヘッダーの2つの符号化があります。また、デバッグ用トレースフラグや、リクエストの両側でIDを共有できることなど、OpenTelemetryに直接対応しないセマンティクスも持っています。OpenTelemetryとZipkinの実装間の互換性を最大化するため、B3のコンテキスト伝搬について以下の指針が定められています。

#### B3 Extract

B3を抽出する際、propagatorは、

* 単一ヘッダーとマルチヘッダーの両方の形式で符号化されたB3の抽出をMUST試みるものとします。単一ヘッダー方式はマルチヘッダー方式より優先されます。
* デバッグ用トレースフラグを受信した場合、それをMUST保持し、後続のリクエストにMUST伝搬するものとします。さらに、OpenTelemetryの実装は、デバッグフラグが設定されている場合にサンプル済みトレースフラグをMUST設定するものとします。
* サーバー側のspanのIDとして`X-B3-SpanId`をMUST NOT再利用するものとします。

#### B3 Inject

B3を注入する際、propagatorは、

* デフォルトで単一ヘッダー形式を使ってB3をMUST注入するものとします。
* デフォルトの注入形式をB3マルチヘッダーに変更する設定をMUST提供するものとします。
* OpenTelemetryはリクエストの両側で同じIDを再利用することをサポートしないため、`X-B3-ParentSpanId`をMUST NOT伝搬するものとします。

#### Fields

Fieldsは、設定された形式に対応するヘッダー名、すなわち注入操作で使われるヘッダーをMUST返すものとします。

#### Configuration

| Option    | Extract Order | Inject Format | Specification     |
|-----------|---------------|---------------| ------------------|
| B3 Single | Single, Multi | Single        | [Link][b3-single] |
| B3 Multi  | Single, Multi | Multi         | [Link][b3-multi]  |

[b3-single]: https://github.com/openzipkin/b3-propagation#single-header
[b3-multi]: https://github.com/openzipkin/b3-propagation#multiple-headers

