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


# OTEP-0122: OTLP: OTLP/HTTPのためのJSONエンコーディング

これは、[OTLP](0035-opentelemetry-protocol.md)（OpenTelemetry Protocol）に対して、JSONシリアライゼーションをサポートするHTTPトランスポート拡張を追加する提案です。

## 動機 {#motivation}

Protobufは比較的大きな依存関係であり、それを取り込みたくないクライアントも存在します。
たとえば、WebJSやiOS/Android（インストールパッケージのサイズが制限されているシナリオでは、protobufへの依存関係を導入したくない）がこれにあたります。
プレーンなJSONはより小さな依存関係であり、多くのプログラミング言語の標準ライブラリに組み込まれています。

## OTLP/HTTP+JSONプロトコルの詳細 {#otlphttpjson-protocol-details}

OTLP/HTTP+JSONは、ペイロードがprotobufの代わりにJSONを使用することを除いて、[OTLP/HTTP](0099-otlp-http.md)仕様と一貫性があります。

### JSONマッピング {#json-mapping}

protobufとJSONの間のマッピングには、proto3標準で定義された[JSON Mapping](https://protobuf.dev/programming-guides/proto3/#json)を使用します。
OTLP/HTTP+JSONでは、`trace_id` と `span_id` は16進数ではなくbase64でエンコードされます。

### リクエスト {#request}

テレメトリーデータはHTTP POSTリクエストで送信されます。

トレースデータを運ぶリクエストのデフォルトのURLパスは `/v1/traces` です（たとえば、"example.com" サーバーに接続する場合の完全なURLは `https://example.com/v1/traces` になります）。
リクエストボディは、JSONエンコードされた[`ExportTraceServiceRequest`](https://github.com/open-telemetry/opentelemetry-proto/blob/e6c3c4a74d57f870a0d781bada02cb2b2c497d14/opentelemetry/proto/collector/trace/v1/trace_service.proto#L38)メッセージです。

メトリクスデータを運ぶリクエストのデフォルトのURLパスは `/v1/metrics` であり、リクエストボディは、JSONエンコードされた[`ExportMetricsServiceRequest`](https://github.com/open-telemetry/opentelemetry-proto/blob/e6c3c4a74d57f870a0d781bada02cb2b2c497d14/opentelemetry/proto/collector/metrics/v1/metrics_service.proto#L35)メッセージです。

クライアントは "Content-Type: application/json" リクエストヘッダーを設定しなければなりません（MUST）。
クライアントはコンテンツをgzip圧縮してもよく（MAY）、その場合は "Content-Encoding: gzip" リクエストヘッダーを含めるべきです（SHOULD）。
クライアントは、gzipエンコードされたレスポンスを受信できる場合、"Accept-Encoding: gzip" リクエストヘッダーを含めてもよいです（MAY）。

リクエストのデフォルト以外のURLパスは、クライアント側とサーバー側の両方で設定してもよいです（MAY）。

### レスポンス {#response}

#### 成功 {#success}

成功時、サーバーは `HTTP 200 OK` で応答しなければなりません（MUST）。
レスポンスボディは、トレースの場合はJSONエンコードされた[`ExportTraceServiceResponse`](https://github.com/open-telemetry/opentelemetry-proto/blob/e6c3c4a74d57f870a0d781bada02cb2b2c497d14/opentelemetry/proto/collector/trace/v1/trace_service.proto#L47)メッセージ、メトリクスの場合は[`ExportMetricsServiceResponse`](https://github.com/open-telemetry/opentelemetry-proto/blob/e6c3c4a74d57f870a0d781bada02cb2b2c497d14/opentelemetry/proto/collector/metrics/v1/metrics_service.proto#L44)メッセージでなければなりません（MUST）。

サーバーは "Content-Type: application/json" レスポンスヘッダーを設定しなければなりません（MUST）。
リクエストヘッダーに "Accept-Encoding: gzip" が含まれている場合、サーバーはレスポンスをgzipエンコードし、"Content-Encoding: gzip" レスポンスヘッダーを設定してもよいです（MAY）。

サーバーは、リクエストのデコードと検証に成功した後でのみ、成功で応答するべきです（SHOULD）。

#### 失敗 {#failures}

リクエストの処理が失敗した場合、サーバーは適切な `HTTP 4xx` または `HTTP 5xx` ステータスコードで応答しなければなりません（MUST）。
特定の失敗事例と、使用すべきHTTPステータスコードについての詳細は、以下のセクションを参照してください。

すべての `HTTP 4xx` および `HTTP 5xx` レスポンスのレスポンスボディは、問題を説明するJSONエンコードされた[Status](https://pkg.go.dev/google.golang.org/genproto/googleapis/rpc/status#Status)メッセージでなければなりません（MUST）。

この仕様は `Status.code` フィールドを使用せず、サーバーは `Status.code` フィールドを省略してもよいです（MAY）。
クライアントは `Status.code` フィールドに基づいて挙動を変更することは想定されていませんが、トラブルシューティングの目的でそれを記録してもよいです（MAY）。

`Status.message` フィールドは、`Status` メッセージスキーマで定義されている通り、開発者向けのエラーメッセージを含むべきです（SHOULD）。

サーバーは、追加の詳細を含む `Status.details` フィールドを含めてもよいです（MAY）。
このフィールドが各失敗事例で何を含み得るかについては、以下を参照してください。

#### 不正なデータ {#bad-data}

リクエストの処理が、デコードできない、あるいは無効なデータをリクエストが含んでいることによって失敗し、その失敗が恒久的なものである場合、サーバーは `HTTP 400 Bad Request` で応答しなければなりません（MUST）。
レスポンスの `Status.details` フィールドには、不正なデータを説明する[BadRequest](https://github.com/googleapis/googleapis/blob/d14bf59a446c14ef16e9931ebfc8e63ab549bf07/google/rpc/error_details.proto#L166)を含めるべきです（SHOULD）。

クライアントは、`HTTP 400 Bad Request` レスポンスを受信した場合、リクエストを再試行してはなりません（MUST NOT）。

#### スロットリング {#throttling}

サーバーがクライアントに許可されている数より多くのリクエストを受信した場合、またはサーバーが過負荷状態にある場合、サーバーは `HTTP 429 Too Many Requests` または `HTTP 503 Service Unavailable` で応答するべきであり（SHOULD）、再試行するまでに待機すべき時間間隔（秒単位）を推奨する["Retry-After"](https://datatracker.ietf.org/doc/html/rfc7231#section-7.1.3)ヘッダーを含めてもよいです（MAY）。

クライアントは、"Retry-After" ヘッダーが存在する場合、そこで指定されている待機時間を尊重するべきです（SHOULD）。
クライアントが `HTTP 429` または `HTTP 503` レスポンスを受信し、レスポンスに "Retry-After" ヘッダーが存在しない場合、クライアントは再試行の間に指数バックオフ戦略を実装するべきです（SHOULD）。

#### その他すべてのレスポンス {#all-other-responses}

このドキュメントで明示的に列挙されていないその他すべてのHTTPレスポンスは、HTTP仕様に従って扱われるべきです。

サーバーがレスポンスを返さずに切断した場合、クライアントは再試行して同じリクエストを送信するべきです（SHOULD）。
クライアントは、サーバーへの過負荷を避けるために、再試行の間に指数バックオフ戦略を実装するべきです（SHOULD）。

### 接続 {#connection}

クライアントがサーバーに接続できない場合、クライアントは再試行の間に指数バックオフ戦略を使用して接続を再試行するべきです（SHOULD）。
再試行の間隔には、ランダムなジッターがなければなりません（MUST）。

クライアントは、リクエストの間、接続を維持し続けるべきです（SHOULD）。

サーバーの実装は、OTLP/gRPC、OTLP/HTTPリクエスト、およびOTLP/HTTP+JSONを同じポートで処理し、"Content-Type" リクエストヘッダーに基づいて、接続を対応するトランスポートハンドラーに多重化してもよいです（MAY）。

### 並列接続 {#parallel-connections}

より高い総スループットを達成するために、クライアントは複数の並列HTTP接続を使用してリクエストを送信してもよいです（MAY）。
その場合、並列接続の最大数は設定可能であるべきです（SHOULD）。

