# 共通概念

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


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

## AnyValue

`AnyValue`は次のいずれかです。

- プリミティブ型（文字列、ブーリアン、倍精度浮動小数点数（IEEE 754-1985）、または符号付き64ビット整数）
- プリミティブ型の値からなる同種の配列。同種の配列は異なる型の値をMUST NOT含めるものとします。
- バイト配列
- `AnyValue`の配列
- [`map<string, AnyValue>`](#mapstring-anyvalue)
- 言語がサポートしている場合の空の値（JavaScript/TypeScriptの`null`や`undefined`、Pythonの`None`、Go/Rubyの`nil`など。Erlangではサポートされません）

配列やマップの値については、任意の深さの入れ子がMAY許容されます（実質的にJSONオブジェクトと同等のものを表現できます）。

APIは、配列やマップの値を使うとプリミティブな値に比べて高いパフォーマンスオーバーヘッドが発生しうることをユーザーに伝わるように文書化すべきです（SHOULD）。

空の値、数値のゼロ、空文字列、空配列を表すAnyValueは意味のあるものとみなされ、プロセッサーやエクスポーターに保存・引き渡されなければなりません（MUST）。

`null`は有効な属性値ですが、同種の配列の中で使うことは、言語の制約上不可能な場合を除き一般的に避けるべきです（SHOULD）。しかし、`null`値を受け付けないようにすることが不可能な場合（例えば適切なコンパイル時型チェックを持たない言語）、配列内の`null`値はそのまま（すなわちプロセッサーやエクスポーターに`null`として引き渡される形で）保持されなければなりません（MUST）。エクスポーターが`null`値のエクスポートをサポートしない場合、これらの値を`0`、`false`、または空文字列に置き換えても構いません（MAY）。これは、インデックスが同期された2つの配列で表現されるマップ・辞書構造（例えば、`header_keys[i] -> header_values[i]`というマッピングを表すために、文字列の配列を含む2つの属性`header_keys`と`header_values`を使う場合）で必要になります。

### map<string, AnyValue>

`map<string, AnyValue>`は、文字列キーから`AnyValue`値へのマップです。マップ内のキーは一意です（重複キーは許容されません）。

キーの大文字・小文字の区別は保持されなければなりません（MUST）。大文字・小文字が異なるキーは別個のキーとして扱われます。

マップの表現方法は言語に依存します。

実装は、エクスポートされるマップが一意なキーのみを含むことをデフォルトでMUST強制するものとします。一意性の強制方法は、特定の実装の制約に最も適合する多様な方法（例えば重複を除去する方法）で構いません（MAY）。

実装は、重複キーを持つマップのエクスポートを許容するオプションを持っても構いません（MAY）（例えばパフォーマンス向上のため）。そのようなオプションを提供する場合、多くの受信側にとって重複キーを持つマップの扱いは予測不能であり、キーが重複しないようにするのはユーザーの責任であることをMUST文書化するものとします。

マップは、要素が現れる順序に関わらず、同じキーと値の組を含む場合に等しいとみなされます（順序を問わないコレクションの等価性）。

### AnyValue representation for non-OTLP protocols

AnyValueの一部の型をネイティブにサポートしないプロトコルでは、それらの値は以下の符号化規則に従って文字列として表現すべきです（SHOULD）。

> [!NOTE]
> この文字列表現は情報を失います。すべての値が文字列に変換されるため型情報が失われ、数値については精度が失われることがあります（特に浮動小数点数や、受信側システムの文字列から数値への変換の精度を超える大きな整数の場合）。

#### Strings

文字列は追加の符号化を行わずそのまま表現すべきです（SHOULD）。明示的な囲み引用符を付けたJSON文字列としては符号化しないべきです（SHOULD NOT）。

例: `hello world`、（空文字列）

#### Booleans

ブーリアンは[JSONブーリアン](https://datatracker.ietf.org/doc/html/rfc8259#section-3)として表現すべきです（SHOULD）。

例: `true`、`false`

#### Integers

整数は[JSON数値](https://datatracker.ietf.org/doc/html/rfc8259#section-6)として表現すべきです（SHOULD）。

例: `42`、`-123`

#### Floating Point Numbers

浮動小数点数は[JSON数値](https://datatracker.ietf.org/doc/html/rfc8259#section-6)として表現すべきです（SHOULD）。

特殊な浮動小数点値であるNaNとInfinityは、`NaN`、`Infinity`、`-Infinity`として表現すべきです（SHOULD）。囲み引用符を付けたJSON文字列としては符号化しないべきです（SHOULD NOT）。

例: `3.14159`、`1.23e10`、`NaN`、`Infinity`、`-Infinity`

#### Byte Arrays

バイト配列は[Base64エンコード](https://datatracker.ietf.org/doc/html/rfc4648#section-4)すべきです（SHOULD）。囲み引用符を付けたJSON文字列としては符号化しないべきです（SHOULD NOT）。

例: `aGVsbG8gd29ybGQ=`

#### Empty Values

空の値は空文字列として表現すべきです（SHOULD）。囲み引用符を付けたJSON文字列としては符号化しないべきです（SHOULD NOT）。

#### Arrays

[バイト配列](#byte-arrays)を除く配列は、[JSON配列](https://datatracker.ietf.org/doc/html/rfc8259#section-5)として表現すべきです（SHOULD）。

配列の要素は、以下の規則に従いJSONの値として表現すべきです（SHOULD）。

- [Strings](#strings)は[JSON文字列](https://datatracker.ietf.org/doc/html/rfc8259#section-7)として、
- [Booleans](#booleans)は[JSONブーリアン](https://datatracker.ietf.org/doc/html/rfc8259#section-3)（`true`または`false`）として、
- [Integers](#integers)と[floating point numbers](#floating-point-numbers)は[JSON数値](https://datatracker.ietf.org/doc/html/rfc8259#section-6)として。ただし特殊な浮動小数点値のNaNとInfinityは、JSON文字列`"NaN"`、`"Infinity"`、`"-Infinity"`として表現すべきです（SHOULD）。
- [Byte arrays](#byte-arrays)は[Base64エンコード](https://datatracker.ietf.org/doc/html/rfc4648#section-4)されたJSON文字列として、
- [Empty values](#empty-values)は[JSONの`null`](https://datatracker.ietf.org/doc/html/rfc8259#section-3)として、
- [Arrays](#arrays)は[JSON配列](https://datatracker.ietf.org/doc/html/rfc8259#section-5)として、
- [Maps](#maps)は[JSONオブジェクト](https://datatracker.ietf.org/doc/html/rfc8259#section-4)として。

例: `[]`、`[1, "-Infinity", "a", true, {"nested": "aGVsbG8gd29ybGQ="}]`

#### Maps

マップは[JSONオブジェクト](https://datatracker.ietf.org/doc/html/rfc8259#section-4)として表現すべきです（SHOULD）。

マップのキーはJSONオブジェクトのメンバー名として表現すべきです（SHOULD）。

マップの値は、[配列の要素](#arrays)と同じ規則を使って表現すべきです（SHOULD）。

例: `{}`、`{"a": "-Infinity", "b": 2, "c": [3, null]}`

## Attribute

<a id="attributes"></a>

`Attribute`はキーと値の組であり、以下の性質をMUST持つものとします。

- 属性キーは非`null`かつ空でない文字列でなければなりません（MUST）。
  - キーの大文字・小文字の区別は保持されます。大文字・小文字が異なるキーは別個のキーとして扱われます。
- 属性値は[AnyValue](#anyvalue)で定義された型のいずれかでなければなりません（MUST）。

属性は、キーと値が等しい場合に等しいとみなされます。

命名の指針については[Attribute Naming](https://opentelemetry.io/docs/specs/semconv/general/naming/#attributes)を参照してください。

要求レベルの指針については[Requirement Level](/works/otel-specs-ja/semconv/general/attribute-requirement-level/)を参照してください。

OpenTelemetryの外部で取得した値をOpenTelemetryの属性値にマッピングする方法については[この文書](./attribute-type-mapping/)を参照してください。

### Attribute representation for non-OTLP

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

単一の`Attribute`を文字列として表現する必要のある非OTLPプロトコルでは、単一の名前・値の組（メンバー）を含む[JSONオブジェクト](https://datatracker.ietf.org/doc/html/rfc8259#section-4)を推奨形式とします（RECOMMENDED）。

属性キーはJSONオブジェクトのメンバー名として表現すべきです（SHOULD）。

属性値はJSONオブジェクトのメンバー値として表現し、[配列](#arrays)の要素や[マップ](#maps)の値として表現される場合と同様に、[AnyValue representation for non-OTLP protocols](#anyvalue-representation-for-non-otlp-protocols)で定義された符号化規則に従うべきです（SHOULD）。

例: `{"http.request.method": "GET"}`、`{"retries": 3}`、`{"payload": "aGVsbG8gd29ybGQ="}`、`{"session.id": null}`、`{"colors": ["red", "blue"]}`、`{"context": {"nested": true}}`

> [!NOTE]
> この文字列表現は情報を失います。すべての値が文字列に変換されるため型情報が失われ、数値については精度が失われることがあります（特に浮動小数点数や、受信側システムの文字列から数値への変換の精度を超える大きな整数の場合）。

## Attribute Collections

[リソース](/works/otel-specs-ja/spec/resource/sdk/)、
[Instrumentation Scope](./instrumentation-scope/)、
[メトリクスポイント](/works/otel-specs-ja/spec/metrics/data-model/#metric-points)、
[スパン](../trace/api/#set-attributes)、
スパン[イベント](../trace/api/#add-events)、
スパン[リンク](../trace/api/#link)、
[ログレコード](/works/otel-specs-ja/spec/logs/data-model/)は、
いずれも属性のコレクションを持ちます。

Attribute Collectionは、OpenTelemetryのデータモデルで使われるキーと値の組のトップレベルのコレクションです。これは、[`map<string, AnyValue>`](#mapstring-anyvalue)とは異なる点に注意してください。`map<string, AnyValue>`は、属性値やログレコードのbody（[log record body](/works/otel-specs-ja/spec/logs/data-model/#field-body)など）のような入れ子のデータ構造を表現するために使われる[`AnyValue`](#anyvalue)の一種です。

実装は、エクスポートされる属性コレクションが一意なキーのみを含むことをデフォルトでMUST強制するものとします。一意性の強制方法は、特定の実装の制約に最も適合する多様な方法（例えば重複を除去する方法）で構いません（MAY）。

通常、OpenTelemetry SDKで生成されるテレメトリーでは、単一のキーと値の組またはそのコレクションを受け付けるAPIを介して属性のキーと値の組が設定されます。既存の属性と同じキーで属性を設定すると、既存の属性の値を上書きすべきです（SHOULD）。例えばSpanの[SetAttribute](../trace/api/#set-attributes)APIを参照してください。

[SetAttribute](../trace/api/#set-attributes)APIの典型的な実装は、エクスポート待ちの既存の属性値を上書きすることで一意性を強制するので、Spanが最終的にエクスポートされる時点でエクスポーターが目にするのは一意な属性だけになります。特にOTLP形式は、エクスポートされるリソース、スパン、メトリクスのデータポイント、ログレコードが一意な属性のみを含むことを要求します。

他の実装では、[SetAttribute](../trace/api/#set-attributes)APIの呼び出しごとに、その個々の属性値がストリーミングワイヤープロトコルを使って即座にエクスポートされる、ストリーミング方式を採る場合があります。このような場合、一意性の強制はこのデータの受信側の責任になる可能性が高くなります。

実装は、重複キーを持つ属性コレクションのエクスポートを許容するオプションを持っても構いません（MAY）（例えばパフォーマンス向上のため）。そのようなオプションを提供する場合、多くの受信側にとって重複キーを持つマップの扱いは予測不能であり、キーが重複しないようにするのはユーザーの責任であることをMUST文書化するものとします。

属性のコレクションは、要素が現れる順序に関わらず、同じ属性を含む場合に等しいとみなされます（順序を問わないコレクションの等価性）。

### Attribute Collection representation for non-OTLP

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

Attribute Collectionを文字列として表現する必要のある非OTLPプロトコルでは、[JSONオブジェクト](https://datatracker.ietf.org/doc/html/rfc8259#section-4)を推奨形式とします（RECOMMENDED）。

各属性キーはJSONオブジェクトのメンバー名として表現すべきです（SHOULD）。

各属性値は、対応するJSONオブジェクトのメンバー値として表現し、[配列](#arrays)の要素や[マップ](#maps)の値として表現される場合と同様に、[AnyValue representation for non-OTLP protocols](#anyvalue-representation-for-non-otlp-protocols)で定義された符号化規則に従うべきです（SHOULD）。

この表現は、[マップ](#maps)と同じJSONオブジェクトの形式に従いますが、入れ子の[`map<string, AnyValue>`](#mapstring-anyvalue)値ではなく、トップレベルのAttribute Collectionに適用されます。

例: `{}`、`{"http.request.method": "GET", "retries": 3}`、`{"payload": "aGVsbG8gd29ybGQ=", "session.id": null}`、`{"colors": ["red", "blue"], "context": {"nested": true}}`

## Attribute Limits

不正なコードの実行は意図しない属性を生じさせることがあります。属性コレクションに制限が設けられていない場合、それらは利用可能なメモリーを急速に使い果たし、安全に復旧することが難しいクラッシュを引き起こす可能性があります。

デフォルトでは、SDKは以下の[configurable parameters](#configurable-parameters)の一覧に従って切り詰めを適用すべきです（SHOULD）。

SDKが以下の方法を提供する場合、

- 各属性値について、属性値の長さの制限を設定する方法を提供する場合、
  - それが文字列であり、その制限を超える場合（各文字を1として数える）、SDKはその値を切り詰め、長さが制限と等しくなるようにしなければなりません（MUST）。
  - それがバイト配列であり、長さが制限を超える場合（各バイトを1として数える）、SDKはその値を切り詰め、長さが制限と等しくなるようにしなければなりません（MUST）。
  - それが文字列の配列である場合、配列内の各値に個別に制限を適用します。
  - それが[AnyValue](#anyvalue)の配列である場合、配列の各要素に個別に（かつ再帰的に）制限を適用します。
  - それが[map](#mapstring-anyvalue)である場合、マップ内の各値に個別に（かつ再帰的に）制限を適用します。
  - それ以外の場合、値は切り詰められないものとします（MUST NOT）。
- 属性数の制限を設定する方法を提供する場合、
  - 属性を属性コレクションに追加すると制限を超える場合（コレクション内の各属性を1として数える）、SDKはその属性を破棄し、属性コレクション内の属性の総数が制限と等しくなるようにしなければなりません（MUST）。
  - 数の制限は、トップレベルの属性にのみ適用され、[マップ](#mapstring-anyvalue)内の入れ子のキーと値の組には適用されません。
  - それ以外の場合、属性は破棄されないものとします（MUST NOT）。

属性が切り詰められた、あるいは破棄されたことをユーザーに示すログが出力されてもよいです（MAY）。過度なログ出力を防ぐため、そのログは1つのレコードで属性が設定されるたびに複数回出力されてはなりません（MUST NOT）。

SDKが上記の制限を実装する場合、これらの制限をプログラムから変更する方法をMUST提供するものとします。設定オプションの名前は、以下の一覧と同じにすべきです（SHOULD）。

SDKは、例えば`SpanAttributeCountLimit`や`LogRecordAttributeCountLimit`のような、モデル固有の制限を実装しても構いません（MAY）。一般的な制限とモデル固有の制限の両方が実装されている場合、SDKはまずモデル固有の制限の使用をMUST試みるものとし、それが設定されていない場合は一般的な制限の使用をMUST試みるものとします。どちらも定義されていない場合、SDKはモデル固有の制限のデフォルト値、続いてグローバルな制限のデフォルト値を使うことをMUST試みるものとします。

これらの制限は属性コレクションにのみ適用される点に注意してください。したがって、[`LogRecord.Body`](/works/otel-specs-ja/spec/logs/data-model/#field-body)のような他のデータ構造内の値には適用されません。

### Configurable Parameters

* `AttributeCountLimit`（デフォルト値=128）- レコードごとに許容される属性の最大数
* `AttributeValueLengthLimit`（デフォルト値=Infinity）- 許容される属性値の最大長（文字列値とバイト配列に適用される）

### Exempt Entities

リソース属性は、上記の制限から除外すべきです（SHOULD）。リソースは、過剰な属性数やサイズを生じさせる状況（自動計装など）の影響を受けにくいためです。リソースはスパンごとではなくバッチごとに一度だけ送信されるため、より多くの、あるいはより大きな属性を持たせる相対的なコストも低くなります。リソースは設計上不変であり、通常は制限とともにTracerProviderへと渡されます。これにより、リソースに対して属性の制限を実装するのは不自然になります。

メトリクスに属する属性は、現時点では上記の制限から除外されています。詳細は[Metrics Attribute Limits](/works/otel-specs-ja/spec/metrics/sdk/#属性の制限)で議論されています。

- [Instrumentation Scope](/works/otel-specs-ja/spec/common/instrumentation-scope/)
- [任意のデータをAnyValueへマッピングする](/works/otel-specs-ja/spec/common/attribute-type-mapping/)
- [非OTLP形式へのマッピング](/works/otel-specs-ja/spec/common/mapping-to-non-otlp/)
