# TraceStateの取り扱い

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


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

[TraceContext](https://www.w3.org/TR/trace-context/)仕様に合わせて、このセクションでは[RFC5234](https://www.w3.org/TR/trace-context/#bib-rfc5234)のAugmented Backus-Naur Form（ABNF）記法を使い、同文書内のDIGIT規則も含めます。

OTelエコシステムの一部である[TraceState](/works/otel-specs-ja/spec/trace/api/#tracestate)の値を設定する場合、それらはすべて`ot`キーを使った単一のエントリに含めなければならず（MUST）、その値はセミコロンで区切られたキーと値のペアのリストにします。例えば以下のとおりです。

* `ot=p:8;r:62`
* `ot=foo:bar;k1:13`

[TraceContext](https://www.w3.org/TR/trace-context/)仕様は、混在するトレーシング環境において、テナント固有の値に`tenant@`という接頭辞を付けることで、各「テナント」がそれぞれ独自の`tracestate`エントリを使えるようにする仕組みをサポートしています。OpenTelemetryはこの構文を認識しますが、マルチテナントの`tracestate`に対する解釈は規定していません。
このリストは、以下のように形式的に定義できます。

```
list        = list-member *( ";" list-member )
list-member = key ":" value
```

リスト全体の長さは、[TraceState value section](https://www.w3.org/TR/trace-context/#value)で定義されているとおり256文字を超えてはならず（MUST NOT）、使われるキーは一意でなければなりません（MUST）。

計装ライブラリとクライアントはこのエントリを使ってはならず（MUST NOT）、代わりに自身のエントリを使わなければなりません（MUST）。

## Key

キーは、OTelの関心事を記述する識別子です。単純な例としては`p`、`ts`、`s1`などがあります。

キーは、以下のように形式的に定義できます。

```
key        = lcalpha *(lcalpha / DIGIT )
lcalpha    = %x61-7A ; a-z
```

OTelの関心事によって使われる具体的なキーは、本仕様書の一部として定義されなければならず（MUST）、したがって本仕様書自体で定義されていないキーを使うことは禁止されています。

## Value

値は不透明な文字列です。最大長は規定されていませんが、キーと値の**リスト全体**が256文字を超えてはならない（MUST NOT）ため、短い値を使うことが推奨されます。

値は、以下のように形式的に定義できます。

```
value      = *(chr)
chr        = ucalpha / lcalpha / DIGIT / "." / "_" / "-"
ucalpha    = %x41-5A ; A-Z
lcalpha    = %x61-7A ; a-z
```

## Setting values

他のOTelの関心事に属する既存の値を保持するため、値を設定する場合は`TraceState`内の`ot`エントリを更新するか、そこに追加しなければなりません（MUST）。例えば、ある関心事Kが`k1:13`を設定したい場合は以下のようになります。

* `ot=p:8;r:62`は`ot=p:8;r:62;k1:13`になります。
* `ot=p:8;k1:7;r:62`は`ot=p:8;r:62;k1:13`になります。順序を保持することは必須ではありません。

値の設定によって`ot`エントリ全体が256文字の上限を超えてしまう場合、SDKはその操作を中止し、利用者にエラーを通知することが推奨されます。例えば以下のとおりです。

```go
traceState, ok := SetTraceStateValue(traceState, value)
if ok {
  // Successfully set the specified value, traceState was updated.
} else {
  // traceState was not updated.
}
```

## Predefined OpenTelemetry sub-keys

以下の値はOpenTelemetryによって定義されています。

### Sampling threshold value `th`

OpenTelemetryのTraceStateサブキー`th`は、実効サンプリング確率を伝えるサンプリング閾値を定義します。`th`サブフィールドの有効な値は、1桁から14桁の小文字16進数字です。

```
hexdigit = DIGIT ; a-f
```

OpenTelemetryのTraceState `th`の値から閾値をデコードするには、まず値を末尾に0を追加して14桁に拡張します。次に、その14桁の値を56ビットの符号なし16進数として解釈し、拒否閾値を得ます。

OpenTelemetryは、56ビットのトレースランダム性の値を56ビットの拒否閾値と比較する形で一貫したサンプリングを定義します。ランダム性の値が拒否閾値より小さい場合、そのスパンはサンプリングされません。

閾値`0`は、どのスパンも拒否されないこと、つまり100%サンプリングに対応することを示します。例えば、以下のTraceStateの値は100%サンプリングのトレースを示します。

```
tracestate: ot=th:0
```

拒否閾値からサンプリング確率を計算するには、識別可能な56ビットの値の個数である2^56に等しい定数`MaxAdjustedCount`を定義します。サンプリング確率は以下のように定義されます。

```
Probability = (MaxAdjustedCount - Threshold) / MaxAdjustedCount
```

閾値は確率から以下のように計算できます。

```
Threshold = MaxAdjustedCount * (1 - Probability)
```

サンプリングにおいて、_調整済みカウント（adjusted count）_という用語は、サンプリングされたテレメトリー項目1つが表す実効的な項目数を指します。あるスパンの調整済みカウントは、そのサンプリング確率の逆数であり、以下のように閾値から導出できます。

```
AdjustedCount = MaxAdjustedCount / (MaxAdjustedCount - Threshold)
```

例えば、以下はOpenTelemetryのサンプリング閾値の値を含むW3C TraceStateの値です。

```
tracestate: ot=th:c
```

これは以下のように25%のサンプリング確率に対応します。

- 16進数値`c`は56ビット分の`c0000000000000`に拡張されます。
- 拒否閾値は`0xc0000000000000 / 0x100000000000000`であり、これは75%です。
- サンプリング確率は25%です。

### Explicit randomness value `rv`

OpenTelemetryのTraceStateサブキー`rv`は、_明示的ランダム性値（explicit randomness value）_と呼ばれる、ランダム性の代替の源を定義します。`rv`の値は、正確に14桁の小文字16進数字でなければなりません（MUST）。

明示的ランダム性値は、TraceIDからランダム性を抽出する代わりに使われることを意図しており、そのためW3C Trace Context Level 2がTraceIDについて推奨するのと同じビット数を含みます。

小文字の16進数字が指定されているのは、サンプリング閾値と、（`traceparent`ヘッダーに現れる）TraceID、あるいは（`tracestate`ヘッダーに現れる）明示的ランダム性値との間で、直接の字句比較ができるようにするためです。

明示的ランダム性値は、変更されることなく[スパンコンテキスト](/works/otel-specs-ja/spec/context/)を通じて伝搬されることを意図しています。明示的ランダム性値を使って行われたサンプリング判断がシグナル間で一貫するように、明示的ランダム性値は、いったん新しいTraceIDに関連付けられた後は、OpenTelemetryのTraceStateから消去したり変更したりすべきではありません（SHOULD NOT）。

例えば、以下はOpenTelemetryの明示的ランダム性値を含むW3C TraceStateの値です。

```
tracestate: ot=rv:6e6d1a75832a2f
```

これは、符号なし整数値として0x6e6d1a75832a2fという明示的ランダム性値に対応します。このランダム性値は、TraceIDの下位56ビットの代わりに使われることを意図しています。
この例では、56ビットの分数（すなわち0x6e6d1a75832a2f / 0x100000000000000 = 43.1%）は、56.9%から100%までの確率（すなわち拒否閾値0x6e6d1a75832a2fから0まで）で一貫した正のサンプリング判断を行うことを裏付けており、これは明示的ランダム性値を持たない、6e6d1a75832a2fで終わる16進数のTraceIDの場合と同じです。

