> Source: https://www.ymotongpoo.com/works/oteps/trace/otep-4673/


# OTEP-4673: TraceState: 確率的サンプリング

**ステータス**: アーカイブ済み

このドキュメントには、古い実験的な「tracestateによる確率的サンプリング」仕様の最終状態が記載されています。
この仕様は、OpenTelemetryの仕様から削除した後も参照できるように、OTEPとして記録されています。

以下に、このドキュメントに加えられた変更点の概要を示します。

- [`sdk.md`][SDK_SPEC] へのリンクについて: 参照は一般的なものでした。というのも、SDK仕様がこのドキュメントを参照するように更新されることはなかったためです。これらのリンクは、将来的にリンク切れが起きないよう、現在の固定リンクに更新されました。
- [`tracestate-handling.md`][TRACESTATE_HANDLING] へのリンクについて: これらのリンクは、[PR#4162](https://github.com/open-telemetry/opentelemetry-specification/pull/4162) が新しい仕様を追加する前の、このファイルが書かれた当時のバージョンに更新されました。
- 目次を削除しました。

[TRACESTATE_HANDLING]: https://github.com/open-telemetry/opentelemetry-specification/blob/ec3779c3d0044503a1ec/specification/trace/tracestate-handling.md
[SDK_SPEC]: https://github.com/open-telemetry/opentelemetry-specification/blob/03e4ea2748e18e63d1e00e58e373ca55768fb1b0/specification/trace/sdk.md
[SDK_SPEC#parentbased]: https://github.com/open-telemetry/opentelemetry-specification/blob/03e4ea2748e18e63d1e00e58e373ca55768fb1b0/specification/trace/sdk.md#parentbased
[SDK_SPEC#sampler]: https://github.com/open-telemetry/opentelemetry-specification/blob/03e4ea2748e18e63d1e00e58e373ca55768fb1b0/specification/trace/sdk.md#sampling
[SDK_SPEC#traceidratiobased]: https://github.com/open-telemetry/opentelemetry-specification/blob/03e4ea2748e18e63d1e00e58e373ca55768fb1b0/specification/trace/sdk.md#traceidratiobased

## Overview {#overview}

確率的サンプリングにより、OpenTelemetryのトレーシング利用者は、ランダム化されたサンプリング手法を使ってスパンの収集コストを下げることができます。
目的は次のとおりです。

- 既存のW3C trace contextの `sampled` フラグと互換性がある
- Span-to-metricsパイプラインを使ってスパンを正確にカウントできる
- スパンが独立してサンプリングの決定を行う場合でも、トレースが完全になる傾向がある

このドキュメントでは、「r-value」と「p-value」に基づく手法を規定します。
非常に大まかに言うと、r-valueはランダム性の源であり、p-valueはサンプリング確率をエンコードします。
`p <= r` のとき、コンテキストはサンプリングされます。

重要な点として、r-valueとp-valueをOpenTelemetryの `tracestate` に含めることで、これら2つの値はコンテキストを通じて自動的に伝播し、すべてのスパンに記録されます。
これにより、トレースの利用者は、あるスパンのp-valueを解釈するだけで、スパンを正しくカウントできるようになります。

効率のため、サポートされるサンプリング確率は2のべき乗に限定されます。
p-valueはサンプリング確率から導出され、`2**-p` に等しくなります。
したがって、p-valueは符号なし整数を使ってエンコードされます。

たとえば、p-valueが3であれば、サンプリング確率が1/8であることを示します。

W3C trace contextは、TraceIdの128ビットのうち何ビットが真の一様分布ランダムビットであるかを規定していないため、追加のランダム性の源としてr-valueが導入されています。

「r-value」を生成する推奨方法は、62個のランダムビットからなる文字列の先頭にある0の個数を数えることですが、この方法を使うことは必須ではありません。

### Definitions {#definitions}

#### Sampling {#sampling}

サンプリングとは、完全なデータセットの一部だけを収集・分析するための一連の手法です。
「サンプリング」された個々の項目は、収集・カウントされる際に1つ以上のスパンを代表するとみなされます。
各スパンの代表性は、Span-to-Metricsパイプラインでスパンを正確にカウントするために使用されます。

サンプリングの用語では、サンプリング元となる完全なデータの集合を指すために「母集団 (population)」という言葉を使います。
OpenTelemetryのトレーシングにおいて、「母集団」はすべてのスパンを指します。

確率的サンプリングでは、個々のサンプル項目の代表性は一般に既知ですが、OpenTelemetryは「非確率的 (non-probability)」なサンプリング手法も認識しており、その場合は代表性が明示的に定量化されません。

#### Adjusted count {#adjusted-count}

調整カウント (Adjusted count) は代表性の尺度であり、個々のサンプリングされたスパンによって代表される母集団内のスパンの数です。
Span-to-metricsパイプラインは、各サンプルスパンの調整カウントを、一致するスパンのカウンターに加算することで構築できます。

確率的サンプリングにおいて、調整カウントはサンプリング確率の逆数（つまり数学的な逆数）として定義されます。

非確率的サンプリングにおいて、調整カウントは不明です。

調整カウントがゼロであるという扱いは、確率的サンプリングと非確率的サンプリングの合成をサポートするために定義されています。
確率サンプラーがスパンを選択しなかった場合、調整カウントとしてゼロが割り当てられます。

したがって、調整カウントには意味のある3つのカテゴリーがあります。

| 調整カウント | 解釈 |
| -- | -- |
| _不明 (Unknown)_ | 調整カウントが不明である。非確率的サンプラーの結果である可能性がある。このカテゴリーの項目はカウントすべきではない |
| _ゼロ (Zero)_ | 調整カウントは既知であり、その項目の実効カウントはゼロである |
| _非ゼロ (Non-zero)_ | 調整カウントは既知であり、その項目の実効カウントはゼロより大きい |

#### Sampler {#sampler}

サンプラーは、トレーシングクライアントライブラリにおいて、どのスパンを「記録 (record)」および／または「サンプリング (sample)」するかを選択するための、SDKが使用する設定可能なロジックを提供します。
スパンを「記録する」とは、クライアントのメモリ内にその表現を構築することを意味し、これによりエクスポート対象となる資格を得ます。
スパンを「サンプリングする」とは、W3Cの `sampled` フラグを設定し、スパンを記録し、スパンが終了したときにそれをエクスポートすることを意味します。

OpenTelemetryは、ライブなスパンのプロセス内での可観測性（たとえばzページ）のために、「記録」されるが「サンプリング」されないスパンをサポートします。

Sampler インターフェースおよびOpenTelemetryが定義する組み込みのサンプラーは、スパンをサンプリングするかどうかを即座に決定し、子コンテキストはその決定を即座に伝播します。

#### Parent-based sampler {#parent-based-sampler}

コンテキストからのW3Cの `sampled` フラグに基づいてサンプリングの決定を行うサンプラーは、Parentベースのサンプリングを使用しているといいます。

#### Probability sampler {#probability-sampler}

確率サンプラーとは、その決定のそれぞれについて、そのスパンが選択される確率を即座に把握しているサンプラーです。

サンプリング確率は、1以下かつ0より大きい数として定義されます（つまり `0 < probability <= 1`）。
確率0のケースは、特殊な非確率的なケースとして扱われます。

#### Consistent probability sampler {#consistent-probability-sampler}

一貫性のある確率サンプラーとは、トレース内の各スパンで独立したサンプリングの決定をサポートしながら、トレース全体にわたる特定の最小確率でトレースが完全になることを維持するサンプラーです。

一貫性のある確率的サンプリングでは、あるトレース内の任意のスパンについて、より小さいサンプリング確率を持つサンプラーがそのスパンをサンプリングのために選択した場合、より大きい確率で設定されたサンプラーによってもそのスパンが選択されることが要求されます。

#### Trace completeness {#trace-completeness}

トレースは、そのトレースに属するすべてのスパンが収集されたときに完全であるといいます。
少なくとも1つのスパンが収集されているものの、すべてのスパンが収集されていない場合、そのトレースは不完全とみなされます。

トレースの不完全性は、意図的に（たとえばサンプリング設定を通じて）生じる場合もあれば、偶発的に（たとえば収集エラーを通じて）生じる場合もあります。
OpenTelemetryのトレースデータモデルは、不完全性についての*一方向の*テストをサポートします。
ルート以外の任意のスパンについて、そのスパンの親スパンが収集されていなければ、そのトレースは確実に不完全です。

サンプリング設定の結果として生じる（つまり意図的な）不完全なトレースは、部分トレースとして知られています。
部分トレースの中でも重要な部分集合は、完全なサブトレースでもあるものです。
完全なサブトレースは、あるスパンにおいて、そのすべての子孫スパンが収集されているときに定義されます。

不完全性のテストは一方向であるため、どのサンプリング設定が不完全なトレースにつながる可能性があるかを知ることが重要です。
完全なトレースおよび完全なサブトレースに自然につながるサンプリング設定については、[以下で議論します](#trace-producer-completeness)。

#### Non-probability sampler {#non-probability-sampler}

非確率的サンプラーとは、偶然ではなく、任意のロジックと内部状態に基づいて決定を行うサンプラーです。
非確率的サンプラーによってサンプリングされたスパンの調整カウントは不明です。

#### Always-on consistent probability sampler {#always-on-consistent-probability-sampler}

Always-onサンプラーは、確率1の一貫性のある確率サンプラーの別名です。

#### Always-off sampler {#always-off-sampler}

Always-offサンプラーは、スパンを完全に無効化する効果を持ち、事実上そのスパンを母集団から除外します。
これは、ゼロパーセント確率のサンプラーではなく非確率的サンプラーとして定義されます。
なぜなら、そのスパンは事実上代表されないからです。

## Consistent Probability sampling {#consistent-probability-sampling}

OpenTelemetryが採用する一貫性のあるサンプリング方式は、「p-value」と「r-value」と呼ばれる2つの値をコンテキストを通じて伝播します。

両方のフィールドは、[tracestate仕様][TRACESTATE_HANDLING]の規則に従って、`ot` ベンダータグの下でOpenTelemetryの `tracestate` を介して伝播されます。
両方のフィールドは、最大6ビットの情報を必要とする符号なし10進整数として表現されます。

このサンプリング方式は、固定された63個の異なる確率値の集合から項目を選択します。
サポートされる確率の集合には、1から2の-62乗までの2の整数べき乗が含まれます。
ゼロ確率および2の-62乗より小さい確率は、単位確率（つまり100%）が「ConsistentAlwaysOn」サンプラーの特殊なケースを表すのと同様に、「ConsistentAlwaysOff」サンプラーの特殊なケースとして扱われます。

R-valueは、63通りの可能性のうち、あるトレースについて一貫してサンプリングを決定するのはどれかをエンコードします。
具体的には、r-valueは、対応するp-valueの観点から、あるトレースをサンプリングすると決定する最小の確率を指定します。
たとえば、r-value 0を持つトレースは100%サンプリング用に設定されたスパンをサンプリングし、r-value 1は50%または100%サンプリング用に設定されたスパンをサンプリングし、以下同様に、r-value 62まで続きます。
r-value 62では、一貫性のある確率サンプラーは、サポートされるすべての確率（つまり2の-62乗以上）において「サンプリングする」と決定します。

P-valueは、子コンテキスト（つまり `tracestate` の利用者）と、Span-to-metricsパイプラインで使用するために記録するサンプルスパンの利用者のための調整カウントをエンコードします。
特別なp-value 63は、調整カウントがゼロであることを意味するよう定義されており、非確率的サンプラーの合成規則を定義する助けとなります。

`traceparent` に含まれる `sampled` トレースフラグと、`tracestate` に含まれるr-valueおよびp-valueとを結びつける不変条件が規定されます。

### Conformance {#conformance}

OpenTelemetryの `tracestate` データの利用者は、そのデータを解釈する前に、確率的サンプリングのフィールドを検証することが期待されます。
これは、ここで規定される2つのサンプラーだけでなく、スパンデータの利用者にも当てはまり、スパンの調整カウントを解釈する前に `tracestate` を検証することが期待されます。

p-valueとr-valueのフィールドを含むOpenTelemetryの `tracestate` を生成する側は、`ConsistentProbabilityBased` サンプラーに対して述べられている振る舞い上の要件を満たし、統計的に妥当な結果を保証する必要があります。
この仕様にはテストスイートが含まれており、利用者やOpenTelemetryの `tracestate` の利用者は、Span-to-metricsパイプラインにおける正確性を確認できます。

### Completeness guarantee {#completeness-guarantee}

この仕様は、2のべき乗のサンプリング確率に対する一貫性のあるサンプリングを規定します。
サンプラーが2のべき乗でないサンプリング確率で設定された場合、サンプラーは最も近い2つのべき乗の間で確率的に選択します。

トレースのルートで単一の一貫性のある確率サンプラーが使用され、他のすべてのスパンがParentベースのサンプラーを使用する場合、結果として得られるトレースは常に完全になります（収集エラーは無視します）。
この性質は、2のべき乗でないサンプリング確率であっても成立します。

同じトレース内で複数の一貫性のある確率サンプラーが使用される場合、一般に、トレースの完全性は、トレース全体における最小のサンプリング確率以上となる最小の2のべき乗において保証されます。

### Context invariants {#context-invariants}

W3Cの `traceparent`（バージョン0）には、TraceId、SpanId、トレースフラグという3つの情報フィールドが含まれます。
`sampled` トレースフラグは、コンテキストをサンプリングする意図を伝えるものとしてW3Cによって定義されています。

[Sampler API][SDK_SPEC#sampler] は、`sampled` フラグと `tracestate` を設定する役割を担います。

P-valueとr-valueは、識別子 `p` と `r` を使って、ベンダータグ `ot` の下でOpenTelemetryの `tracestate` に設定されます。
P-valueは、`[0, 63]` の範囲（つまり64個の有効な値がある）で有効な符号なし整数です。
R-valueは、`[0, 62]` の範囲（つまり63個の有効な値がある）で有効な符号なし整数です。
P-valueとr-valueは独立した設定であり、それぞれ他方が存在しなくても意味を持って設定できます。

#### Sampled flag {#sampled-flag}

確率的サンプリングは、一貫性のある意思決定を可能にし、サンプリングされたスパンの調整カウントを記録するために、追加の情報を使用します。
両方の値が定義されていて指定された範囲内にある場合、r-valueとp-valueと `sampled` トレースフラグの間の不変条件は、`((p <= r) == sampled) OR (sampled AND (p == 63)) == TRUE` であると述べています。

`sampled`、`p`、`r` の間の不変条件は、`p` と `r` の両方が存在する場合にのみ適用されます。
不変条件に違反する場合、`sampled` フラグが優先され、調整カウントが不明であることを知らせるために `tracestate` から `p` が解除されます。

##### Requirement: Inconsistent p-values are unset {#requirement-inconsistent-p-values-are-unset}

サンプラーは、`tracestate` を使ってサンプリングの決定を行ったり調整カウントを解釈したりする前に、`sampled`、`p`、`r` の値の間の不変条件に違反している場合、`p` を解除すべきです（SHOULD）。

#### P-value {#p-value}

調整カウントがゼロであることは、特別なp-value 63で表されます。
それ以外の場合、p-valueはサンプリング確率の底2の対数の負の値に設定されます。

| p-value | 親の確率 | 調整カウント |
| -----   | -----------        | --             |
| 0       | 1                  | 1              |
| 1       | 1/2                | 2              |
| 2       | 1/4                | 4              |
| ...     | ...                | ...            |
| N       | 2**-N              | 2**N           |
| ...     | ...                | ...            |
| 61      | 2**-61             | 2**61          |
| 62      | 2**-62             | 2**62          |
| 63      | 0                  | 0              |

##### Requirement: Out-of-range p-values are unset {#requirement-out-of-range-p-values-are-unset}

利用者は、符号なし10進数の値が63より大きい場合、サンプリングの決定を行ったり調整カウントを解釈したりする前に、`tracestate` から `p` を解除すべきです（SHOULD）。

#### R-value {#r-value}

R-valueは、一貫性のある確率的サンプリングをサポートするために、トレースのルートにあるサンプラーによって `tracestate` に設定されます。
この値が省略されている、または存在しない場合、トレース内の子スパンは一貫性のある確率的サンプリングに参加できません。

R-valueは、次のように、あるトレースのスパンについてどのサンプリング確率がサンプリングする、またはしないと決定するかを決定します。

| r-value          | 示唆されるサンプリング確率 |
| ---------------- | ----------------------         |
| 0                | 1                              |
| 1                | 1/2 and above                  |
| 2                | 1/4 and above                  |
| 3                | 1/8 and above                  |
| ...              | ...                            |
| 0 <= r <= 61     | 2**-r and above                |
| ...              | ...                            |
| 59               | 2**-59 and above               |
| 60               | 2**-60 and above               |
| 61               | 2**-61 and above               |
| 62               | 2**-62 and above               |

これらの確率は、準拠するSampler実装が正しい調整カウントを持つスパンを記録することを保証するために規定されています。
r-valueを生成する推奨方法は、62個のランダムビットからなる文字列の先頭にある0の個数を数えることですが、この方法を使うことは必須ではありません。

##### Requirement: Out-of-range r-values unset both p and r {#requirement-out-of-range-r-values-unset-both-p-and-r}

サンプラーは、`tracestate` を使ってサンプリングの決定を行う前に、`r` の符号なし10進数の値が62より大きい場合、`r` と `p` の両方を `tracestate` から解除すべきです（SHOULD）。

##### Requirement: R-value is generated with the correct probabilities {#requirement-r-value-is-generated-with-the-correct-probabilities}

サンプラーは、62個のランダムビットからなる文字列の先頭にある0の個数を数えることで生成される値と同等の確率で各値を生成する、ランダム化された方式を使ってr-valueを生成しなければなりません（MUST）。

#### Examples: Context invariants {#examples-context-invariants}

##### Example: Probability sampled context {#example-probability-sampled-context}

次のヘッダーを持つトレースコンテキストを考えます。

```
traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
tracestate: ot=r:3;p:2
```

この例における `traceparent` の内容は、[W3Cの仕様](https://www.w3.org/TR/trace-context/#examples-of-http-traceparent-headers) から引用したものであり、以下のbase64エンコードされたフィールド値を持ちます。

```
base16(version) = 00
base16(trace-id) = 4bf92f3577b34da6a3ce929d0e0e4736
base16(parent-id) = 00f067aa0ba902b7
base16(trace-flags) = 01  // (i.e., sampled)
```

`tracestate` ヘッダーには、10進数でエンコードされたp-valueとr-valueを含むOpenTelemetryの文字列 `r:3;p:2` が含まれます。

```
base10(r) = 3
base10(p) = 2
```

ここで、r-value 3は、12.5%（つまり8分の1）以上の確率で設定された一貫性のある確率サンプラーがこのトレースをサンプリングすることを示しています。
p-value 2は、`sampled` フラグを設定した親が25%（つまり4分の1）でサンプリングするよう設定されていたことを示しています。
`p <= r` が真であり `sampled` フラグが設定されているため、このトレースコンテキストは一貫性があります。

##### Example: Probability unsampled {#example-probability-unsampled}

この例は、r-valueのみが設定された、サンプリングされていないコンテキストです。

```
traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00
tracestate: ot=r:3
```

r-valueを持つことで、子コンテキストにおける一貫性のある確率的サンプリングをサポートします。
p-valueは設定されておらず、これはサンプリングされていないコンテキストと整合しています。

### Samplers {#samplers}

#### ParentConsistentProbabilityBased sampler {#parentconsistentprobabilitybased-sampler}

`ParentConsistentProbabilityBased` サンプラーは、[`ParentBased` サンプラー][SDK_SPEC#parentbased] のオプションの代替として意図されています。
このサンプラーは、まず `tracestate` を検証し、その後W3Cの traceparentにおける `sampled` フラグを尊重する必要があります。

##### Requirement: ParentConsistentProbabilityBased API {#requirement-parentconsistentprobabilitybased-api}

`ParentConsistentProbabilityBased` サンプラーのコンストラクターは、単一のSampler引数を取るべきです（SHOULD）。
これは、`ParentConsistentProbabilityBased` サンプラーがルートスパンに対して呼び出された場合に使用するサンプラーです。

##### Requirement: ParentConsistentProbabilityBased does not modify valid tracestate {#requirement-parentconsistentprobabilitybased-does-not-modify-valid-tracestate}

`ParentConsistentProbabilityBased` サンプラーは、有効な `tracestate` を変更してはなりません（MUST NOT）。

##### Requirement: ParentConsistentProbabilityBased calls the configured root sampler for root spans {#requirement-parentconsistentprobabilitybased-calls-the-configured-root-sampler-for-root-spans}

`ParentConsistentProbabilityBased` サンプラーは、有効な親トレースコンテキストが存在しない場合、設定されたルートサンプラーに委譲しなければなりません（MUST）。

##### Requirement: ParentConsistentProbabilityBased respects the sampled flag for non-root spans {#requirement-parentconsistentprobabilitybased-respects-the-sampled-flag-for-non-root-spans}

`ParentConsistentProbabilityBased` サンプラーは、W3Cの traceparentヘッダーにおける `sampled` フラグの値に従って、そのスパンをサンプリングするかどうかを決定しなければなりません（MUST）。

#### ConsistentProbabilityBased sampler {#consistentprobabilitybased-sampler}

`ConsistentProbabilityBased` サンプラーは、[`TraceIdRatioBased` サンプラー][SDK_SPEC#traceidratiobased] のオプションの代替として意図されています。
ルートサンプラーとして使用される場合、`ConsistentProbabilityBased` サンプラーは有効な `tracestate` を生成する必要があります。
ルート以外のコンテキストで使用される場合、受信した `tracestate` を検証し、送信するコンテキストに対して有効な `tracestate` を生成する必要があります。

`ConsistentProbabilityBased` サンプラーは、正確な2のべき乗ではない確率をサポートする必要があります。
そのためには、実装は最も近い2つのべき乗の間で確率的に選択する必要があります。
たとえば、5%サンプリングは、60%の確率で1/16サンプリングを選択し、40%の確率で1/32サンプリングを選択することで達成できます。

##### Requirement: TraceIdRatioBased API compatibility {#requirement-traceidratiobased-api-compatibility}

`ConsistentProbabilityBased` サンプラーは、各OpenTelemetry SDKに組み込まれている `TraceIdRatioBased` サンプラーと同じコンストラクターシグネチャを持たなければなりません（MUST）。

##### Requirement: ConsistentProbabilityBased sampler sets r for root span {#requirement-consistentprobabilitybased-sampler-sets-r-for-root-span}

`ConsistentProbabilityBased` サンプラーは、ルートのサンプリング決定を行う際に `r` を設定しなければなりません（MUST）。

##### Requirement: ConsistentProbabilityBased sampler un-sets p when not sampled {#requirement-consistentprobabilitybased-sampler-un-sets-p-when-not-sampled}

`ConsistentProbabilityBased` サンプラーは、サンプリングしないと決定した場合、`tracestate` から `p` を解除しなければなりません（MUST）。

##### Requirement: ConsistentProbabilityBased sampler sets p when sampled {#requirement-consistentprobabilitybased-sampler-sets-p-when-sampled}

`ConsistentProbabilityBased` サンプラーは、設定されたサンプリング確率に従ってサンプリングすると決定した場合、`p` を設定しなければなりません（MUST）。

##### Requirement: ConsistentProbabilityBased sampler records unbiased adjusted counts {#requirement-consistentprobabilitybased-sampler-records-unbiased-adjusted-counts}

ゼロでない確率を持つ `ConsistentProbabilityBased` サンプラーは、`tracestate` から解釈される調整カウントが、母集団内の代表スパン数の不偏推定値となるように `p` を設定しなければなりません（MUST）。

##### Requirement: ConsistentProbabilityBased sampler sets r for non-root span {#requirement-consistentprobabilitybased-sampler-sets-r-for-non-root-span}

入力の traceコンテキストに `r` が設定されておらず、かつそのスパンがルートスパンでない場合、`ConsistentProbabilityBased` は、あたかもルートスパンであるかのように `r` を設定し、潜在的に一貫性のないトレースが生成されていることを利用者に警告すべきです（SHOULD）。

##### Requirement: ConsistentProbabilityBased sampler decides not to sample for probabilities less than 2**-62 {#requirement-consistentprobabilitybased-sampler-decides-not-to-sample-for-probabilities-less-than-2-62}

設定されたサンプリング確率が区間 `[0, 2**-62)` 内にある場合、サンプラーはサンプリングしないと決定しなければなりません（MUST）。

#### Examples: Consistent probability samplers {#examples-consistent-probability-samplers}

##### Example: Setting R-value for a root span {#example-setting-r-value-for-a-root-span}

新しいルートスパンが、一貫性のある確率サンプラーによって25%でサンプリングされます。
新しいr-valueを生成する必要があります（適切な方法については付録を参照）。
この例では、1.5625%の確率で発生し、サンプリングすることを示すr-value 5が使用されます。

```
tracestate: ot=r:5;p:2
```

p-value 2はr-value 5以下であるため、このスパンはサンプリングされます。
r-value 1が25%でサンプリングしないことを示す `tracestate` の例を次に示します。

```
tracestate: ot=r:1
```

p-value 2（25%サンプリングに対応）がr-value 1より大きいため、このスパンはサンプリングされません。

##### Example: Handling inconsistent P-value {#example-handling-inconsistent-p-value}

一貫性のある確率サンプラーまたはParentベースの一貫性のある確率サンプラーが、サンプリングされたコンテキストを受信したものの、p-valueが無効である場合を考えます。
たとえば、

```
tracestate: ot=r:4;p:73
```

`tracestate` はそのp-valueが取り除かれます。
r-valueは保持され、サンプラーは以下を受信したかのように振る舞うべきです。

```
tracestate: ot=r:4
```

一貫性のある確率サンプラーは、受信したr-valueを使って独自の（一貫性のある）決定を行います。

Parentベースの一貫性のある確率サンプラーは、この場合 `sampled` フラグに従います。
コンテキストがサンプリングされている場合、結果として得られるスパンはp-valueを持たないr-valueを持つことになり、これは調整カウントが不明であることを示します。

##### Example: Handling corrupt R-value {#example-handling-corrupt-r-value}

ルート以外のスパンが次を受信します。

```
tracestate: ot=r:100;p:10
```

ここでr-valueは有効範囲外です。
不変条件に従い、検証時にr-valueとp-valueが取り除かれます。
この場合、サンプラーは `tracestate` を受信していないかのように振る舞います。

この場合、Parentベースの一貫性のある確率サンプラーは、`sampled` フラグに基づいてサンプリングするかしないかを決定します。
コンテキストがサンプリングされている場合、記録されるスパンはp-valueを持たないr-valueを持つことになり、これは調整カウントが不明であることを示します。

一貫性のある確率サンプラーは、新しいr-valueを生成し、破損した可能性のある一貫性のないr-valueについて利用者に警告しながら、新しいサンプリングの決定を行います。

### Composition rules {#composition-rules}

複数のサンプラーがコンテキストをサンプリングする決定に関与する場合、それらの決定は合成規則を使って組み合わせることができます。
すべての場合において、組み合わされたサンプリングの決定は、各サンプラーの決定の論理和です（つまり、合成対象のサンプラーのうち少なくとも1つがサンプリングを決定すればサンプリングします）。

2つの一貫性のある確率サンプラーの決定からp-valueを組み合わせるには、確率がより大きい方のサンプラーが効力を持ちます。
出力されるp-valueは、両者の `p` の値のうち最小値になります。

一貫性のある確率サンプラーの決定と非確率的サンプラーの決定を組み合わせるには、p-value 63を使って調整カウントがゼロであることを示します。
確率サンプラーがサンプリングすると決定した場合、そのp-valueが効力を持ちます。
非確率的サンプラーがサンプリングする一方で確率サンプラーがサンプリングしないと決定した場合、調整カウントがゼロであることを示すp-value 63が効力を持ちます。

#### List of requirements {#list-of-requirements}

##### Requirement: Combining multiple sampling decisions using logical `or` {#requirement-combining-multiple-sampling-decisions-using-logical-or}

複数のサンプラーが合成によって組み合わされる場合、組み合わされたサンプラーのうち少なくとも1つがサンプリングを決定すれば、サンプリングの決定はサンプリングすることでなければなりません（MUST）。

##### Requirement: Combine multiple consistent probability samplers using the minimum p-value {#requirement-combine-multiple-consistent-probability-samplers-using-the-minimum-p-value}

複数の一貫性のある確率サンプラーについてサンプラーの決定を組み合わせ、少なくとも1つがサンプリングすると決定した場合、`tracestate` には「サンプリングする」と決定した `p` の値のうち最小のものを設定しなければなりません（MUST）。

##### Requirement: Unset p when multiple consistent probability samplers decide not to sample {#requirement-unset-p-when-multiple-consistent-probability-samplers-decide-not-to-sample}

複数の一貫性のある確率サンプラーについてサンプラーの決定を組み合わせ、いずれもサンプリングしないと決定した場合、`tracestate` においてp-valueを解除しなければなりません（MUST）。

##### Requirement: Use probability sampler p-value when its decision to sample is combined with non-probability samplers {#requirement-use-probability-sampler-p-value-when-its-decision-to-sample-is-combined-with-non-probability-samplers}

一貫性のある確率サンプラーと非確率的サンプラーについてサンプラーの決定を組み合わせ、確率サンプラーがサンプリングすると決定した場合、非確率的サンプラーの決定にかかわらず、そのp-valueを `tracestate` に設定しなければなりません（MUST）。

##### Requirement: Use p-value 63 when a probability sampler decision not to sample is combined with a non-probability sampler decision to sample {#requirement-use-p-value-63-when-a-probability-sampler-decision-not-to-sample-is-combined-with-a-non-probability-sampler-decision-to-sample}

一貫性のある確率サンプラーと非確率的サンプラーについてサンプラーの決定を組み合わせ、確率サンプラーがサンプリングしないと決定した一方で非確率的サンプラーがサンプリングする場合、p-value 63を `tracestate` に設定しなければなりません（MUST）。

#### Examples: Composition {#examples-composition}

##### Example: Probability and non-probability sampler in a root context {#example-probability-and-non-probability-sampler-in-a-root-context}

新しいルートコンテキストにおいて、一貫性のある確率サンプラーが `sampled` フラグを設定しないと決定し、6.5%（つまり16分の1）以上の確率でトレースが一貫してサンプリングされることを示す `r:4` を追加します。

この確率サンプラーの決定は、コンテキストをサンプリングすると決定する非確率的サンプラーと合成されます。
確率サンプラーがサンプリングしていないにもかかわらず `sampled` を設定するには、調整カウントがゼロであることを示す `p:63` の設定が必要です。

結果として得られるコンテキストは次のとおりです。

```
traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
tracestate: ot=r:4;p:63
```

##### Example: Two consistent probability samplers {#example-two-consistent-probability-samplers}

ルートであるかどうかにかかわらず、複数の一貫性のある確率サンプラーが、あるコンテキストをサンプリングすると決定した場合、最小のp-valueがtracestateに出力されます。

ルートコンテキストの場合、2つのサンプラーのうち最初のものが `r:15` と自身のp-value `p:10`（つまり調整カウント1024）を生成します。
2つの確率サンプラーのうち2番目のものは、より小さい調整カウント `p:8`（つまり調整カウント256）を出力します。

結果として得られるコンテキストは、より小さい方のp-valueを採用します。

```
traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
tracestate: ot=r:15;p:8
```

### Producer and consumer recommendations {#producer-and-consumer-recommendations}

#### Trace producer: completeness {#trace-producer-completeness}

[完全性の保証](#completeness-guarantee) で述べたように、同じトレース内で複数の一貫性のある確率サンプラーを設定すると、トレースが不完全になる可能性があります。
不完全なトレースの生成を避ける1つの方法は、ルートスパン以外ではParentベースのサンプラーを使用することです。

トレースの不完全性については単純なテストがありますが、これは一方向のテストであり、子スパンが収集されていないことを検出できません。
不完全なトレースの生成を避ける1つの方法は、ルート以外のスパンに対して2のべき乗ではないサンプリング確率を設定しないことです。
なぜなら、2のべき乗でないサンプリング確率については完全性が保証されないからです。

##### Recommendation: use non-descending power-of-two probabilities {#recommendation-use-non-descending-power-of-two-probabilities}

トレースのルートからリーフに至るまでのサンプリング確率の並びが、非減少の2のべき乗で構成されている場合、完全なサブトレースが生成されます。
完全なサブトレースが確実に生成されるようにするには、子のサンプラーは、親スパンのサンプリング確率以上の2のべき乗の確率で設定されるべきです（SHOULD）。

#### Trace producer: correctness {#trace-producer-correctness}

調整カウントの情報を伝えるためにtracestateを使用することは、トレースの参加者間の信頼に基づいています。
利用者は、親のサンプリング決定に対応する調整カウントが信頼できない場合には、Span-to-metricsパイプラインを使用しないことが推奨されます。

`ConsistentProbabilityBased` および `ParentConsistentProbabilityBased` サンプラーは、スパンやその他の固定属性に基づいてサンプラーの選択を条件付けるために、他のサンプラーの委譲先として使用できます。
しかし、調整カウントが信頼できるものであるためには、ルート以外のサンプラーの選択を、親の `sampled` トレースフラグやOpenTelemetryの `tracestate` のr-valueおよびp-valueに基づいて条件付けることはできません。
なぜなら、そうした決定は誤った調整カウントにつながるからです。

たとえば、組み込みの[`ParentBased` サンプラー][SDK_SPEC#parentbased] は、親コンテキストがリモートか非リモートか、サンプリングされているかいないかに基づいて、委譲先のサンプラーを設定することをサポートしています。
`ParentBased` サンプラーが、サンプリングされていないコンテキストに対してのみ `ConsistentProbabilityBased` サンプラーに委譲する場合、結果として得られるSpan-to-metricsパイプラインは（おそらく）スパンを過剰にカウントすることになります。

##### Recommendation: sampler delegation {#recommendation-sampler-delegation}

ルート以外のスパンについて、合成サンプラーは、親の `sampled` フラグやOpenTelemetryの `tracestate` に基づいて委譲先のサンプラーの選択を条件付けるべきではありません（SHOULD NOT）。

#### Trace producer: interoperability with `ParentBased` sampler {#trace-producer-interoperability-with-parentbased-sampler}

OpenTelemetryに組み込みの `ParentBased` サンプラーは、委譲先のサンプラーがその選択を決定した決定を変更しない限り、`ConsistentProbabilityBased` サンプラーと相互運用可能です。
たとえば、決定がサンプリングされる方向に変わらない限り、サンプリングされていないスパンに対して代替の `ParentBased` サンプラー委譲先を設定しても安全です。

`ParentBased` サンプラーは `sampled` トレースフラグを尊重し、OpenTelemetryのSDKは `Span` データにtracestateを含めるため、システム全体で `TraceIDRatioBased` サンプラーを準拠する `ConsistentProbabilityBased` サンプラーに置き換えるだけで、システムを確率的サンプリングにアップグレードできることを意味します。

#### Trace producer: interoperability with `TraceIDRatioBased` sampler {#trace-producer-interoperability-with-traceidratiobased-sampler}

[`TraceIDRatioBased` の仕様][SDK_SPEC#traceidratiobased] には、トレース全体でサンプラーの決定を一貫させる方法を規定していないため、ルート以外のスパンには使用しないという推奨事項が含まれています。
ルートスパンにおける `TraceIDRatioBased` サンプラーは、完全性の観点では `ConsistentParentProbabilityBased` サンプラーと相互運用可能ですが、結果として得られるスパンの調整カウントは不明になります。

`TraceIDRatioBased` サンプラーがルート以外のスパンに設定される場合、不正なOpenTelemetryのtracestateが生成されるいくつかのケースが生じます。
たとえば、ルート(R)が `ConsistentProbabilityBased` サンプラーを持ち、ルートの子(P)が `TraceIDRatioBased` サンプラーを持ち、孫(C)が `ParentBased` サンプラーを持つ、3つのスパンからなるトレースを考えます。
`TraceIDRatioBased` サンプラーはOpenTelemetryのtracestateを更新せずに中間の `sampled` フラグを変更するため、次のケースが生じます。

1. `TraceIDRatioBased` がPの決定を変更しない場合、トレースは完全であり、すべてのスパンの調整カウントは正しくなります。
2. `TraceIDRatioBased` がPの決定を「いいえ」から「はい」に変更する場合、利用者はPとCを含む（確実に）不完全なトレースを観測します。両方のスパンは無効なOpenTelemetryのtracestateを持ち、この場合、調整カウントが不明になります。
3. `TraceIDRatioBased` がサンプリングの決定を「はい」から「いいえ」に変更する場合、利用者は正しい調整カウントを持つ単一のスパンからなるトレースを観測します。利用者は、Rにサンプリングされていない子孫が2つあることを判断できません。

これらのケースが示すように、利用者は、ルート以外のスパンに `TraceIDRatioBased` サンプラーを使用すると、不完全性と不明な調整カウントが生じることを予期できますが、これは当初規定されていた警告に反しています。

#### Trace consumer {#trace-consumer}

トレースの利用者は、不完全性についての単純な一方向のテストを適用することが期待されます。
ルート以外のスパンが独立したサンプリング確率で設定されている場合、トレースは検出できない形で完全になることがあります。
一方向のテストであるため、完全なトレースを保証したい利用者は、システム全体における最小のサンプリング確率を知っていることが期待されます。

偶発的なデータ損失を無視すると、あるトレースのすべてのスパンが一貫性のある確率サンプラーでサンプリングされ、かつそのトレースのr-valueが、トレース全体における最小のサンプリング確率以上の値に対応する最小の2のべき乗より大きい場合、そのトレースは完全になります。

`ConsistentProbabilityBased` サンプラーには、ルート以外のスパンで `r` が未設定の場合にそれを設定するという要件があるため、トレースの利用者はトレースのr-valueの一貫性を確認することが推奨されます。
単一のトレースに複数の異なる `r` の値が含まれる場合、それはそのトレースがルートで確率的サンプリング用に正しくサンプリングされなかったことを意味します。
このシナリオでは各スパンの調整カウントは正しいものの、完全なトレースを検出することが不可能になる場合があります。

##### Recommendation: Recognize inconsistent r-values {#recommendation-recognize-inconsistent-r-values}

単一のトレースに、`r` について複数の異なる値を持つ `tracestate` の値を持つスパンが含まれる場合、利用者はそのトレースが一貫性なくサンプリングされたと認識すべきです（SHOULD）。

### Appendix: Statistical test requirements {#appendix-statistical-test-requirements}

このセクションでは、サンプリングの決定が不偏であるという要件への基本的な準拠を保証するために実装できるテストを規定します。

このテスト仕様の目標は、実装がシンプルであり、成功のために高度な統計スキルやライブラリを必要としないことです。

このテストは、乱数生成器の性能を評価することを意図したものではありません。
このテストは、基盤となるRNGが十分な品質を持つことを前提とし、サンプラーが高い統計的信頼度で期待される比率を生成することを確認します。

この種のテストの課題の1つは、確率的なテストは時折例外的な結果を生成することが予想される点です。
これをランダムな挙動に対する厳密なテストにするために、以下のアプローチを取ります。

- あらかじめ決められた20個のランダムシードのリストを生成する
- 有意水準（5%）と試行回数（20）に固定値を使用する
- 母集団サイズとして100,000個のスパンを使用する
- 各試行について、母集団をシミュレートし、カイ二乗検定統計量を計算する
- 20試行のうちちょうど1回だけカイ二乗有意性検定が失敗するような、順序付けられたリスト内の最初のシード値を特定する

このテストを作成するには、あらかじめ決められたリストのシード値を順番に使って上記の手順を実行し、ちょうど1回失敗するシード値が見つかるまで続けます。
これはかなり頻繁に起こると予想され、利用可能な20個のシードのうち少なくとも1回は発生することが要求されます。
ちょうど1回のカイ二乗検定失敗を示す最初のシードのインデックスを計算した後、それをテストに記録します。
継続的インテグレーションでのテストのためには、あらかじめ決められたシードインデックスを使ってテストを再実行するだけで十分です。

規定されたとおり、カイ二乗検定は、サンプリング確率が正確な2のべき乗であるかどうかに応じて、1自由度または2自由度を持ちます。

#### Test procedure: non-powers of two {#test-procedure-non-powers-of-two}

この場合、カイ二乗検定には2つの自由度があります。
次の表はテストパラメーターをまとめたものです。

| テストケース | サンプリング確率 | サンプリング時の下側・上側p-value | Expect<sub>lower</sub> | Expect<sub>upper</sub> | Expect<sub>unsampled</sub> |
|-----------|----------------------|-----------------------------------|------------------------|------------------------|----------------------------|
| 1         | 0.900000             | 0, 1                              | 80000                  | 10000                  | 10000                      |
| 2         | 0.600000             | 0, 1                              | 20000                  | 40000                  | 40000                      |
| 3         | 0.330000             | 1, 2                              | 16000                  | 17000                  | 67000                      |
| 4         | 0.130000             | 2, 3                              | 1000                   | 12000                  | 87000                      |
| 5         | 0.100000             | 3, 4                              | 7500                   | 2500                   | 90000                      |
| 6         | 0.050000             | 4, 5                              | 3750                   | 1250                   | 95000                      |
| 7         | 0.017000             | 5, 6                              | 275                    | 1475                   | 98300                      |
| 8         | 0.010000             | 6, 7                              | 437.5                  | 562.5                  | 99000                      |
| 9         | 0.005000             | 7, 8                              | 218.75                 | 281.25                 | 99500                      |
| 10        | 0.002900             | 8, 9                              | 189.375                | 100.625                | 99710                      |
| 11        | 0.001000             | 9, 10                             | 4.6875                 | 95.3125                | 99900                      |
| 12        | 0.000500             | 10, 11                            | 2.34375                | 47.65625               | 99950                      |

このカイ二乗を計算する式は次のとおりです。

```
ChiSquared = math.Pow(sampled_lowerP - expect_lowerP, 2) / expect_lowerP +
             math.Pow(sampled_upperP - expect_upperP, 2) / expect_upperP +
             math.Pow(100000 - sampled_lowerP - sampled_upperP - expect_unsampled, 2) / expect_unsampled
```

このカイ二乗値は、有意水準5%で2自由度のカイ二乗分布の値である0.102587と比較されます。
上記の表の各確率について、このテストは、0.102587未満のカイ二乗値をちょうど1つ生成するシードを示すことが要求されます。

##### Requirement: Pass 12 non-power-of-two statistical tests {#requirement-pass-12-non-power-of-two-statistical-tests}

20試行、各100,000スパンのテストにおいて、カイ二乗検定統計量が20回中ちょうど1回だけ0.102587を下回るような乱数生成器のシードを示さなければなりません（MUST）。

#### Test procedure: exact powers of two {#test-procedure-exact-powers-of-two}

この場合、カイ二乗検定には1つの自由度があります。
次の表はテストパラメーターをまとめたものです。

| テストケース | サンプリング確率 | サンプリング時のp-value | Expect<sub>sampled</sub> | Expect<sub>unsampled</sub> |
|-----------|----------------------|----------------------|--------------------------|----------------------------|
| 13        | 0x1p-01 (0.500000)   | 1                    | 50000                    | 50000                      |
| 14        | 0x1p-04 (0.062500)   | 4                    | 6250                     | 93750                      |
| 15        | 0x1p-07 (0.007812)   | 7                    | 781.25                   | 99218.75                   |

このカイ二乗を計算する式は次のとおりです。

```
ChiSquared = math.Pow(sampled - expect_sampled, 2) / expect_sampled +
             math.Pow(100000 - sampled - expect_unsampled, 2) / expect_unsampled
```

このカイ二乗値は、有意水準5%で1自由度のカイ二乗分布の値である0.003932と比較されます。
上記の表の各確率について、このテストは、0.003932未満のカイ二乗値をちょうど1つ生成するシードを示すことが要求されます。

##### Requirement: Pass 3 power-of-two statistical tests {#requirement-pass-3-power-of-two-statistical-tests}

20試行、各100,000スパンのテストにおいて、カイ二乗検定統計量が20回中ちょうど1回だけ0.003932を下回るような乱数生成器のシードを示さなければなりません（MUST）。

#### Test implementation {#test-implementation}

このテストの推奨される構造は、15個の確率値、期待されるp-value、カイ二乗統計量が1自由度か2自由度か、そしてあらかじめ決められたシードのリストへのインデックスを列挙した表を使用します。

```
    for _, test := range []testCase{
        // Non-powers of two
        {0.90000, 1, twoDegrees, 3},
        {0.60000, 1, twoDegrees, 2},
        {0.33000, 2, twoDegrees, 2},
        {0.13000, 3, twoDegrees, 1},
        {0.10000, 4, twoDegrees, 0},
        {0.05000, 5, twoDegrees, 0},
        {0.01700, 6, twoDegrees, 2},
        {0.01000, 7, twoDegrees, 2},
        {0.00500, 8, twoDegrees, 2},
        {0.00290, 9, twoDegrees, 4},
        {0.00100, 10, twoDegrees, 6},
        {0.00050, 11, twoDegrees, 0},

        // Powers of two
        {0x1p-1, 1, oneDegree, 0},
        {0x1p-4, 4, oneDegree, 0},
        {0x1p-7, 7, oneDegree, 1},
    } {
```

上記の例のシードインデックスは、正しい分布であるように見えることに注意してください。
5個の0、2個の1、5個の2、1個の3、1個の4は、ちょうど1回の失敗が起きる例を見つけるのが比較的容易であることを示しています。
確率0.001（この場合シードインデックス6）は、外れ値が存在することを思い出させてくれます。
この分布についてのさらなる有意性検定は推奨されません。

## Appendix {#appendix}

### Methods for generating R-values {#methods-for-generating-r-values}

r-valueを生成するために使用する方法は、実装に最適化の自由度を持たせるために規定されていません。
一般的に、TraceIdが62ビットのランダムなビット部分文字列を含むことがわかっている場合、r-valueは、TraceIdの62個のランダムビットから、次の方法で直接導出できます。

1. 先頭のゼロを数える
2. 先頭の1を数える
3. 末尾のゼロを数える
4. 末尾の1を数える

```golang
import (
    "math/rand"
    "math/bits"
)

func nextRValueLeading() int {
    x := uint64(rand.Int63()) // 63 least-significant bits are random
    y := x << 1 | 0x3         // 62 most-significant bits are random
    return bits.LeadingZeros64(y)
}
```

TraceIdに不明または不十分なランダム性しか含まれない場合、別のアプローチとして、最初のtrueまたはfalseの値が出るまでランダムビットを生成する方法があります。

```
func nextRValueGenerated() int {
    for r := 0; r < 62; r++ {
        if rand.Bool() == true {
            return r
        }
    }
    return 62
}
```

次の表に示すr-valueを生成する方式であれば、どのようなものでも準拠しているとみなされます。

| r-value          | r-valueの確率   |
| ---------------- | ------------------------ |
| 0                | 1/2                      |
| 1                | 1/4                      |
| 2                | 1/8                      |
| 3                | 1/16                     |
| ...              | ...                      |
| 0 <= r <= 61     | 2**-(r+1)                |
| ...              | ...                      |
| 59               | 2**-60                   |
| 60               | 2**-61                   |
| 61               | 2**-62                   |
| 62               | 2**-62                   |

