# トレーシングSDK

> Source: https://www.ymotongpoo.com/works/otel-specs-ja/spec/trace/sdk/


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

## TracerProvider

### Tracerの作成

`Tracer`インスタンスの作成は、`TracerProvider`を通じてのみ可能であるべきです（SHOULD）（[API](../api/#tracerprovider)を参照）。

`TracerProvider`は[TracerAPIの取得](../api/#tracerの取得)をMUST実装するものとします。

ユーザーが提供した入力は、作成された`Tracer`上に保存される[`InstrumentationScope`](/works/otel-specs-ja/spec/common/instrumentation-scope/)インスタンスを作成するためにMUST使われるものとします。

**ステータス**: [Development](../../document-status/) - `TracerProvider`は、設定された[TracerConfigurator](#tracerconfigurator)を使って関連する[TracerConfig](#tracerconfig)をMUST計算するものとし、その`TracerConfig`に準拠して振る舞う`Tracer`をMUST作成するものとします。

### 設定

設定（すなわち[SpanProcessor](#spanprocessor)、[IdGenerator](#idジェネレーター)、[SpanLimits](#spanの上限)、[`Sampler`](#サンプリング)、そして（**Development**）[TracerConfigurator](#tracerconfigurator)）は、`TracerProvider`によってMUST所有されるものとします。設定は、適切であれば`TracerProvider`の作成時に適用してもかまいません（MAY）。

TracerProviderは、設定を更新するメソッドを提供してもかまいません（MAY）。設定が更新された場合（例えば`SpanProcessor`を追加する場合）、更新された設定は既に返却済みのすべての`Tracer`にもMUST適用されるものとします（すなわち、`Tracer`が設定変更の前後どちらに`TracerProvider`から取得されたかは問題にならないようにMUSTするものとします）。注: 実装としては、`Tracer`インスタンスが自身の`TracerProvider`への参照を持ち、この参照を通じてのみ設定にアクセスする形が考えられます。

#### TracerConfigurator

**ステータス**: [Development](../../document-status/)

`TracerConfigurator`は、[`Tracer`](#tracer)の[TracerConfig](#tracerconfig)を計算する関数です。

この関数は以下のパラメータをMUST受け付けるものとします。

* `tracer_scope`: `Tracer`の[`InstrumentationScope`](/works/otel-specs-ja/spec/common/instrumentation-scope/)。

この関数は、関連する`TracerConfig`、または[デフォルトのTracerConfig](#tracerconfig)を使うべきことを示す何らかのシグナルをMUST返すものとします。このシグナルは、言語にとってイディオマティックな形に応じて、nil、null、空、あるいはデフォルトの`TracerConfig`のインスタンスでもかまいません（MAY）。

この関数は、`Tracer`が最初に作成されたときに呼び出され、また（更新がサポートされている場合）`TracerProvider`の`TracerConfigurator`が更新された際には、未終了のすべての`Tracer`に対して呼び出されます。したがって、この関数が速やかに値を返すことが重要です。

`TracerConfigurator`は、柔軟性を最大化するため関数としてモデル化されています。しかし、実装は一般的な使用例に対応するため、簡略な記法やヘルパー関数を提供してもかまいません（MAY）。

* 名前で1つ以上のTracerを選択する（完全一致またはパターンマッチング）。
* 1つ以上の特定のTracerを無効化する。
* すべてのTracerを無効化し、1つ以上の特定のTracerを選択的に有効化する。

### Shutdown

このメソッドは、プロバイダーが必要なクリーンアップを行うための手段を提供します。

`Shutdown`は、`TracerProvider`インスタンスごとに一度だけMUST呼び出されるものとします。`Shutdown`の呼び出し後、`Tracer`を取得しようとする以後の試みは許可されません。SDKは、可能であればこれらの呼び出しに対して有効なno-opのTracerをSHOULD返すものとします。

`Shutdown`は、呼び出し元に成功・失敗・タイムアウトのいずれであったかを知らせる手段をSHOULD提供するものとします。

`Shutdown`は、ある程度のタイムアウト内に完了または中断すべきです（SHOULD）。`Shutdown`は、ブロッキングAPIとして実装しても、コールバックやイベントを通じて呼び出し元に通知する非同期APIとして実装してもかまいません。OpenTelemetryクライアントの実装者は、シャットダウンのタイムアウトを設定可能にするかどうかを決めてかまいません。

`Shutdown`は、少なくともすべての内部プロセッサー内で`Shutdown`を呼び出すことによってMUST実装されるものとします。

### ForceFlush

このメソッドは、プロバイダーがすべての内部プロセッサーについて、まだエクスポートされていないすべてのspanを直ちにエクスポートするための手段を提供します。

`ForceFlush`は、呼び出し元に成功・失敗・タイムアウトのいずれであったかを知らせる手段をSHOULD提供するものとします。

`ForceFlush`は、ある程度のタイムアウト内に完了または中断すべきです（SHOULD）。`ForceFlush`は、ブロッキングAPIとして実装しても、コールバックやイベントを通じて呼び出し元に通知する非同期APIとして実装してもかまいません。OpenTelemetryクライアントの実装者は、フラッシュのタイムアウトを設定可能にするかどうかを決めてかまいません。

`ForceFlush`は、登録済みのすべての`SpanProcessor`に対して`ForceFlush`をMUST呼び出すものとします。

## Tracer

**ステータス**: [Development](../../document-status/) - `Tracer`は、[Tracerの作成](#tracerの作成)時に計算された[TracerConfig](#tracerconfig)に従ってMUST振る舞うものとします。`TracerProvider`が[TracerConfigurator](#tracerconfigurator)の更新をサポートする場合、更新時に`Tracer`は新しい`TracerConfig`に従って振る舞うようMUST更新されるものとします。

### TracerConfig

**ステータス**: [Development](../../document-status/)

`TracerConfig`は、`Tracer`の振る舞いに関する様々な設定可能な側面を定義します。これは以下のパラメータから構成されます。

* `enabled`: そのTracerが有効かどうかを示すブール値。

  明示的に設定されない場合、`enabled`パラメータのデフォルトは`true`であるべきです（SHOULD）（すなわち、`Tracer`はデフォルトで有効になっています）。

  `Tracer`が無効化されている場合、それは[no-opのTracer](../api/#sdkが存在しない場合のapiの振る舞い)と同等にMUST振る舞うものとします。

  `enabled`の値は、`Tracer`が[Enabled](../api/#enabled)かどうかを解決するためにMUST使われるものとします。`enabled`が`false`の場合、`Enabled`は`false`を返します。`enabled`が`true`の場合、`Enabled`は`true`を返します。

実装は、これらのパラメータへの変更が`Enabled`の呼び出し元に即座に反映されることを保証する必要はありません。しかし、変更は最終的にはMUST反映されるものとします。

### Enabled

`Enabled`は、以下のいずれかに該当する場合に`false`をMUST返すものとします。

- 登録済みの[`SpanProcessor`](#spanprocessor)が存在しない場合。
- **ステータス**: [Development](../../document-status/) - `Tracer`が無効化されている場合（[`TracerConfig.enabled`](#tracerconfig)が`false`）。

それ以外の場合、`true`をSHOULD返すものとします。追加の最適化や機能をサポートするために`false`を返してもかまいません（MAY）。

## 追加のSpanインターフェース

[Spanのインターフェースに関するAPIレベルの定義](../api/#spanの操作)は、spanへの書き込み専用のアクセスのみを定義しています。これは、計装やアプリケーションがアプリケーションロジックのためにspanに保存されたデータを使うことを意図していないという点で好ましい設計です。しかし、SDKは最終的にどこかの箇所でそのデータを読み戻す必要があります。そのため、SDKの仕様書は`Span`に類するパラメータに対して考えられる要件の集合を定義します。

* **Readable span**: これを引数として受け取る関数は、[Span](../api/#span)のAPI仕様に列挙されている、そのspanに追加されたすべての情報にMUSTアクセスできるものとします。注: 以下では、明確さのためいくつかの特定のプロパティを取り上げますが、必須プロパティの完全な一覧については[Span APIの仕様](../api/#span)が正式なものです。

  これを引数として受け取る関数は、そのspanに（暗黙的に）関連付けられた`InstrumentationScope`（[1.10.0以降]）と`Resource`の情報にMUSTアクセスできるものとします。後方互換性のため、`InstrumentationScope`と同じ名前・バージョンの値を持つ`InstrumentationLibrary`（[1.10.0で非推奨]）にもMUSTアクセスできるものとします。

  これを引数として受け取る関数は、そのSpanが終了しているかどうかを確実にMUST判定できるものとします（一部の言語では、終了タイムスタンプが`null`であることによってこれを実装しているかもしれず、他の言語では明示的な`hasEnded`ブール値を持つかもしれません）。

  [エクスポーター](../../common/mapping-to-non-otlp/#dropped-attributes-count)の仕様に記述されている通り、収集の上限によって破棄された属性・イベント・リンクの数は、エクスポーターが報告できるようMUST利用可能であるものとします。

  APIの仕様で定義されているspanのプロパティの正式な集合に対する例外として、実装はSpanの親[Context](/works/otel-specs-ja/spec/context/)の全体を公開（および保存）しなくてもかまいません（MAY）が、少なくとも親の完全な[SpanContext](../api/#spancontext)はMUST公開するものとします。

  これを引数として受け取る関数は、そのSpanを変更できない場合があります。

  注: これは典型的には、新しいインターフェースや（イミュータブルな）値型として実装されます。言語によっては、SpanProcessorはエクスポーターとは異なるreadable span型を持つことがあります（例えば`SpanData`型がイミュータブルなスナップショットを含み、`ReadableSpan`インターフェースは`Span`インターフェースが操作する同じ基盤データ構造から直接情報を読み取る場合があります）。

* **Read/write span**: これを引数として受け取る関数は、[Spanインターフェースに関するAPIレベルの定義](../api/#spanの操作)で定義されている完全なspan APIと、それに加えて（readable spanと同様に）そのspanに追加されたすべての情報を取得できる能力の両方にアクセスできなければなりません。

  これを引数として呼び出される関数は、[spanを作成するAPI](../api/#span作成)がユーザーへ返した（あるいは返すことになる）のと同じ`Span`インスタンスおよび型を、何らかの形で取得できることがMUST可能であるものとします（例えば、その`Span`はそうした関数に渡されるパラメータの1つでもよく、あるいはゲッターを提供してもかまいません）。

## サンプリング

サンプリングとは、OpenTelemetryがバックエンドへ収集・送信するトレースのサンプル数を減らすことで、ノイズとオーバーヘッドを抑える仕組みです。

サンプリングは、トレース収集の異なる段階で実装される場合があります。最も早い段階のサンプリングは、実際にトレースが作成される前に行われることがあり、最も遅い段階のサンプリングは、プロセス外にあるCollector上で行われることがあります。

OpenTelemetry APIには、データ収集を担う2つのプロパティがあります。

* `Span`の`IsRecording`フィールド。これが`false`の場合、現在の`Span`はすべてのトレースデータ（属性、イベント、ステータスなど）を破棄します。ユーザーはこのプロパティを使って、コストの高いトレースデータの収集を避けられるかどうかを判断できます。[SpanProcessor](#spanprocessor)は、このフィールドが`true`に設定されたspanのみをMUST受け取るものとします。一方で[SpanExporter](#spanexporter)は、`Sampled`フラグも設定されていない限りそれらを受け取るべきではありません（SHOULD NOT）。
* `SpanContext`上の`TraceFlags`にある`Sampled`フラグ。このフラグは`SpanContext`を通じて子Spanへ伝搬します。詳細は[W3C Trace Context仕様][W3CCONTEXTSAMPLEDFLAG]を参照してください。このフラグは、その`Span`が`sampled`（サンプリング済み）であり、エクスポートされることを示します。[SpanExporter](#spanexporter)は、`Sampled`フラグが`true`に設定されたspanをMUST受け取るものとし、設定されていないspanはSHOULD NOT受け取るものとします。

`SampledFlag == false`かつ`IsRecording == true`というフラグの組み合わせは、現在の`Span`はデータを記録するものの、その子`Span`はおそらく記録しないことを意味します。

`SampledFlag == true`かつ`IsRecording == false`というフラグの組み合わせは、分散トレースに欠落を生む可能性があるため、OpenTelemetry SDKはこの組み合わせをMUST NOT許容するものとします。

### 記録とサンプリングの反応表

以下の表は、`IsRecording`と`Sampled`フラグの各組み合わせについて期待される挙動をまとめたものです。

| `IsRecording` | `Sampled`フラグ | SpanProcessorはspanを受け取るか？ | SpanExporterはspanを受け取るか？ |
| ------------- | -------------- | ----------------------------- | ---------------------------- |
| true          | true           | true                          | true                         |
| true          | false          | true                          | false                        |
| false         | true           | 許容されない                   | 許容されない                  |
| false         | false          | false                         | false                        |

SDKは、[`Sampler`](#sampler)インターフェースと、[組み込みSampler](#組み込みsampler)の集合を定義し、`Sampler`を各[`TracerProvider`]に関連付けます。

### SDKによるSpan作成

Spanの作成を求められたとき、SDKは以下を順番に行っているかのようにMUST動作するものとします。

1. 有効な親トレースIDが存在する場合はそれを使います。存在しない場合は新しいトレースIDを生成します（注: これは`ShouldSample`の呼び出しより前に行う必要があります。`ShouldSample`は入力として有効なトレースIDを想定するためです）。
2. `Sampler`の[`ShouldSample`](#shouldsample)メソッドに問い合わせます。
3. サンプリング判断とは独立に、その`Span`に対して新しいspan IDを生成します。これは、`Span`が非記録のインスタンスであっても、他のコンポーネント（ログや例外処理など）が一意なspan IDに依拠できるようにするためです。
4. `ShouldSample`が返した判断に応じてspanを作成します。`IsRecording`と`Sampled`をSpanにどう設定するかについては、以下の[`ShouldSample`の](#shouldsample)返り値に関する説明を、`SpanProcessor`にそのSpanを渡すかどうかについては、[上の表](#記録とサンプリングの反応表)を参照してください。非記録のspanは、SDKがインストールされていない場合にSpanが作成されるときと同じ機構、あるいは[SpanContextのSpanへのラッピング](../api/#spancontextのspanへのラッピング)に記述された方法で実装してもかまいません（MAY）。

#### Spanフラグ

SpanおよびSpan LinkのOTLP表現には、Span Flagsと呼ばれる32ビットのフィールドが含まれます。

Span Flagsフィールドのビット0〜7（下位8ビット）は、[W3C Trace Context Level 2][W3CCONTEXTMAIN] Candidate Recommendationで規定されているTrace Contextフラグの8ビットのために予約されています。
[認識されるフラグの一覧を参照してください](../api/#spancontext)。

### Sampler

`Sampler`インターフェースを使うと、ユーザーは、`Span`が作成される直前に一般的に利用可能な情報に基づいてサンプリング結果`SamplingResult`を返すカスタムサンプラーを作成できます。

#### ShouldSample

これから作成される`Span`に対するサンプリングのDecisionを返します。

**必須の引数:**

* 親`Span`を持つ[`Context`](/works/otel-specs-ja/spec/context/)。このSpanのSpanContextは、ルートspanを示すために無効であることがあります。
* 作成される`Span`の`TraceId`。親`SpanContext`が有効な`TraceId`を含む場合、それらはMUST常に一致するものとします。
* 作成される`Span`の名前。
* 作成される`Span`の`SpanKind`。
* 作成される`Span`の初期の`Attributes`の集合。
* 作成される`Span`に関連付けられるリンクのコレクション。これはバッチ処理に対して典型的に有用です。[Spans間のリンク](../../overview/#スパン間のリンク)を参照してください。

注: 実装は、すべてまたは複数の引数を単一のオブジェクトに「まとめて」もかまいません。

**返り値:**

これは`SamplingResult`と呼ばれる出力を生成し、以下を含みます。

* サンプリングの`Decision`。以下の列挙値のいずれかです。
  * `DROP` - `IsRecording`は`false`になり、その`Span`は記録されず、すべてのイベントと属性が破棄されます。
  * `RECORD_ONLY` - `IsRecording`は`true`になりますが、`Sampled`フラグはMUST NOT設定されるものとします。
  * `RECORD_AND_SAMPLE` - `IsRecording`は`true`になり、`Sampled`フラグはMUST設定されるものとします。
* `Span`にも追加されるspan属性の集合。返されるオブジェクトはイミュータブルでなければなりません（複数回の呼び出しが異なるイミュータブルなオブジェクトを返すことがあります）。
* 新しい`SpanContext`を通じてその`Span`に関連付けられる`Tracestate`。サンプラーがここで空の`Tracestate`を返した場合、`Tracestate`はクリアされるため、変更を意図していないサンプラーは通常、渡された`Tracestate`をそのままSHOULD返すものとします。

#### GetDescription

サンプラーの名前、または設定を含む短い説明を返します。これはデバッグページやログに表示されることがあります。例: `"TraceIdRatioBased{0.000100}"`。

説明は、例えばサンプラーが動的な設定をサポートしていたり、パラメータを別の方法で調整したりする場合には、時間とともに変化してもかまいません（MAY）。呼び出し元は、返された値をキャッシュすべきではありません（SHOULD NOT）。

### 組み込みSampler

OpenTelemetryは、選択可能な複数の組み込みサンプラーをサポートしています。デフォルトのサンプラーは`ParentBased(root=AlwaysOn)`です。

#### AlwaysOn

* 常に`RECORD_AND_SAMPLE`を返します。
* 説明は`AlwaysOnSampler`でなければなりません（MUST）。

#### AlwaysOff

* 常に`DROP`を返します。
* 説明は`AlwaysOffSampler`でなければなりません（MUST）。

#### TraceIdRatioBased

**ステータス**: [Stable](../../document-status/)

`TraceIdRatioBased`サンプラーは、コンポーザブルな[`ProbabilitySampler`](#probabilitysampler)を優先する形で非推奨になっています。このコンポーネントは、[1.0のトレース仕様書における「TODO」に対応するために段階的に廃止されています](https://github.com/open-telemetry/opentelemetry-specification/issues/1413)。OpenTelemetry SDKの実装者は、少なくとも2027年1月1日までは、既存の`TraceIdRatioBased`サンプラーの振る舞いを削除・変更してはなりません（SHALL NOT）。その時点で、SDKの実装者は、`TraceIdRatioBased`の設定を同等の設定を持つ`ProbabilitySampler`へ黒子で置き換えることが推奨されます。

* `TraceIdRatioBased`は、親の`SampledFlag`をMUST無視するものとします。親の`SampledFlag`を尊重するには、以下で指定する`ParentBased`サンプラーのデリゲートとして`TraceIdRatioBased`を使うべきです。
* 説明は、`RATIO`をSamplerインスタンスのトレースサンプリング比率を表す小数値に置き換えた`"TraceIdRatioBased{RATIO}"`という形式の文字列をMUST返すものとします。数値の精度は実装言語の標準に従うべきであり（SHOULD）、Samplerが異なる比率を持つことを識別できるよう十分に高くあるべきです（SHOULD）。例えば、10,000スパンにつき1つというサンプリング比率を持つTraceIdRatioBased Samplerは、説明として`"TraceIdRatioBased{0.000100}"`を返すことができます（COULD）。

##### TraceIdRatioBasedサンプラーアルゴリズムの要件

**ステータス**: [Stable](../../document-status/)

* サンプリングアルゴリズムは決定的でなければなりません（MUST）。与えられた`TraceId`によって識別されるトレースは、言語や時間などに関わらずサンプリングされるかされないかが決まります。これを実現するため、実装はサンプリング判断を計算する際に`TraceId`の決定的なハッシュをMUST使うものとします。これを保証することで、任意の子`Span`に対してサンプラーを実行しても同じ判断が得られます。
* あるサンプリング確率を持つ`TraceIdRatioBased`サンプラーは、それより低いサンプリング確率を持つ任意の`TraceIdRatioBased`サンプラーがサンプリングするすべてのトレースもMUSTサンプリングするものとします。これは、バックエンドシステムがフロントエンドシステムよりも高いサンプリング確率で動作させたい場合に重要です。この方法により、フロントエンドのすべてのトレースは依然としてサンプリングされ、追加のトレースはバックエンドでのみサンプリングされます。

##### TraceIdRatioBasedサンプラーの互換性に関する警告

**ステータス**: [Development](../../document-status/)

**警告:** 正確なアルゴリズムは一度も規定されたことがありません。このサンプラーは、他のいかなるSDKとも互換性を持つように定義されていないため、不安定であると見なされます。設定と作成のAPIのみが安定しています。異なる言語のSDK、あるいは同じ言語のSDKの異なるバージョンでも、同じ入力に対して一貫しない結果を生成することがあるため、このサンプラーアルゴリズムはルートspanに対してのみ（[`ParentBased`](#parentbased)と組み合わせて）使うことが推奨されます。

このサンプラーが空でない親のspanコンテキストを観測した場合、つまりルートサンプラーとして使われていない場合、SDKは以下のような警告を発するべきです（SHOULD）。

```
WARNING: The TraceIdRatioBased sampler is operating as a child sampler;
the behavior is subject to change. Please upgrade this SDK configuration
to use ProbabilitySampler.
```

このような場面では、このサンプラーは`th`または`rv`サブキーを持つOpenTelemetryのtracestate（`ot=...`）をTracestate内で検査することによって`ProbabilitySampler`の使用を検出することもでき、その場合警告はより直接的なものになってもかまいません（MAY）。

```
WARNING: The TraceIdRatioBased sampler is operating as a child sampler
and a parent is using ProbabilitySampler. Please upgrade this SDK configuration
to use ProbabilitySampler.
```

#### ProbabilitySampler

**ステータス**: [Development](../../document-status/)

`ProbabilitySampler`は、[W3C Trace Context Level 2][W3CCONTEXTMAIN] Candidate Recommendationで規定されたランダム性の機能を使って、単純な比率ベースの確率的サンプリングを実装します。OpenTelemetryは、56ビットのランダム性を規定するW3C Trace Context Level 2に従い、[56ビットのランダム性を使って一貫した確率サンプリングの判断を行う方法を規定しています][CONSISTENTSAMPLING]。

`ProbabilitySampler`サンプラーは、親の`SampledFlag`をMUST無視するものとします。親の`SampledFlag`を尊重する方法については、以下で指定する`ParentBased`サンプラーを参照してください。

これは非コンポーザブルな形式の確率サンプラーであることに注意してください。`ProbabilitySampler`はSDKのSampler APIを直接実装しますが、[`ComposableProbability`](#composableprobability)は[`CompositeSampler`](#compositesampler)で使うためのコンポーザブルな形式です。

[W3CCONTEXTMAIN]: https://www.w3.org/TR/trace-context-2/

##### ProbabilitySamplerサンプラーの設定

`ProbabilitySampler`サンプラーは通常、サンプリング比率を表現するために32ビットまたは64ビットの浮動小数点数を使って設定されます。有効な最小サンプリング比率は`2^-56`で、有効な最大サンプリング比率は1.0です。入力されたサンプリング比率から棄却しきい値の値が計算されます。可変精度でサンプリング比率をしきい値に変換する詳細については、[一貫した確率サンプラーの要件][CONSISTENTSAMPLING]を参照してください。

[CONSISTENTSAMPLING]: /works/otel-specs-ja/spec/trace/tracestate-probability-sampling/

##### ProbabilitySamplerサンプラーアルゴリズム

サンプリングしきい値`T`とランダム性の値`R`（典型的には、トレースIDの右端7バイト）を持つContextで設定されたSamplerに対して`ShouldSample()`が呼び出されると、`R >= T`という式を使って`RECORD_AND_SAMPLE`または`DROP`のいずれを返すかを判断します。

* ランダム性の値（R）が棄却しきい値（T）以上である場合、すなわち（R >= T）である場合は`RECORD_AND_SAMPLE`を返し、そうでない場合は`DROP`を返します。
* （R >= T）である場合、[OpenTelemetry TraceStateの`th`サブキー][TRACESTATEHANDLING]で規定されている通り、OpenTelemetryのTraceStateは棄却しきい値の値（T）を表すキーバリュー`th:T`を含むよう変更されるべきです（SHOULD）。

[TRACESTATEHANDLING]: /works/otel-specs-ja/spec/trace/tracestate-handling/#sampling-threshold-value-th

##### ProbabilitySamplerの互換性に関する警告

`ProbabilitySampler`がTraceIDのランダム性に基づいて非ルートSpanの判断を下す場合、そのTraceIDが実際にはこの仕様書を認識していない古いSDKによって生成されたものである可能性があります。Trace randomフラグは、この2つのケースを区別できるようにします。このフラグは、TraceIDがランダムであることをProbabilitySampler Samplerが確認できるようにする情報を伝えますが、これにはそのコンテキストを扱ったすべてのTrace SDKがW3C Trace Context Level 2をサポートしていることが必要です。

ProbabilitySampler Samplerが、[Trace randomフラグが設定されていないときにTraceIDのランダム性](#traceidのランダム性の推定)を使って非ルートSpanの判断を下す場合、SDKはそのログに互換性に関する警告文をSHOULD発行するものとします。この互換性の警告の例を示します。

```
WARNING: The ProbabilitySampler sampler is presuming TraceIDs are random
and expects the Trace random flag to be set in confirmation.  Please
upgrade your caller(s) to use W3C Trace Context Level 2.
```

#### ParentBased

* これはサンプラーデコレーターです。`ParentBased`は以下のケースを区別する助けになります。
  * 親がない（ルートspan）。
  * `SampledFlag`が設定されているリモートの親（`SpanContext.IsRemote() == true`）。
  * `SampledFlag`が設定されていないリモートの親（`SpanContext.IsRemote() == true`）。
  * `SampledFlag`が設定されているローカルの親（`SpanContext.IsRemote() == false`）。
  * `SampledFlag`が設定されていないローカルの親（`SpanContext.IsRemote() == false`）。

必須パラメータ:

* `root(Sampler)` - 親を持たないspan（ルートspan）に対して呼び出されるSampler。

任意パラメータ:

* `remoteParentSampled(Sampler)`（デフォルト: AlwaysOn）
* `remoteParentNotSampled(Sampler)`（デフォルト: AlwaysOff）
* `localParentSampled(Sampler)`（デフォルト: AlwaysOn）
* `localParentNotSampled(Sampler)`（デフォルト: AlwaysOff）

| 親  | parent.isRemote() | parent.IsSampled() | 呼び出されるサンプラー             |
| ------- | ----------------- | ------------------ | -------------------------- |
| 存在しない  | n/a               | n/a                | `root()`                   |
| 存在する | true              | true               | `remoteParentSampled()`    |
| 存在する | true              | false              | `remoteParentNotSampled()` |
| 存在する | false             | true               | `localParentSampled()`     |
| 存在する | false             | false              | `localParentNotSampled()`  |

#### JaegerRemoteSampler

[Jaeger remote sampler][jaeger-remote-sampling]は、SDKのサンプリング設定をリモートから制御できるようにします。サンプリング設定はバックエンドから定期的に読み込まれ（[Remote Sampling API][jaeger-remote-sampling-api]を参照）、そこでは運用担当者が設定ファイルを通じて管理することも、自動的に計算させることもできます（[Adaptive Sampling][jaeger-adaptive-sampling]を参照）。remote samplerが取得したサンプリング設定は、サービス全体に対して単一のサンプリング方式（例えば`TraceIdRatioBased`）を使うよう指示することも、エンドポイント（span名）ごとに異なる方式を使うよう指示することもできます。例えば、`/product`エンドポイントは10%、`/admin`エンドポイントは100%でサンプリングし、`/metrics`エンドポイントは決してサンプリングしない、といった指定です。

完全なprotobufの定義は[jaegertracing/jaeger-idl/api_v2/sampling.proto](https://github.com/jaegertracing/jaeger-idl/blob/main/proto/api_v2/sampling.proto)にあります。

サンプラーを作成する際、以下の設定プロパティが利用可能であるべきです。

* endpoint - Jaeger CollectorやOpenTelemetry Collectorなど、[Remote Sampling API][jaeger-remote-sampling-api]を実装するサービスのアドレス。
* polling interval - リモートから設定を取得するポーリング間隔。
* initial sampler - 最初の設定が取得される前に使われる初期サンプラー。

[jaeger-remote-sampling]: https://www.jaegertracing.io/docs/2.14/architecture/sampling/#remote-sampling
[jaeger-remote-sampling-api]: https://www.jaegertracing.io/docs/2.14/architecture/apis/#remote-sampling-configuration
[jaeger-adaptive-sampling]: https://www.jaegertracing.io/docs/2.14/architecture/sampling/#adaptive-sampling

#### AlwaysRecord

`AlwaysRecord`は、通常であれば破棄されるspanも含め、すべてのspanが`SpanProcessor`に渡されることを保証するサンプラーデコレーターです。これは、ラップされたサンプラーからの`DROP`判断を`RECORD_ONLY`判断へ変換することで実現されており、プロセッサーはエクスポーターへ送信することなくすべてのspanを見られるようになります。これは典型的には、正確なspanからメトリクスへの処理を可能にするために使われます。

ラップされたルートサンプラーからの判断に基づいて、`AlwaysRecord`は以下のようにMUST振る舞うものとします。

| ルートサンプラーの判断 | AlwaysRecordの判断 |
| --------------------- | --------------------- |
| `DROP`                | `RECORD_ONLY`         |
| `RECORD_ONLY`         | `RECORD_ONLY`         |
| `RECORD_AND_SAMPLE`   | `RECORD_AND_SAMPLE`   |

必須パラメータ:

* `root(Sampler)` - ラップされるサンプラー。`AlwaysRecord`が変更する元のサンプル・破棄の判断を提供します。

#### CompositeSampler

**ステータス**: [Development](../../document-status/)

CompositeSamplerは標準の`Sampler`インターフェースを実装しますが、その判断を行うために複数のサンプラーの合成を使います。

CompositeSamplerはComposableSamplerを入力として受け取り、最終的なサンプリング判断を助けるデリゲートとして使います。Consistent Probability Samplingの基本については[TraceStateにおける確率サンプリング](/works/otel-specs-ja/spec/trace/tracestate-probability-sampling/)を参照してください。

ShouldSampleの呼び出しに応じて最終的なSamplingResultを構築する処理は、以下の手順から構成されます。

* サンプラーはデリゲート（以下のComposableSamplerを参照）に対して`GetSamplingIntent`を呼び出します。
* 受け取ったTHRESHOLD値が`null`である場合、サンプリング判断は`DROP`になります。それ以外の場合、
* サンプラーは受け取った`adjusted_count_reliable`を確認し、`true`である場合は[ランダム性の値（R）](/works/otel-specs-ja/spec/trace/tracestate-probability-sampling/#randomness-value-r)に記述された通りTraceStateまたはTraceIdからランダム性の値Rを導出し、`false`である場合は新しいランダムな56ビットの数値を16進エンコードして新しいランダム性の値Rを生成します。
* サンプラーは、受け取ったTHRESHOLD値とランダム性の値Rを（実装によって辞書式順序またはその他の方法で）比較し、[判断アルゴリズム](/works/otel-specs-ja/spec/trace/tracestate-probability-sampling/#decision-algorithm)に記述された通り最終的なサンプリングの`Decision`を導出します。
* サンプラーは、親の`Tracestate`と最終的なサンプリングの`Decision`を渡して受け取った`trace_state_provider`関数を呼び出し、その`Span`に関連付ける新しい`Tracestate`を取得します。
* サンプリング判断が肯定的な場合、
  - サンプラーは受け取った`attributes_provider`関数を呼び出し、`Span`に追加する`Attributes`の集合を決定します。
  - `adjusted_count_reliable`が`true`である場合、受け取ったTHRESHOLDに従って`Tracestate`の`ot`キーの`th`値を変更します。返された値が`false`だった場合は、`Tracestate`の`ot`キーから`th`値を削除します。
* サンプリング判断が否定的な場合、`Tracestate`の`ot`キーから`th`値を削除します。

##### ComposableSampler

ComposableSamplerは、CompositeSamplerによって使われる特化されたインターフェースです。これは、複数のサンプラーが協調してサンプリング判断を行えるようにする`GetSamplingIntent`という新しいメソッドを定義することで、コンポーザブルなアプローチをサンプリングにもたらします。

###### GetSamplingIntent

Spanをサンプリングすることに関するサンプラーの意向を示す、実際に最終判断を下すことなくSamplingIntent構造体を返します。

**必須の引数:**

* `traceId`を除く、元のSampler APIのすべてのパラメータが含まれます。
* 親コンテキスト、しきい値、着信のtrace state、trace flagの情報は、ComposableSamplerがこの情報を得るためにContextを繰り返し調べる必要がないよう、事前に計算されている場合があります（MAY）。

注: ComposableSamplerは、デリゲートのGetSamplingIntentメソッドに渡されたパラメータを変更してはなりません（MUST NOT）。それらは読み取り専用の状態と見なされます。

**返り値:**

このメソッドは、以下の要素を持つ`SamplingIntent`構造体を返します。

* `threshold` - サンプリングしきい値。しきい値が低いほどサンプリングされる可能性が高くなります。
* `adjusted_count_reliable` - [Spanからメトリクスへの推定](/works/otel-specs-ja/spec/trace/tracestate-probability-sampling/#sampling-related-terms)のためにそのしきい値を信頼できる形で使えるかどうかを示すブール値。
* `attributes_provider` - サンプリングされた場合にspanに追加される属性の任意のプロバイダー。
* `trace_state_provider` - 変更されたTraceStateの任意のプロバイダー。

`trace_state_provider`が複雑さの大きな要因になりうることに注意してください。ComposableSamplerは、OpenTelemetryのTraceState（すなわちTraceStateの`ot`サブキー）をMUST NOT変更するものとします。呼び出し元のCompositeSamplerは、上述の通り送信するTraceStateのしきい値をSHOULD更新するものとします。明示的なランダム性の値は変更してはなりません（MUST）。

##### 組み込みComposableSampler

###### ComposableAlwaysOn

* すべてのspanをサンプリングするしきい値（threshold = 0）を持つ`SamplingIntent`を常に返します。
* `adjusted_count_reliable`を`true`に設定します。
* 属性を追加しません。

###### ComposableAlwaysOff

* すべてのspanが破棄されるべきことを示す、しきい値を持たない`SamplingIntent`を常に返します。
* `adjusted_count_reliable`を`false`に設定します。
* 属性を追加しません。

###### ComposableProbability

* 設定されたサンプリング比率によって決まるしきい値を持つ`SamplingIntent`を返します。
* `adjusted_count_reliable`を`true`に設定します。
* 属性を追加しません。

**必須パラメータ:**

* `ratio` - サンプリングの望ましい確率を表す、`2^-56`から1.0（両端を含む）までの値。

比率の値が0の場合、非確率的であると見なされます。この0のケースでは、代わりに`ComposableAlwaysOff`インスタンスをSHOULD返すものとします。

トップレベルの`ProbabilitySampler`は`Composite(ComposableProbability(ratio))`という設定を使って実装できることに注意してください。

###### ComposableParentThreshold

* 親コンテキストを持たないspanについては、ルートサンプラーに委譲します。
* 親コンテキストを持つspanについては、親のサンプリング判断を伝える`SamplingIntent`を返します。
* 利用可能であれば親のしきい値を返します。そうでなく親の*sampled*フラグが設定されている場合はthreshold=0を返します。そうでなく親の*sampled*フラグが設定されていない場合、しきい値は返されません。
* `adjusted_count_reliable`を親の信頼性に一致させて設定します。これは、親がしきい値を持っていた場合にtrueになります。
* 属性を追加しません。

**必須パラメータ:**

* `root` - 親コンテキストを持たないspanをサンプリングするためのデリゲート。

###### ComposableRuleBased

* 述語に基づく一連のルールを評価し、最初に一致したサンプラーからの`SamplingIntent`を返します。
* いずれのルールも一致しない場合、サンプリングしない意向を返します。

**必須パラメータ:**

* `rules` - (Predicate, ComposableSampler)のペアのリスト。Predicateはそのルールが適用されるかどうかを評価する関数です。

###### ComposableAnnotating

* サンプリング判断を別のサンプラーに委譲しますが、サンプリングされたspanに属性を追加します。
* デリゲートのしきい値と追加の属性を組み合わせた`SamplingIntent`を返します。

**必須パラメータ:**

* `attributes` - サンプリングされたspanに追加する属性。
* `delegate` - 実際のサンプリング判断を行う基盤となるサンプラー。

**設定例:**

複合サンプラーの設定を作成する例です。

```
// Create a rule-based sampler for root spans
rootSampler = ComposableRuleBased([
  (isHealthCheck, ComposableAlwaysOff),
  (isCheckout, ComposableAlwaysOn),
  (isAnything, ComposableTraceIDRatio(0.1))
])

// Create a parent-based sampler for child spans
finalSampler = ComposableParentThreshold(rootSampler)
```

この例は以下のような設定を作成します。

- ヘルスチェックのエンドポイントは決してサンプリングされません。
- checkoutのエンドポイントは常にサンプリングされます。
- その他のルートspanは10%でサンプリングされます。
- 子spanは親のサンプリング判断に従います。

### サンプリングの要件

**ステータス**: [Development](../../document-status/)

[W3C Trace Context Level 2][W3CCONTEXTLEVEL2] Candidate Recommendationには、統計的な目的のためにTraceIDが56ビットのランダムな値を含むことを示す[Random trace flag][W3CCONTEXTRANDOMFLAG]が含まれています。このフラグは、[TraceIDの最下位（「右端」）7バイト、すなわち56ビットがランダムである][W3CCONTEXTTRACEID]ことを示します。

このRandomフラグは、そのフラグを認識しない[Trace Context Level 1][W3CCONTEXTLEVEL1]の実装を通じては伝搬しないことに注意してください。このフラグが1の場合、それは意味を持つと見なされます。このフラグが0の場合、TraceIDがランダムでないことが原因であることもあれば、Trace Context Level 1のpropagatorが使われたことが原因であることもあります。このような状況やその他のTraceIDが十分なランダム性を欠く状況でサンプリングを可能にするため、OpenTelemetryは[W3C TraceStateフィールド][W3CCONTEXTTRACESTATE]内にエンコードされる任意の[明示的なランダム性の値][OTELRVALUE]を定義しています。

本仕様書は、TraceIDのランダム性または明示的なランダム性のいずれかを使うことを推奨しており、これによりW3C Trace Contextの伝搬を使う際にサンプラーが常に十分なランダム性を持つことが保証されます。

[W3CCONTEXTLEVEL2]: https://www.w3.org/TR/trace-context-2/
[W3CCONTEXTLEVEL1]: https://www.w3.org/TR/trace-context/
[W3CCONTEXTTRACEID]: https://www.w3.org/TR/trace-context-2/#randomness-of-trace-id
[W3CCONTEXTTRACESTATE]: https://www.w3.org/TR/trace-context-2/#tracestate-header
[W3CCONTEXTSAMPLEDFLAG]: https://www.w3.org/TR/trace-context-2/#sampled-flag
[W3CCONTEXTRANDOMFLAG]: https://www.w3.org/TR/trace-context-2/#random-trace-id-flag
[OTELRVALUE]: /works/otel-specs-ja/spec/trace/tracestate-handling/#explicit-randomness-value-rv

#### TraceIDのランダム性

ルートspanのコンテキストについて、SDKはTraceIDの値を生成する際に[W3C Trace Context Level 2][W3CCONTEXTTRACEID] Candidate RecommendationのTraceIDランダム性要件をSHOULD実装するものとします。

#### Randomトレースフラグ

ルートspanのコンテキストについて、SDKは[W3C Trace Context Level 2のランダム性要件][W3CCONTEXTTRACEID]を満たすTraceIDを生成する際、trace flagsの`Random`フラグをSHOULD設定するものとします。

#### 明示的なランダム性

明示的なランダム性とは、APIの利用者とSDKの実装者がトレースのランダム性を制御できるようにする仕組みです。以下の推奨事項は、上述のTraceIDランダム性に関する推奨を無視したTrace SDKに適用されます。これには2つの部分があります。

##### 明示的なランダム性を上書きしない

APIの利用者はルートspanの初期TraceStateを制御するため、[OpenTelemetry TraceStateの`rv`サブキー][OTELRVALUE]を定義することで、そのトレースの明示的なランダム性を提供できます。SDKとSamplerは、OpenTelemetry TraceStateの値における明示的なランダム性をMUST NOT上書きするものとします。

##### ルートサンプラーは非ランダムなTraceIDに対して明示的なランダム性を設定する

SDKが[W3C Trace Context Level 2のランダム性要件][W3CCONTEXTTRACEID]を満たさないTraceIDを生成した場合（未設定のtrace randomフラグによって示されます）、かつ[OpenTelemetry TraceStateの`rv`サブキー][OTELRVALUE]がまだ設定されていない場合、Root samplerには明示的なランダム性の値を挿入する機会があります。

Root Samplerは、明示的なランダム性の値がまだ設定されていない場合に、OpenTelemetry TraceStateの値へ明示的なランダム性の値を挿入してもかまいません（MAY）。

例えば、以下は非ランダムな識別子と明示的なランダム性の値を持つW3C Trace Contextです。

```
traceparent: 00-ffffffffffffffffffffffffffffffff-ffffffffffffffff-00
tracestate: ot=rv:7479cfb506891d
```

#### TraceIDのランダム性の推定

すべてのspanのコンテキストについて、OpenTelemetryのサンプラーは、[OpenTelemetry TraceStateの`rv`サブキー][OTELRVALUE]に明示的なランダム性の値が存在しない限り、TraceIDがW3C Trace Context Level 2のランダム性要件を満たしているとSHOULD推定するものとします。

#### IdGeneratorのランダム性

SDKが`IdGenerator`拡張ポイントを使う場合、SDKは新しいIDが生成される際にRandomフラグを設定するかどうかをその拡張が決定できるようSHOULD許容するものとします。

## Spanの上限

Spanの属性は、[属性の上限に関する共通のルール](/works/otel-specs-ja/spec/common/#attribute-limits)にMUST従うものとします。

SDKのSpanは、設定された上限を超えて各コレクションの要素数を増やすことになるリンクやイベントを破棄してもかまいません（MAY）。

SDKが上記の上限を実装する場合、Javaの例のように個々の上限をユーザーが設定できるようにすることで、TracerProviderへの設定を通じてこれらの上限を変更する方法をMUST提供するものとします。

設定オプションの名前は`EventCountLimit`と`LinkCountLimit`であるべきです（SHOULD）。これらのオプションはクラスにまとめてもかまいません（MAY）。その場合、そのクラスは`SpanLimits`とSHOULD呼ばれるものとします。実装は、`AttributePerEventCountLimit`や`AttributePerLinkCountLimit`のような追加の設定を提供してもかまいません（MAY）。

```java
public final class SpanLimits {
  SpanLimits(int attributeCountLimit, int linkCountLimit, int eventCountLimit);

  public int getAttributeCountLimit();

  public int getAttributeCountPerEventLimit();

  public int getAttributeCountPerLinkLimit();

  public int getEventCountLimit();

  public int getLinkCountLimit();
}
```

**設定可能なパラメータ:**

* [属性に適用可能なすべての共通オプション](/works/otel-specs-ja/spec/common/#configurable-parameters)
* `EventCountLimit`（デフォルト=128） - 許容されるspanイベント数の最大値。
* `LinkCountLimit`（デフォルト=128） - 許容されるspanリンク数の最大値。
* `AttributePerEventCountLimit`（デフォルト=128） - spanイベントごとに許容される属性数の最大値。
* `AttributePerLinkCountLimit`（デフォルト=128） - spanリンクごとに許容される属性数の最大値。

属性、イベント、またはリンクがこのような上限によって破棄されたことをユーザーに示すメッセージが、SDKのログにSHOULD出力されるものとします。過剰なログ出力を防ぐため、このメッセージはspanごとに最大一度だけMUST出力されるものとします（すなわち、破棄された属性・イベント・リンクごとではありません）。

## IDジェネレーター

SDKはデフォルトで`TraceId`と`SpanId`の両方をランダムにMUST生成するものとします。

SDKは、`TraceId`と`SpanId`の両方についてIDの生成方法をカスタマイズする仕組みをMUST提供するものとします。

SDKは、以下のJavaの例のようなインターフェース（このインターフェースの名前は`IdGenerator`でもかまいません（MAY）。メソッドの名前は[SpanContext](../api/#traceidとspanidの取得)と一致していなければなりません（MUST））のカスタム実装を許容することで、この機能を提供してもかまいません（MAY）。これは、`SpanId`を生成するためのメソッドと`TraceId`を生成するためのメソッドの、2つの拡張ポイントを提供します。

```java
public interface IdGenerator {
  byte[] generateSpanIdBytes();
  byte[] generateTraceIdBytes();
}
```

AWS X-RayのトレースID生成器のようなベンダー固有のプロトコルを実装する追加の`IdGenerator`は、OpenTelemetryの[コアパッケージ](../../overview/#コアパッケージ)の一部としてMUST NOT保守・配布されるものとします。

### IdGeneratorのランダム性

**ステータス**: [Development](../../document-status/)

`IdGenerator`のカスタム実装は、生成されるすべてのTraceIDの値が[W3C Trace Context Level 2のランダム性要件][W3CCONTEXTTRACEID]を満たす場合、関連するTraceコンテキストでTraceの`random`フラグが設定されるよう、適切に自身を識別すべきです（SHOULD）。これは`IdGenerator`実装の静的なプロパティであると想定され、例えばマーカーインターフェースを拡張するといった言語機能を使って推論できます。

## SpanProcessor

SpanProcessorは、span開始・終了メソッドの呼び出しに対してフックできるようにするインターフェースです。span processorは、[`IsRecording`](../api/#isrecording)が`true`である場合のみ呼び出されます。

組み込みのSpanProcessorは、spanのバッチ処理とエクスポート可能な表現への変換を担い、バッチをエクスポーターに渡します。

SpanProcessorはSDKの`TracerProvider`上に直接登録でき、登録された順序と同じ順序で呼び出されます。

`TracerProvider`に登録された各プロセッサーは、span processorと任意のエクスポーターから構成されるパイプラインの起点です。SDKは、各パイプラインを個別のエクスポーターで終端させることをMUST許容するものとします。

SDKは、ユーザーがカスタムプロセッサーを実装・設定することをMUST許容するものとします。

以下の図は、`SpanProcessor`とSDK内の他のコンポーネントとの関係を示しています。

```
  +-----+--------------+   +-------------------------+   +----------------+
  |     |              |   |                         |   |                |
  |     |              |   | Batching Span Processor |   |  SpanExporter  |
  |     |              +---> Simple Span Processor   +---> (OTLPExporter) |
  |     |              |   |                         |   |                |
  | SDK | Span.start() |   +-------------------------+   +----------------+
  |     | Span.end()   |
  |     |              |
  |     |              |
  |     |              |
  |     |              |
  +-----+--------------+
```

### インターフェース定義

`SpanProcessor`インターフェースは以下のメソッドをMUST宣言するものとします。

* [OnStart](#onstart)
* [OnEnd](#onendspan)
* [Shutdown](#shutdown-1)
* [ForceFlush](#forceflush-1)

`SpanProcessor`インターフェースは以下のメソッドをSHOULD宣言するものとします。

* [OnEnding](#onending)メソッド。

#### OnStart

`OnStart`は、spanが開始されたときに呼び出されます。このメソッドは、そのspanを開始したスレッド上で同期的に呼び出されるため、ブロックしたり例外をスローしたりすべきではありません。複数の`SpanProcessor`が登録されている場合、それらの`OnStart`コールバックは登録された順序で呼び出されます。

**パラメータ:**

* `span` - 開始されたspanに対する[read/write span object](#追加のspanインターフェース)。このspanオブジェクトへの参照を保持でき、そのspanへの更新はそこに反映されるべきです（SHOULD）。例えば、これはバックグラウンドスレッドからすべてのアクティブなspanに関する情報を定期的に評価・出力するSpanProcessorを作成する際に有用です。
* `parentContext` - SDKが決定した、そのspanの親`Context`（明示的に渡された`Context`、現在の`Context`、または明示的に要求された場合の空の`Context`）。

**戻り値:** `Void`

#### OnEnding

**ステータス**: [Development](../../document-status/)

`OnEnding`は、spanの`End()`操作の中で呼び出されます。終了タイムスタンプはMUST計算済みでなければなりません（`OnEnding`メソッドの処理時間はspanの継続時間には含まれません）。`OnEnding`が呼び出されている間、Spanオブジェクトは依然としてMUST可変であるものとします（すなわち、`SetAttribute`、`AddLink`、`AddEvent`を呼び出せます）。このメソッドは[`Span.End()` API](../api/#end)の中で同期的にMUST呼び出されるものとし、したがってブロックしたり例外をスローしたりすべきではありません。複数の`SpanProcessor`が登録されている場合、それらの`OnEnding`コールバックは登録された順序で呼び出されます。SDKは、最初の`SpanProcessor`の`OnEnding`を呼び出す前に、そのspanが他のいかなるスレッドによっても変更され得なくなっていることをMUST保証するものとします。それ以降、変更は呼び出された`OnEnding`コールバックの内部からのみ同期的に許可されます。登録されたすべてのSpanProcessorの`OnEnding`コールバックは、いずれのSpanProcessorの`OnEnd`コールバックが呼び出されるより前に実行されます。

**パラメータ:**

* `span` - まさに終了しようとしているspanに対する[read/write span object](#追加のspanインターフェース)。

**戻り値:** `Void`

#### OnEnd(Span)

`OnEnd`は、spanが終了した後（すなわち終了タイムスタンプが既に設定された後）に呼び出されます。このメソッドは[`Span.End()` API](../api/#end)の中で同期的にMUST呼び出されるものとし、したがってブロックしたり例外をスローしたりすべきではありません。

**パラメータ:**

* `Span` - 終了したspanに対する[readable span object](#追加のspanインターフェース)。注: 渡されたSpanが技術的には書き込み可能であっても、この時点では既に終了しているため、それを変更することは許可されません。

**戻り値:** `Void`

#### Shutdown()

プロセッサーをシャットダウンします。SDKがシャットダウンされる際に呼び出されます。これはプロセッサーが必要なクリーンアップを行う機会です。

`Shutdown`は、`SpanProcessor`インスタンスごとに一度だけSHOULD呼び出されるものとします。`Shutdown`の呼び出し後、`OnStart`・`OnEnd`・`ForceFlush`への以後の呼び出しは許可されません。SDKは可能であればこれらの呼び出しを穏やかにSHOULD無視するものとします。

`Shutdown`は、呼び出し元に成功・失敗・タイムアウトのいずれであったかを知らせる手段をSHOULD提供するものとします。

`Shutdown`は`ForceFlush`の効果をMUST含むものとします。

`Shutdown`は、ある程度のタイムアウト内に完了または中断すべきです（SHOULD）。`Shutdown`は、ブロッキングAPIとして実装しても、コールバックやイベントを通じて呼び出し元に通知する非同期APIとして実装してもかまいません。OpenTelemetryクライアントの実装者は、シャットダウンのタイムアウトを設定可能にするかどうかを決めてかまいません。

#### ForceFlush()

これは、`ForceFlush`の呼び出しより前に`SpanProcessor`が既にイベントを受け取っていた`Span`に関連するすべてのタスクが、できる限り早く、望ましくはこのメソッドから戻る前に完了しているべきことを示すヒントです（SHOULD）。

特に、`SpanProcessor`に関連付けられたエクスポーターがある場合、まだ完了していないすべてのspanについてエクスポーターの`Export`を呼び出し、その後`ForceFlush`をそのエクスポーターに対して呼び出そうとSHOULD試みるものとします。[組み込みのSpanProcessor](#組み込みspanprocessor)はこれをMUST行うものとします。タイムアウトが指定されている場合（下記参照）、SpanProcessorはこの目標を達成するため、すべての呼び出しを完了させることよりもタイムアウトを守ることをMUST優先するものとします。この目標を達成するために、一部または全部のExportやForceFlushの呼び出しをスキップまたは中断してもかまいません（MAY）。

`ForceFlush`は、呼び出し元に成功・失敗・タイムアウトのいずれであったかを知らせる手段をSHOULD提供するものとします。

`ForceFlush`は、プロセスを中断させてから完了したspanをエクスポートする前にプロセスを停止させてしまう可能性のある一部のFaaSプロバイダーを使う場合など、絶対に必要な場合に限りSHOULD呼び出されるものとします。

`ForceFlush`は、ある程度のタイムアウト内に完了または中断すべきです（SHOULD）。`ForceFlush`は、ブロッキングAPIとして実装しても、コールバックやイベントを通じて呼び出し元に通知する非同期APIとして実装してもかまいません。OpenTelemetryクライアントの実装者は、フラッシュのタイムアウトを設定可能にするかどうかを決めてかまいません。

### 組み込みSpanProcessor

標準のOpenTelemetry SDKは、以下に記述するシンプルなプロセッサーとバッチプロセッサーの両方をMUST実装するものとします。その他の一般的な処理シナリオは、まず[OpenTelemetry Collector](../../overview/#collector)でプロセス外で実装することを検討すべきです。

#### シンプルなSpanProcessor

これは、終了したspanを渡し、終了したspanをそのままエクスポートに適した表現に変換して設定済みの`SpanExporter`へ渡す`SpanProcessor`の実装です。

このプロセッサーは、`SpanExporter`の`Export`への呼び出しが並行して呼び出されないよう、それらの呼び出しをMUST同期するものとします。

**設定可能なパラメータ:**

* `exporter` - spanが送られるエクスポーター。

#### バッチ処理を行うSpanProcessor

これは、終了したspanのバッチを作成し、そのエクスポートに適した表現を設定済みの`SpanExporter`へ渡す`SpanProcessor`の実装です。

このプロセッサーは、`SpanExporter`の`Export`への呼び出しが並行して呼び出されないよう、それらの呼び出しをMUST同期するものとします。

このプロセッサーは、以下のいずれかが起こり、かつ直前のexport呼び出しが既に返っている場合にバッチをSHOULDエクスポートするものとします。

- プロセッサーが構築されてから、または最初のspanがそのspan processorに受け取られてから`scheduledDelayMillis`が経過したとき。
- 直前のexportタイマーが終了してから、または直前のexportが完了してから、あるいは直前のexportタイマーの終了後もしくは直前のバッチの完了後に最初のspanがキューに追加されてから`scheduledDelayMillis`が経過したとき。
- キューに`maxExportBatchSize`個以上のspanが含まれているとき。
- `ForceFlush`が呼び出されたとき。

exportが発生した時点でキューが空である場合、プロセッサーは空のバッチをエクスポートしても、エクスポートをスキップして直ちに完了したものとみなしてもかまいません（MAY）。

**設定可能なパラメータ:**

* `exporter` - spanが送られるエクスポーター。
* `maxQueueSize` - 最大のキューサイズ。このサイズに達すると、spanは破棄されます。デフォルト値は`2048`です。
* `scheduledDelayMillis` - 連続する2回のexportの間の最大の遅延間隔（ミリ秒）。デフォルト値は`5000`です。
* `exportTimeoutMillis` - exportがキャンセルされるまでに実行できる時間。デフォルト値は`30000`です。
* `maxExportBatchSize` - 1回のexportあたりの最大バッチサイズ。`maxQueueSize`以下でなければなりません。キューが`maxExportBatchSize`に達すると、`scheduledDelayMillis`ミリ秒が経過していなくてもバッチがエクスポートされます。デフォルト値は`512`です。

## SpanExporter

`SpanExporter`は、OpenTelemetry SDKにプラグインしてテレメトリーデータの送信をサポートするために、プロトコル固有のエクスポーターが実装しなければならないインターフェースを定義します。

このインターフェースの目的は、プロトコルに依存するテレメトリーエクスポーターの実装の負担を最小化することです。プロトコルエクスポーターは、主にシンプルなテレメトリーデータのエンコーダーおよび送信者であることが期待されます。

各実装は、SDKがそのエクスポーターに要求する並行性の特性をMUST文書化するものとします。

### インターフェース定義

エクスポーターは、**Export**、**Shutdown**、**ForceFlush**の3つの機能をMUSTサポートするものとします。強く型付けされた言語では、通常シグナルごとに個別の`Exporter`インターフェース（`SpanExporter`など）が存在します。

#### `Export(batch)`

[readable span](#追加のspanインターフェース)のバッチをエクスポートします。この機能を実装するプロトコルエクスポーターは、典型的にはデータをシリアライズして宛先へ送信することが期待されます。

Export()は、同じエクスポーターインスタンスに対する他の`Export`呼び出しと並行して呼び出されるべきではありません。

実装によっては、exportの結果は、Export()の呼び出しの戻り値としてではなく、非同期タスクの完了を伝えるための言語固有の方法でプロセッサーへ返されることがあります。つまり、あるエクスポーターのインスタンスのExport()が並行して呼び出されるべきでないとしても、それはエクスポートというタスク自体を並行に行えないことを意味しません。これをどのように行うかは本仕様書の範囲外です。

Export()は無期限にブロックしてはならず（MUST NOT）、それを超えるとエラー結果（`Failure`）でタイムアウトしなければならない、妥当な上限が存在しなければなりません（MUST）。

並行リクエストとリトライロジックはエクスポーターの責務です。必要となるロジックはspanの送信先となる特定のプロトコルとバックエンドに大きく依存する可能性が高いため、デフォルトSDKのSpan Processorはリトライロジックを実装すべきではありません（SHOULD NOT）。例えば、[OpenTelemetry Protocol（OTLP）仕様書](https://opentelemetry.io/docs/specs/otlp/)は、並行リクエストの送信とリクエストの再試行の両方についてロジックを定義しています。

**パラメータ:**

batch - [readable span](#追加のspanインターフェース)のバッチ。バッチの正確なデータ型は言語固有であり、典型的には何らかのリストです。例えばJavaのspanでは典型的には`Collection<SpanData>`になります。

**戻り値:** ExportResult:

Export()の戻り値は実装固有です。その言語にとってイディオマティックな方法で、Exporterはプロセッサーに`ExportResult`を送信しなければなりません（MUST）。`ExportResult`は`Success`または`Failure`のいずれかの値を持ちます。

* `Success` - バッチが正常にエクスポートされました。プロトコルエクスポーターの場合、これは典型的にはデータがワイヤー上で送信され、宛先サーバーに配送されたことを意味します。
* `Failure` - エクスポートが失敗しました。バッチは破棄されなければなりません。例えば、これはバッチに不正なデータが含まれていてシリアライズできない場合に発生することがあります。

例えば、Javaでは、Export()の戻り値は完了時に`ExportResult`オブジェクトを返すFutureになります。一方Erlangでは、Exporterは特定のspanのバッチに対する`ExportResult`を含むメッセージをプロセッサーへ送信します。

#### `Shutdown()`

エクスポーターをシャットダウンします。SDKがシャットダウンされる際に呼び出されます。これはエクスポーターが必要なクリーンアップを行う機会です。

`Shutdown`は`Exporter`インスタンスごとに一度だけ呼び出されるべきです。`Shutdown`の呼び出し後、`Export`への以後の呼び出しは許可されず、`Failure`結果を返すべきです。

`Shutdown`は（例えばデータをフラッシュしようとして宛先が利用できない場合など）無期限にブロックすべきではありません。OpenTelemetryクライアントの実装者は、シャットダウンのタイムアウトを設定可能にするかどうかを決めてかまいません。

#### `ForceFlush()`

これは、`ForceFlush`の呼び出しより前にエクスポーターが受け取っていた`Span`のエクスポートが、できる限り早く、望ましくはこのメソッドから戻る前に完了しているべきことを示すヒントです（SHOULD）。

`ForceFlush`は、呼び出し元に成功・失敗・タイムアウトのいずれであったかを知らせる手段をSHOULD提供するものとします。

`ForceFlush`は、プロセスを中断させてから完了したspanをエクスポートする前にプロセスを停止させてしまう可能性のある一部のFaaSプロバイダーを使う場合など、絶対に必要な場合に限りSHOULD呼び出されるものとします。

`ForceFlush`は、ある程度のタイムアウト内に完了または中断すべきです（SHOULD）。`ForceFlush`は、ブロッキングAPIとして実装しても、コールバックやイベントを通じて呼び出し元に通知する非同期APIとして実装してもかまいません。OpenTelemetryクライアントの実装者は、フラッシュのタイムアウトを設定可能にするかどうかを決めてかまいません。

### 言語ごとの特化

上記で示した汎用的なインターフェース定義に基づき、ライブラリの実装者は特定の言語に対する正確なインターフェースを定義しなければなりません。

実装者は、プロトコルエクスポーターによるワイヤーフォーマットへの高速なシリアライズに適し、メモリマネージャへの負荷を最小化する、効率的なデータ構造をインターフェースの境界で使うことが推奨されます。後者は典型的には、急速に生成され短命なテレメトリーデータ構造を、その言語固有のメモリマネージャにとって扱いやすい形に最適化する方法を理解している必要があります。一般的な推奨は、割り当ての回数を最小化し、可能であればアロケーションアリーナを使うことで、テレメトリーデータの生成率が高い状況で割り当て・解放・回収の操作が爆発的に増えることを避けることです。

#### 例

以下は、特定の言語における`Exporter`インターフェースがどのようなものになりうるかの例です。これらの例はあくまで説明のためのものです。OpenTelemetryクライアントの実装者は、その設計が`Exporter`という概念の精神に忠実であれば、これらの例から自由に外れてかまいません。

##### GoにおけるSpanExporterインターフェース

```go
type SpanExporter interface {
    Export(batch []ExportableSpan) ExportResult
    Shutdown()
}

type ExportResult struct {
    Code         ExportResultCode
    WrappedError error
}

type ExportResultCode int

const (
    Success ExportResultCode = iota
    Failure
)
```

##### JavaにおけるSpanExporterインターフェース

```java
public interface SpanExporter {
 public enum ResultCode {
   Success, Failure
 }

 ResultCode export(Collection<ExportableSpan> batch);
 void shutdown();
}
```

## 並行性の要件

並行実行をサポートする言語について、Tracing SDKは特定の保証と安全性を提供します。

**TracerProvider** - Tracerの作成、`ForceFlush`、`Shutdown`は並行して呼び出されて安全でなければなりません（MUST）。

**Sampler** - `ShouldSample`と`GetDescription`は並行して呼び出されて安全でなければなりません（MUST）。

**SpanProcessor** - すべてのメソッドは並行して呼び出されて安全でなければなりません（MUST）。

**SpanExporter** - `ForceFlush`と`Shutdown`は並行して呼び出されて安全でなければなりません（MUST）。

## セルフオブザーバビリティ

**ステータス**: [Development](../../document-status/)

Tracing SDKは[SDKのセルフオブザーバビリティ](../../self-observability/)をSHOULDサポートするものとします。

