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


# OTEP-0178: 任意のデータをOTLPのAnyValueにマッピングする

このドキュメントでは、任意のデータ（たとえばインメモリのオブジェクト）をOTLPのAnyValueにマッピング（変換）する方法を定義します。

## 動機 {#motivation}

このマッピングは、変換された値が言語や実装をまたいで曖昧さがなく一貫したものになるように、Logging Library SDKを正しく実装するために必要です。

## 説明 {#explanation}

[AnyValue](https://github.com/open-telemetry/opentelemetry-proto/blob/38b5b9b6e5257c6500a843f7fdacf89dd95833e8/opentelemetry/proto/common/v1/common.proto#L27)は、特定の型のプリミティブなデータと構造化されたデータを表現できます。

インメモリのオブジェクトや他の形式から得られるデータなど、任意の形式のソースデータを持ち、それをAnyValueに変換する必要がある実装は、以下に説明するルールに従うべきです（SHOULD）。

### プリミティブな値 {#primitive-values}

#### 整数値 {#integer-values}

64ビット符号付き数値の範囲[-2^63..2^63-1]に収まる整数値は、AnyValueの[int_value](https://github.com/open-telemetry/opentelemetry-proto/blob/38b5b9b6e5257c6500a843f7fdacf89dd95833e8/opentelemetry/proto/common/v1/common.proto#L33)フィールドに変換されるべきです（SHOULD）。

64ビット符号付き数値の範囲外にある整数値は、10進表現を使ってAnyValueの[string_value](https://github.com/open-telemetry/opentelemetry-proto/blob/38b5b9b6e5257c6500a843f7fdacf89dd95833e8/opentelemetry/proto/common/v1/common.proto#L31)フィールドに変換されるべきです（SHOULD）。

#### 列挙型 {#enumerations}

限定された列挙集合に属する値（たとえばJavaの[enum](https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html)）は、列挙型のシンボル名を文字列として設定したAnyValueの[string_value](https://github.com/open-telemetry/opentelemetry-proto/blob/38b5b9b6e5257c6500a843f7fdacf89dd95833e8/opentelemetry/proto/common/v1/common.proto#L31)フィールドに変換されるべきです（SHOULD）。

列挙型のシンボル名を取得できない場合、実装は、序数が自然に取得できるのであれば、列挙型の値をその序数と等しい値を設定したAnyValueの[int_value](https://github.com/open-telemetry/opentelemetry-proto/blob/38b5b9b6e5257c6500a843f7fdacf89dd95833e8/opentelemetry/proto/common/v1/common.proto#L33)フィールドにマッピングするべきです（SHOULD）。

序数値も取得できない場合、列挙型は、実装が妥当と判断する任意の方法でAnyValueの[bytes_value](https://github.com/open-telemetry/opentelemetry-proto/blob/38b5b9b6e5257c6500a843f7fdacf89dd95833e8/opentelemetry/proto/common/v1/common.proto#L37)フィールドに変換されるべきです（SHOULD）。

#### 浮動小数点値 {#floating-point-values}

IEEE 754の64ビット浮動小数点数の範囲と精度に収まる浮動小数点値（IEEEの32ビット浮動小数点値を含む）は、AnyValueの[double_value](https://github.com/open-telemetry/opentelemetry-proto/blob/38b5b9b6e5257c6500a843f7fdacf89dd95833e8/opentelemetry/proto/common/v1/common.proto#L34)フィールドに変換されるべきです（SHOULD）。

IEEE 754の64ビット浮動小数点数の範囲または精度の外にある浮動小数点値（たとえばIEEEの128ビット浮動小数点値）は、10進の浮動小数点表現を使ってAnyValueの[string_value](https://github.com/open-telemetry/opentelemetry-proto/blob/38b5b9b6e5257c6500a843f7fdacf89dd95833e8/opentelemetry/proto/common/v1/common.proto#L31)フィールドに変換されるべきです（SHOULD）。

#### 文字列値 {#string-values}

有効なUnicodeシーケンスである文字列値は、AnyValueの[string_value](https://github.com/open-telemetry/opentelemetry-proto/blob/38b5b9b6e5257c6500a843f7fdacf89dd95833e8/opentelemetry/proto/common/v1/common.proto#L31)フィールドに変換されるべきです（SHOULD）。

有効なUnicodeシーケンスではない文字列値は、ソース文字列の元の順序と形式を表すバイト列として、AnyValueの[bytes_value](https://github.com/open-telemetry/opentelemetry-proto/blob/38b5b9b6e5257c6500a843f7fdacf89dd95833e8/opentelemetry/proto/common/v1/common.proto#L37)に変換されるべきです（SHOULD）。

#### バイト列 {#bytes-sequences}

バイト列（たとえばGoの`[]byte`スライスやファイルの生のバイト内容）は、AnyValueの[bytes_value](https://github.com/open-telemetry/opentelemetry-proto/blob/38b5b9b6e5257c6500a843f7fdacf89dd95833e8/opentelemetry/proto/common/v1/common.proto#L37)フィールドに変換されるべきです（SHOULD）。

### 複合的な値 {#composite-values}

#### 配列値 {#array-values}

他の値の順序付きシーケンスを表す値（たとえば[配列](https://docs.oracle.com/javase/specs/jls/se7/html/jls-10.html)、[ベクター](https://en.cppreference.com/w/cpp/container/vector.html)、順序付きの[リスト](https://docs.python.org/3/tutorial/datastructures.html#more-on-lists)、[スライス](https://go.dev/ref/spec#Slice_types)）は、AnyValueの[array_value](https://github.com/open-telemetry/opentelemetry-proto/blob/38b5b9b6e5257c6500a843f7fdacf89dd95833e8/opentelemetry/proto/common/v1/common.proto#L35)フィールドに変換されるべきです（SHOULD）。
文字列値とバイト列は、このルールの例外です（前述を参照してください）。

#### 一意なキーを持つ連想配列 {#associative-arrays-with-unique-keys}

一意なキーを持つ連想配列を表す値（マップ、ディクショナリ、キーバリューストアとも呼ばれます）は、AnyValueの[kvlist_value](https://github.com/open-telemetry/opentelemetry-proto/blob/38b5b9b6e5257c6500a843f7fdacf89dd95833e8/opentelemetry/proto/common/v1/common.proto#L36)フィールドに変換されるべきです（SHOULD）。

ソースの配列のキーが文字列でない場合、それらは利用可能な任意の手段で文字列に変換されなければなりません（MUST）。
多くの場合、プログラミング言語で利用可能な`toString()`やstringify関数を使用します。
変換関数は、結果として得られる文字列のキーが変換先の配列内で一意になることを保証する方法で選ばれなければなりません（MUST）。

ソースの配列の各要素の値の部分は、再帰的にAnyValueに変換されるべきです（SHOULD）。

たとえば、JSONオブジェクト `{"a": 123, "b": "def"}` は次のように変換されるべきです（SHOULD）。

```
AnyValue{
    kvlist_value:KeyValueList{
        values:[
            KeyValue{key:"a",value:AnyValue{int_value:123}},
            KeyValue{key:"b",value:AnyValue{string_value:"def"}},
        ]
    }
}
```

#### 一意でないキーを持つ連想配列 {#associative-arrays-with-non-unique-keys}

同じキーに複数の値が関連付けられる可能性がある、一意でないキーを持つ連想配列を表す値（マルチマップ、マルチディクトとも呼ばれることがあります）は、AnyValueの[kvlist_value](https://github.com/open-telemetry/opentelemetry-proto/blob/38b5b9b6e5257c6500a843f7fdacf89dd95833e8/opentelemetry/proto/common/v1/common.proto#L36)フィールドに変換されるべきです（SHOULD）。

結果として得られる[kvlist_value](https://github.com/open-telemetry/opentelemetry-proto/blob/38b5b9b6e5257c6500a843f7fdacf89dd95833e8/opentelemetry/proto/common/v1/common.proto#L36)フィールドは各キーを一度だけリストしなければならず（MUST）、[kvlist_value](https://github.com/open-telemetry/opentelemetry-proto/blob/38b5b9b6e5257c6500a843f7fdacf89dd95833e8/opentelemetry/proto/common/v1/common.proto#L36)フィールドの各要素の値は、AnyValueの[array_value](https://github.com/open-telemetry/opentelemetry-proto/blob/38b5b9b6e5257c6500a843f7fdacf89dd95833e8/opentelemetry/proto/common/v1/common.proto#L35)フィールドを使って表現された配列でなければならず（MUST）、[array_value](https://github.com/open-telemetry/opentelemetry-proto/blob/38b5b9b6e5257c6500a843f7fdacf89dd95833e8/opentelemetry/proto/common/v1/common.proto#L35)の各要素は、指定されたキーに関連付けられたソースの配列の1つの値を表します。

たとえば、次の表に示す連想配列は、

|キー|値|
|---|---|
|"abc"|123|
|"def"|"foo"|
|"def"|"bar"|

次のように変換されるべきです（SHOULD）。

```
AnyValue{
    kvlist_value:KeyValueList{
        values:[
            KeyValue{
                key:"abc",
                value:AnyValue{array_value:ArrayValue{values[
                    AnyValue{int_value:123}
                ]}}
            },
            KeyValue{
                key:"def",
                value:AnyValue{array_value:ArrayValue{values[
                    AnyValue{string_value:"foo"},
                    AnyValue{string_value:"bar"}
                ]}}
            },
        ]
    }
}
```

#### 集合 {#sets}

重複のない値の順序なしコレクション（たとえば[Java Set](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Set.html)、[C++ set](https://en.cppreference.com/w/cpp/container/set.html)、[Python Set](https://docs.python.org/3/tutorial/datastructures.html#sets)）は、集合の各要素が配列の要素になるようにして、AnyValueの[array_value](https://github.com/open-telemetry/opentelemetry-proto/blob/38b5b9b6e5257c6500a843f7fdacf89dd95833e8/opentelemetry/proto/common/v1/common.proto#L35)フィールドに変換されるべきです（SHOULD）。

### その他の値 {#other-values}

上記に列挙されていないその他の値は、ソースデータがプログラミング言語で利用可能な`toString()`やstringify関数を使って文字列にシリアライズできる（文字列化できる）場合、AnyValueの[string_value](https://github.com/open-telemetry/opentelemetry-proto/blob/38b5b9b6e5257c6500a843f7fdacf89dd95833e8/opentelemetry/proto/common/v1/common.proto#L31)フィールドに変換されるべきです（SHOULD）。

ソースデータを文字列にシリアライズできない場合、その値は、利用可能な任意の手段でバイト列にシリアライズすることで、AnyValueの[bytes_value](https://github.com/open-telemetry/opentelemetry-proto/blob/38b5b9b6e5257c6500a843f7fdacf89dd95833e8/opentelemetry/proto/common/v1/common.proto#L37)フィールドに変換されるべきです（SHOULD）。

ソースデータを文字列にもバイト列にもシリアライズできない場合、それは空のAnyValueに変換されるべきです（SHOULD）。

### 空の値 {#empty-values}

ソースデータに型が関連付けられておらず、空、null、nil、またはその他の方法でデータが存在しないことを示している場合、それはすべてのフィールドが未設定である[空](https://github.com/open-telemetry/opentelemetry-proto/blob/38b5b9b6e5257c6500a843f7fdacf89dd95833e8/opentelemetry/proto/common/v1/common.proto#L29)のAnyValueに変換されるべきです（SHOULD）。

型が関連付けられている空の値（たとえば空の連想配列）は、上記で定義された対応する型のルールを使って変換されるべきです（SHOULD）。

## 代替案 {#alternatives}

このドキュメントに列挙されているマッピングの一部は、異なる方法で設計することもできます。
たとえば、マルチマップは、配列値を持つマップの代わりに、マップの配列として表現することもできます。
このような代替の表現方法も検討されましたが、このドキュメントで選択された解決策よりも有利であるとは判断されませんでした。

## 将来の可能性 {#future-possibilities}

AnyValueがより多くのデータ型をサポートするように拡張された場合、より自然なマッピングとなるように、このドキュメントの一部のルールが改訂されることがあります。
これが行われる場合、既存のマッピングルールに依存しているアプリケーションを壊さないように、後方互換性が慎重に検討されるべきです。

