# コンテキスト伝搬のキャリアとしての環境変数

> Source: https://www.ymotongpoo.com/works/otel-specs-ja/spec/context/env-carriers/


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

## Overview

環境変数は、ネットワークプロトコルが使えない場合にプロセス境界を越えてコンテキストとバゲージの情報を伝搬する機構を提供します。本仕様は、[API Propagators](../api-propagators/)を拡張し、[TextMapPropagator](../api-propagators/#textmap-propagator)を環境変数と一緒に使う方法を定義します。

環境変数によるコンテキスト伝搬が有用な一般的なシステムには以下が含まれます。

- バッチ処理システム
- CI/CD環境
- コマンドラインツール

## Propagatorの仕組み

環境変数を介したコンテキストの伝搬には、環境変数の読み書きが伴います。`TextMapPropagator`は、[API Propagators](../api-propagators/)の仕様で説明されている通常の`Get`、`Set`、`Extract`、`Inject`の機能と併せて使うべきです（SHOULD）。

環境変数をキャリアとして使う場合、

- **環境変数キャリア**は形式に依存しないものでなければならず（MUST）、値を不透明な文字列として扱わなければならず（MUST）、値の検証・パース、その他形式固有の制約の強制といった、伝搬形式固有のロジックを適用してはなりません（MUST NOT）。
- 特定の伝搬形式（例えばW3C Trace ContextやW3C Baggage）を実装する**propagator**は、以下について単独で責任を持ち続けます。
  - キャリアで使うキー名を選ぶこと
  - それらの伝搬形式によって定義された命名規則を強制すること
  - 値を検証・パースすること
  - 切り詰めやその他形式固有の振る舞いを適用すること

言語実装は、初期化時の抽出、子プロセスの環境変数の扱い、セキュリティ上の考慮事項を含む[運用上の指針](#運用上の指針)を文書化すべきです（SHOULD）。

言語実装は、環境変数によるコンテキスト伝搬の一部として子プロセスを起動してはなりません（MUST NOT）。

### キー名の正規化

言語実装は、コンテキスト伝搬のために環境変数の`Get`、`Set`、`Keys`操作が正規化されたキー名を使うことをMUST確実にするものとします。キー名を正規化するために、実装は以下をMUST行うものとします。

- 空のキー名を単一のアンダースコア（`_`）に置き換える
- ASCII文字を大文字化する
- ASCII文字、数字、アンダースコア（`_`）以外のすべての文字をアンダースコア（`_`）に置き換える
- ASCIIの数字で始まってしまう場合、名前の先頭にアンダースコアを付加する

正規化された環境変数名とは、この正規化を適用しても変化しない空でない環境変数名のことです。同様に、正規化された環境変数名は正規表現`^[A-Z_][A-Z0-9_]*$`に一致します。空の環境変数名は非正規化であり、`_`に正規化されます。

このパターンに一致しない環境変数名は非正規化です。

これらの要件は、キャリア、`Getter`、`Setter`、その他言語固有のAPIなど、言語内でその操作を実装するどのコンポーネントにも適用されます。

- `Set`は、propagatorによって提供されたキーの正規化された形式を使って値をMUST書き込むものとします。
- `Get`は、propagatorによって要求されたキーをMUST正規化するものとし、キャリアから読み込むために正規化されたキー名をMUST使用するものとします。
- `Keys`は、すでに正規化されているキー名のみをMUST返すものとします。

例えば、propagatorがキー`x-b3-traceid`を要求した場合、環境固有の`Get`操作は要求されたキーを`X_B3_TRACEID`にMUST正規化するものとし、`X_B3_TRACEID`環境変数をMUST読み込むものとします。その名前が`X_B3_TRACEID`に正規化されるとしても、`x-b3-traceid`という正規化されていない環境変数をMUST NOT読み込むものとします。

> [!NOTE]
> Windowsのような、環境変数の検索で大文字・小文字を区別しないプラットフォームでは、`Get`が行うプラットフォームの検索は、大文字・小文字のみが正規化されたキーと異なる環境変数に一致することがあります。例えば、Windowsのプロセス環境に`traceparent`が含まれている場合、正規化されたキー`TRACEPARENT`を読み込むと`traceparent`の値が返されることがあります。

> [!NOTE]
> この正規化は、[POSIX.1-2024](https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap08.html)で定義されている環境変数の命名規則と整合しています。

### 運用上の指針

> [!IMPORTANT]
> 本節は非規範的であり、使用上の指針のみを提供します。仕様に要件を追加するものではありません。

#### 環境変数の不変性

コンテキストに関連する環境変数は、プロセス起動時の入力として扱うのが最善です。

- アプリケーションは通常、初期化時にコンテキストに関連する環境変数を読み込みます。
- アプリケーションは、親プロセスが存在する環境において、コンテキストに関連する環境変数を変更することを避けます。

#### 子プロセスの起動

子プロセスを起動する際、

- 典型的な親プロセスのフローは、現在の環境変数をコピーし（該当する場合）、そのコピーを変更し、子プロセスを起動する際にそのコピーへコンテキストを注入します。
- 子プロセスの起動時が、環境変数からコンテキストが抽出される時点です。
- 異なるコンテキストやバゲージを持つ複数の子プロセスについては、環境変数のコピーを分けることで、適切な情報を子プロセスごとに分離できます。
- アプリケーションのコードは、SDKからコンテキストを受け取り、それをアプリケーションのプロセス起動機構に渡す責任を持ち続けます。

#### セキュリティ

環境変数は一般に、プロセス内で動作するすべてのコードからアクセス可能です。多くのシステムでは、適切な権限を持つ他のプロセスやユーザーからもアクセスできます。

- 環境変数によるコンテキスト伝搬は、機密情報には適していません。
- マルチテナント環境では、環境変数が他のプロセスや適切な権限を持つユーザーに見える場合、追加の露出リスクがあります。

## 実装の指針

> [!IMPORTANT]
> 本節は非規範的であり、実装上の指針のみを提供します。仕様に要件を追加するものではありません。

OpenTelemetryの言語実装は、環境変数によるコンテキスト伝搬をどのように公開するかについて柔軟性を持ちます。既存の`TextMapPropagator`は、環境固有のキャリア、環境固有の[`Getter`](../api-propagators/#getter-argument)と[`Setter`](../api-propagators/#setter-argument)の実装、あるいはこれらの操作自体を実装するキャリア型と一緒に使えます。環境変数について`Get`、`Set`、`Keys`を実行するコンポーネントが何であれ、そのコンポーネントが上記で説明した正規化の振る舞いに責任を持ちます。言語固有のヘルパーコンポーネントは、その言語実装がサポートするキャリアの形状に対してのみ動作することが期待されます。

実装例:

- [OpenTelemetry .NET実装][di]
- [OpenTelemetry C++実装][ci]
- [OpenTelemetry Go実装][gi]
- [OpenTelemetry Java実装][ji]
- [OpenTelemetry JavaScript実装][jsi]
- [OpenTelemetry Python実装][pi]
- [OpenTelemetry Swift実装][si]

[di]: https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry.Api/Context/Propagation/EnvironmentVariableCarrier.cs
[ci]: https://github.com/open-telemetry/opentelemetry-cpp/blob/main/api/include/opentelemetry/context/propagation/environment_carrier.h
[gi]: https://github.com/open-telemetry/opentelemetry-go-contrib/tree/main/propagators/envcar
[ji]: https://github.com/open-telemetry/opentelemetry-java/tree/main/api/incubator/src/main/java/io/opentelemetry/api/incubator/propagation
[jsi]: https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-propagator-env-carrier
[pi]: https://github.com/open-telemetry/opentelemetry-python/blob/main/opentelemetry-api/src/opentelemetry/propagators/_envcarrier.py
[si]: https://github.com/open-telemetry/opentelemetry-swift-core/blob/main/Sources/OpenTelemetrySdk/Trace/Propagation/EnvironmentContextPropagator.swift

