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


**ステータス**: [安定（Stable）](../../document-status/)（別途明記されている箇所を除く）

## 概要

設定SDKは、[宣言的設定インターフェース](../#宣言的設定)の一部です。

SDKは、[計装設定API](../api/)と、その他の利用者向けの宣言的設定ケーパビリティの実装です。これは以下の主要なコンポーネントから構成されます。

* [In-Memory configuration model](#in-memory-configuration-model)は、[設定モデル](../data-model/)のインメモリ表現です。
* [ConfigProvider](#configprovider)は、[ConfigProvider API](../api/#configprovider)のSDK実装を定義します。
* [SDK extension components](#sdk-extension-components)は、利用者とライブラリがカスタムのSDK拡張プラグインインターフェース（エクスポーター、プロセッサーなど）でファイル設定を拡張する方法を定義します。
* [SDK operations](#sdk-operations)は、設定ファイルを解析し、その内容からSDKコンポーネントを生成する利用者向けAPIを定義します。

### In-Memory configuration model

SDKは、[設定モデル](../data-model/)のインメモリ表現をSHOULD提供するものとします。
[`ConfigProperties`](../api/#configproperties)が任意のマッピングノードのスキーマレスな表現であるのに対し、In-Memory configuration modelは設定モデルのスキーマをSHOULD反映するものとします。

SDKは、このインメモリ表現を自身の言語にとってイディオマティックな方法で提供することが推奨されます。SDKがクラスやインターフェースを公開する必要がある場合、`Configuration`という名前がRECOMMENDEDです。

### ConfigProvider

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

[`ConfigProvider`](../api/#configprovider)のSDK実装は、[設定モデル](../data-model/)の[`.instrumentation`](https://github.com/open-telemetry/opentelemetry-configuration/blob/670901762dd5cce1eecee423b8660e69f71ef4be/examples/kitchen-sink.yaml#L438-L439)マッピングノードを表す[`ConfigProperties`](../api/#configproperties)を使ってMUST作成されるものとします。

### SDK extension components

SDKは、「拡張プラグインインターフェース」とも呼ばれる、さまざまな[プラグインコンポーネント](/works/otel-specs-ja/spec/glossary/#sdk-plugins)をサポートし、利用者とライブラリがサンプリング、処理、データのエクスポートを含む振る舞いをカスタマイズできるようにします。

[設定データモデル](../data-model/)は、これらのプラグインコンポーネントの組み込み実装に対して特定の型をSHOULD定義するものとします。例えば、[`BatchSpanProcessor`](https://github.com/open-telemetry/opentelemetry-configuration/blob/f38ac7c3a499ae5f81924ef9c455c27a56130562/schema/tracer_provider.json#L22)型は、組み込みの[バッチ処理を行うSpanProcessor](/works/otel-specs-ja/spec/trace/sdk/#バッチ処理を行うspanprocessor)を参照します。

このスキーマは、ライブラリや利用者によって定義されたプラグインコンポーネントのカスタム実装を指定する能力をSHOULDサポートするものとします。例えば、カスタムの[span exporter](/works/otel-specs-ja/spec/trace/sdk/#spanexporter)は以下のように設定できます。

```yaml
tracer_provider:
  processors:
    - batch:
        exporter:
          my-exporter:
            config-parameter: value
```

ここでは、tracer providerがバッチspanプロセッサーを持ち、それが`my-exporter`という名前のカスタムspanエクスポーターと組み合わされていることを指定しています。このエクスポーターは`config-parameter: value`で設定されています。この設定が成功するには、`type: SpanExporter`かつ`name: my-exporter`で[`PluginComponentProvider`](#plugincomponentprovider)が[登録](#register-plugincomponentprovider)されていなければなりません。[parse](#parse)が呼び出されると、実装は`my-exporter`に遭遇し、対応する設定を同等の[`ConfigProperties`](../api/#configproperties)表現（すなわち`properties: {config-parameter: value}`）へ変換します。[create](#create)が呼び出されると、実装は`my-exporter`に遭遇し、`parse`の際に決定された`ConfigProperties`を使って、登録済みの`PluginComponentProvider`に対して[create component](#create-component)を呼び出します。

言語間の本質的な違いを踏まえると、拡張コンポーネントの機構の詳細は、OpenTelemetryが定義する他のAPIよりも大きく異なる可能性が高くなります。これは想定されたことであり、実装が定義された振る舞いを実現する限りは許容されます。

#### PluginComponentProvider

`PluginComponentProvider`は、設定を解釈し、特定の種類のSDKプラグインコンポーネントの実装を返す責任を負います。

`PluginComponentProvider`は、[register](#register-plugincomponentprovider)を介して設定のSDK実装に登録されます。これは、言語のエコシステムにおいて何が可能でイディオマティックかに応じて、自動的に行われても、利用者による手動の介入を要求してもかまいません（MAY）。例えばJavaでは、`PluginComponentProvider`は[サービスプロバイダインターフェース（SPI）](https://docs.oracle.com/javase/tutorial/sound/SPI-intro.html)機構を使って自動的に登録される場合があります。

`PluginComponentProvider`の使用法を設定モデルの解釈の中で詳しく説明した[create](#create)を参照してください。

##### サポートされるSDKプラグインコンポーネント

以下の表は、設定データモデルにおけるすべてのSDKプラグインコンポーネントの現在のステータスを一覧にしたものです。

| SDKプラグインコンポーネント                                                                        | 宣言的設定における型                                                                                                    |
|-----------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------|
| [リソース検出器](/works/otel-specs-ja/spec/resource/sdk/#環境からのリソース情報の検出) | [ExperimentalResourceDetection](https://opentelemetry.io/docs/specs/otel-config/types/#type-experimentalresourcedetection) |
| [text mapプロパゲーター](/works/otel-specs-ja/spec/context/api-propagators/#textmap-propagator)                     | [TextMapPropagator](https://opentelemetry.io/docs/specs/otel-config/types/#type-textmappropagator)                         |
| [span exporter](/works/otel-specs-ja/spec/trace/sdk/#spanexporter)                                              | [SpanExporter](https://opentelemetry.io/docs/specs/otel-config/types/#type-spanexporter)                                   |
| [span processor](/works/otel-specs-ja/spec/trace/sdk/#spanprocessor)                                            | [SpanProcessor](https://opentelemetry.io/docs/specs/otel-config/types/#type-spanprocessor)                                 |
| [sampler](/works/otel-specs-ja/spec/trace/sdk/#サンプリング)                                                          | [Sampler](https://opentelemetry.io/docs/specs/otel-config/types/#type-sampler)                                             |
| [ID generator](/works/otel-specs-ja/spec/trace/sdk/#idジェネレーター)                                               | [IdGenerator](https://opentelemetry.io/docs/specs/otel-config/types/#type-idgenerator)                                     |
| [pull metric reader](/works/otel-specs-ja/spec/metrics/sdk/#metricreader)                                        | [PullMetricExporter](https://opentelemetry.io/docs/specs/otel-config/types/#type-pullmetricexporter)                       |
| [push metric exporter](/works/otel-specs-ja/spec/metrics/sdk/#metricexporter)                                    | [PushMetricExporter](https://opentelemetry.io/docs/specs/otel-config/types/#type-pushmetricexporter)                       |
| [metric producer](/works/otel-specs-ja/spec/metrics/sdk/#metricproducer)                                         | [MetricProducer](https://opentelemetry.io/docs/specs/otel-config/types/#type-metricproducer)                               |
| [exemplar reservoir](/works/otel-specs-ja/spec/metrics/sdk/#exemplarreservoir)                                   | まだ利用できません（[#189](https://github.com/open-telemetry/opentelemetry-configuration/issues/189)）                         |
| [log record exporter](/works/otel-specs-ja/spec/logs/sdk/#logrecordexporter)                                     | [LogRecordExporter](https://opentelemetry.io/docs/specs/otel-config/types/#type-logrecordexporter)                         |
| [log record processor](/works/otel-specs-ja/spec/logs/sdk/#logrecordprocessor)                                   | [LogRecordProcessor](https://opentelemetry.io/docs/specs/otel-config/types/#type-logrecordprocessor)                       |

##### PluginComponentProviderの操作

`PluginComponentProvider`は以下の関数をMUST提供するものとします。

* [Create Component](#create-component)

###### Create Component

設定を解釈して、SDKプラグインコンポーネントのインスタンスを作成します。

**パラメータ:**

* `properties` - [In-Memory configuration model](#in-memory-configuration-model)内でそのコンポーネントに指定された設定を表す[`ConfigProperties`](../api/#configproperties)。

**戻り値:** 設定済みのSDKプラグインコンポーネント。

プラグインコンポーネントは、オプションまたは必須のプロパティを持ち、型や形式について特定の要求事項を持つことがあります。`PluginComponentProvider`が受け付けるプロパティの集合は、その要求レベルと期待される型とともに、設定スキーマを構成します。`PluginComponentProvider`は、自身の設定スキーマを文書化し、例を含めるべきです（SHOULD）。

Create Componentが呼び出されると、`PluginComponentProvider`は`properties`を解釈し、自身の設定スキーマに従ってデータを抽出しようとします。これが失敗する場合（例えば必須のプロパティが存在しない、型が一致しないなど）、Create Componentはエラーを返すべきです（SHOULD）。

### SDK operations

設定のSDK実装は以下の操作をMUST提供するものとします。

注記: これらの操作は状態を持たない純粋な関数であるため、型やクラス、インターフェースなどの一部として定義されているわけではありません。SDKはこれらを言語にとってイディオマティックな方法で自由に構成してかまいません。

<!-- TODO: https://github.com/open-telemetry/opentelemetry-specification/issues/3771 -->

#### Parse

[設定ファイル](../data-model/#file-based-configuration-model)を解析し、検証します。

**パラメータ:**

* `file`: 解析対象の[設定ファイル](../data-model/#file-based-configuration-model)。これはファイルパス、言語固有のファイルデータ構造、あるいはファイルの内容のストリームでもかまいません（MAY）。
* `file_format`: `file`のファイル形式（例えば[YAML](../data-model/#yaml-file-format)）。実装は`file_format`パラメータを受け付けても、ファイルの拡張子から推論しても、あるいは`parseYaml(file)`のようなファイル形式固有の`parse`のオーバーロードを含めてもかまいません（MAY）。`parse`が`file_format`を受け付ける場合、そのAPIは利用者がそれを提供するよう義務付けられる形にSHOULD構造化されるものとします。

**戻り値:** [設定モデル](#in-memory-configuration-model)

ParseはMUST[環境変数の置換](../data-model/#environment-variable-substitution)を実行するものとします。

Parseは、存在しないプロパティと、存在するがnullであるプロパティをMUST区別するものとします。例えば、以下のスニペットを考えてみましょう。`.meter_provider.views[0].stream.drop`が存在するがnullである点に注意してください。

```yaml
meter_provider:
  views:
    - selector:
        name: some.metric.name
      stream:
        aggregation:
          drop:
```

その結果、このviewのstreamは`drop`集約で設定されるべきです。一部の集約には追加の引数がありますが、`drop`にはないことに注意してください。利用者は、こうした場合に空のオブジェクト（すなわち`drop: {}`）を指定するよう要求されてはなりません（MUST NOT）。

SDKに組み込まれていない[SDK extension component](#sdk-extension-components)への参照に遭遇した場合、Parseは、対応する設定を、[Create Component](#create-component)で説明されている通りの汎用的な[ConfigProperties](../api/#configproperties)表現へMUST解決するものとします。

Parseは、以下の場合にエラーをSHOULD返すものとします。

* `file`が存在しない、あるいは無効である場合
* 解析された`file`の内容が[設定モデル](../data-model/)のスキーマに準拠しない場合。これには、スキーマに組み込まれたすべての制約の強制（例えば必須プロパティが存在すること、プロパティが指定された型に準拠していることなど）が含まれることに注意してください。

#### Create

設定モデルを解釈し、SDKコンポーネントを返します。

**パラメータ:**

* `configuration` - [In-Memory configuration model](#in-memory-configuration-model)。

**戻り値:** トップレベルのSDKコンポーネント。

* [TracerProvider](https://opentelemetry.io/docs/specs/otel/trace/sdk/#tracerprovider)
* [MeterProvider](/works/otel-specs-ja/spec/metrics/sdk/#meterprovider)
* [LoggerProvider](/works/otel-specs-ja/spec/logs/sdk/#loggerprovider)
* [Propagators](/works/otel-specs-ja/spec/context/api-propagators/#composite-propagator)
* **ステータス**: [Development](../../document-status/) `MeterProvider`、`LoggerProvider`、`TracerProvider`に関連付けられた解決済みの`Resource`。
* **ステータス**: [Development](../../document-status/) - [ConfigProvider](#configprovider)

これら複数の戻り値は、タプルやコンポーネントをカプセル化した何らかのデータ構造を使って返してもかまいません（MAY）。

デフォルトおよびnullの振る舞いに関するCreateの要求事項は以下に記述します。[`defaultBehavior`と`nullBehavior`](https://github.com/open-telemetry/opentelemetry-configuration/blob/main/CONTRIBUTING.md#json-schema-source-and-output)は設定データモデルの中で定義されている点に注意してください。

* プロパティが存在し、その値がnullである場合、Createは`nullBehavior`を使わなければならず（MUST）、`nullBehavior`が設定されていなければ`defaultBehavior`を使わなければなりません（MUST）。
* プロパティが必須であり、かつ存在しない場合、CreateはエラーをMUST返すものとします。

いくつかの例で説明します。

* [`BatchSpanProcessor`](https://opentelemetry.io/docs/specs/otel-config/types/#type-batchspanprocessor)を設定する際、`schedule_delay`が存在しないか存在するがnullである場合、そのコンポーネントは`defaultBehavior`である`5000`に従って設定されます。
* [`SpanExporter`](https://opentelemetry.io/docs/specs/otel-config/types/#type-spanexporter)を設定する際、`console`が存在してnullである場合、`console`がnullableであるため、そのコンポーネントはデフォルト設定の`console`エクスポーターで設定されます。

[設定モデル](../data-model/)は、標準のJSON schemaのキーワードでは符号化できないプロパティのセマンティクスを捕捉するために、JSON schemaの[`description`](https://json-schema.org/understanding-json-schema/reference/annotations)アノテーションを使います。Createは、プロパティの`description`に従って無効な値に遭遇した場合、エラーをSHOULD返すものとします。例えば、[`HttpTls`](https://opentelemetry.io/docs/specs/otel-config/types/#type-httptls)を設定する際、`ca_file`がプロパティの説明で定義されている絶対ファイルパスでない場合、エラーを返します。

SDKに組み込まれていない[SDK plugin component](#sdk-extension-components)への参照に遭遇した場合、Createは、[register](#register-plugincomponentprovider)に使われた対応する`type`と`name`を持つ[`PluginComponentProvider`](#plugincomponentprovider)の[Create Component](#create-component)を使って、`parse`の際に決定された設定`properties`を引数として含めて、そのコンポーネントをMUST解決するものとします。その`type`と`name`で登録された`PluginComponentProvider`が存在しない場合、CreateはエラーをSHOULD返すものとします。[Create Component](#create-component)がエラーを返す場合、CreateはそのエラーをSHOULD伝播するものとします。

これは、初期化における[エラー処理の原則](/works/otel-specs-ja/spec/error-handling/#エラー処理の基本原則)に従って、`configuration`の中でエラーに遭遇した場合（すなわちfail fast）、エラーをSHOULD返すものとします。

**ステータス**: [Development](../../document-status/) SDKの実装は、`Create`によって初期化されるコンポーネントのプログラマティックなカスタマイズを可能にするオプションを提供してもかまいません（MAY）。これにより、設定モデルではまだ表現できない、あるいは今後も表現できないかもしれない概念の設定が可能になります。例えば、JavaのOTLPエクスポーターは[ExecutorService](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html)の設定を許容します。これはニッチですが、スレッドプールを厳密に制御する必要があるアプリケーションにとって重要なオプションです。このプログラマティックなカスタマイズは、`Create`にオプションのコールバックを渡す形をとる場合があります。このコールバックは、初期化される各SDKサブコンポーネント（またはSDKコンポーネント型のサブセット）とともに呼び出されます。例えば、以下のスニペットを考えてみましょう。

```yaml
file_format: 1.0
tracer_provider:
  processors:
    - batch:
        exporter:
          otlp_http:
```

このコールバックは、OTLP HTTPエクスポーター、Batch SpanProcessor、Tracer ProviderのSDK表現とともに呼び出されます。このパターンは、解決済みのトップレベルのSDKコンポーネントから特定のコンポーネントまでたどる必要なく、より低レベルの部分をプログラマティックに設定する機会を提供します。

<!-- TODO: https://github.com/open-telemetry/opentelemetry-specification/issues/4804 -->

#### Register PluginComponentProvider

SDKは、[`PluginComponentProvider`](#plugincomponentprovider)を登録する仕組みをMUST提供するものとします。この仕組みは、言語固有かつ自動的なものでもかまいません（MAY）。例えばJavaの実装では、特定のインターフェースの実装を`PluginComponentProvider`として登録するために[サービスプロバイダインターフェース](https://docs.oracle.com/javase/tutorial/sound/SPI-intro.html)機構を使う場合があります。

**パラメータ:**

* `plugin_component_provider` - `PluginComponentProvider`。
* `type` - それが提供するプラグインコンポーネントの型（例えばSpanExporter、Samplerなど）。
* `name` - コンポーネントの型を識別するために使われる名前。これは、対応する`component_provider`がそのコンポーネントを提供することを指定するために[設定モデル](../data-model/)の中で使われます。

`type`と`name`は一意のキーを構成します。同じ`type`と`name`の組み合わせで複数回呼び出された場合、RegisterはエラーをMUST返すものとします。

SDKは、自身の言語にとってイディオマティックな方法で`type`をSHOULD表現するものとします。例えば、クラスリテラルや列挙型などです。
サポートされる`type`の値の集合については、[サポートされるSDK拡張プラグイン](#sdk-extension-components)を参照してください。

### Examples

#### Via configuration API

設定の[Parse](#parse)と[Create](#create)の操作は、[Configuration Model](../data-model/)とともに、単純または複雑な設定目標を達成するためにさまざまな方法で組み合わせられます。

例えば単純なケースでは、設定ファイルを指定して`Parse`を呼び出し、その結果を`Create`に渡すことで設定済みのSDKコンポーネントを得ます。

```java
OpenTelemetry openTelemetry = OpenTelemetry.noop();
try {
    // Parse configuration file to configuration model
    OpenTelemetryConfiguration configurationModel = parse(new File("/app/sdk-config.yaml"));
    // Create SDK components from configuration model
    openTelemetry = create(configurationModel);
} catch (Throwable e) {
    log.error("Error initializing SDK from configuration file", e);
}

// Access SDK components and install instrumentation
TracerProvider tracerProvider = openTelemetry.getTracerProvider();
MeterProvider meterProvider = openTelemetry.getMeterProvider();
LoggerProvider loggerProvider = openTelemetry.getLoggerProvider();
ContextPropagators propagators = openTelemetry.getPropagators();
ConfigProvider configProvider = openTelemetry.getConfigProvider();
```

より複雑なケースでは、異なるソースから複数の設定ファイルを解析し、カスタムロジックを使ってそれらをマージし、マージされた設定モデルからSDKコンポーネントを作成する場合があります。

```java
OpenTelemetry openTelemetry = OpenTelemetry.noop();
try {
    // Parse local and remote configuration files to configuration models
    OpenTelemetryConfiguration localConfigurationModel = parse(new File("/app/sdk-config.yaml"));
    OpenTelemetryConfiguration remoteConfigurationModel = parse(getRemoteConfiguration("http://example-host/config/my-application"));

    // Merge the configuration models using custom logic
    OpenTelemetryConfiguration resolvedConfigurationModel = merge(localConfigurationModel, remoteConfigurationModel);

    // Create SDK components from resolved configuration model
    openTelemetry = create(resolvedConfigurationModel);
} catch (Throwable e) {
    log.error("Error initializing SDK from configuration file", e);
}

// Access SDK components and install instrumentation
TracerProvider tracerProvider = openTelemetry.getTracerProvider();
MeterProvider meterProvider = openTelemetry.getMeterProvider();
LoggerProvider loggerProvider = openTelemetry.getLoggerProvider();
ContextPropagators propagators = openTelemetry.getPropagators();
ConfigProvider configProvider = openTelemetry.getConfigProvider();
```

#### Via OTEL_CONFIG_FILE

[OTEL_CONFIG_FILE](../sdk-environment-variables/#宣言的設定)環境変数を設定すると（それをサポートする言語では）、言語固有の設定の詳細を学んだり多数の環境変数を使ったりする必要なく、OpenTelemetryコンポーネントを初期化する便利な方法を利用者に提供します。設定済みのコンポーネントへアクセスして計装へインストールするパターンは言語ごとに異なります。例えばJavaでの使用法は以下のようになります。

```shell
# Set the required env var to the location of the configuration file
export OTEL_CONFIG_FILE="/app/sdk-config.yaml"
```

```java
// Initialize SDK using autoconfigure model, which recognizes that OTEL_CONFIG_FILE is set and configures the SDK accordingly
OpenTelemetry openTelemetry = AutoConfiguredOpenTelemetrySdk.initialize().getOpenTelemetrySdk();

// Access SDK components and install instrumentation
TracerProvider tracerProvider = openTelemetry.getTracerProvider();
MeterProvider meterProvider = openTelemetry.getMeterProvider();
LoggerProvider loggerProvider = openTelemetry.getLoggerProvider();
ContextPropagators propagators = openTelemetry.getPropagators();
ConfigProvider configProvider = openTelemetry.getConfigProvider();
```

自動計装を使う場合、この初期化のフローは自動的に発生する場合があります。

### References

* 設定の提案（[OTEP #225](https://github.com/open-telemetry/oteps/pull/225)）

