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


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

OpenTelemetryの利用者には、OpenTelemetry APIとの計装のやり取りが実際にテレメトリーを生成するための手段が必要です。OpenTelemetry SDK（以下、単にSDKと呼びます）は、この機能を利用者に提供するOpenTelemetry APIの実装です。

OpenTelemetryのすべての言語実装は、SDKをMUST提供するものとします。

## MeterProvider

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

`MeterProvider`は、[Resource](/works/otel-specs-ja/spec/resource/sdk/)を指定できる手段をMUST提供するものとします。`Resource`が指定された場合、その`MeterProvider`から取得されるすべての`Meter`が生成するメトリクスに関連付けられるべきです（SHOULD）。[トレーシングSDK仕様](/works/otel-specs-ja/spec/trace/sdk/#追加のspanインターフェース)は、これを効率的に実装する方法についていくつかの提案を示しています。

### MeterProviderの作成

SDKは、複数の独立した`MeterProvider`の作成を許容すべきです（SHOULD）。

### Meterの作成

`Meter`インスタンスの作成は、`MeterProvider`を通じてのみ可能であるべきです（SHOULD）（[API](../api/#meterprovider)を参照）。

`MeterProvider`は、[Meterの取得API](../api/#meterの取得)をMUST実装するものとします。

利用者から提供された入力は、作成される`Meter`に格納される[`InstrumentationScope`](https://opentelemetry.io/docs/specs/otel/common/instrumentation-scope/)インスタンスの作成にMUST使用されるものとします。

無効な`name`（nullまたは空文字列）が指定された場合、nullを返したり例外を発生させたりするのではなく、フォールバックとして動作する`Meter`をMUST返すものとし、その`name`は元の無効な値を保持すべきであり（SHOULD）、指定された値が無効であることを報告するメッセージがログにSHOULD記録されるものとします。

**ステータス**: [Development](../../document-status/) - `MeterProvider`は、設定された[MeterConfigurator](#meterconfigurator)を使って関連する[MeterConfig](#meterconfig)をMUST計算するものとし、その`MeterConfig`に準拠する振る舞いをする`Meter`をMUST作成するものとします。

### 設定

設定（すなわち[MetricExporters](#metricexporter)、[MetricReaders](#metricreader)、[Views](#view)、および（**Development**）[MeterConfigurator](#meterconfigurator)）は、`MeterProvider`にMUST所有されるものとします。設定は、適切であれば`MeterProvider`作成時に適用されてもかまいません（MAY）。

`MeterProvider`は、設定を更新する方法を提供してもかまいません（MAY）。設定が更新された場合（例えば`MetricReader`の追加）、更新された設定はすでに返されているすべての`Meter`にもMUST適用されるものとします（すなわち、`Meter`が設定変更の前後どちらに`MeterProvider`から取得されたかはMUST NOT問題にならないものとします）。注: 実装上、これは`Meter`インスタンスが自身の`MeterProvider`への参照を持ち、この参照を介してのみ設定にアクセスすることを意味する場合があります。

#### MeterConfigurator

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

`MeterConfigurator`は、[Meter](#meter)の[MeterConfig](#meterconfig)を計算する関数です。

この関数は以下のパラメータをMUST受け付けるものとします。

* `meter_scope`: `Meter`の[`InstrumentationScope`](https://opentelemetry.io/docs/specs/otel/common/instrumentation-scope/)。

この関数は、関連する`MeterConfig`、または[デフォルトのMeterConfig](#meterconfig)を使うべきであることを示す何らかの信号をMUST返すものとします。この信号は、言語にとってイディオマティックな方法に応じて、nil、null、空、あるいはデフォルト`MeterConfig`のインスタンスであってもかまいません（MAY）。

この関数は、`Meter`が最初に作成されたときと、`MeterProvider`の`MeterConfigurator`が更新されたとき（更新がサポートされている場合）に、現存するすべての`Meter`について呼び出されます。したがって、この関数がすぐに値を返すことが重要です。

`MeterConfigurator`は柔軟性を最大化するために関数としてモデル化されています。しかし、実装は一般的な使用例に対応するため、簡略化された関数やヘルパー関数を提供してもかまいません（MAY）。

* 名前で1つ以上のMeterを、完全一致またはパターンマッチングによって選択する。
* 1つ以上の特定のMeterを無効にする。
* すべてのMeterを無効にし、1つ以上の特定のMeterを選択的に有効にする。

### Shutdown

このメソッドは、プロバイダーが必要なクリーンアップを行うための手段を提供します。

`Shutdown`は、`MeterProvider`インスタンスごとにMUST一度だけ呼び出されるものとします。`Shutdown`の呼び出し後、`Meter`を取得しようとするその後の試みは許可されません。SDKは、可能であればこれらの呼び出しに対して有効なno-op Meterを返すべきです（SHOULD）。

`Shutdown`は、呼び出し元に成功、失敗、タイムアウトのいずれであったかを知らせる手段をSHOULD提供するものとします。

`Shutdown`は、何らかのタイムアウト内に完了または中断すべきです（SHOULD）。`Shutdown`は、ブロッキングAPIとして実装されても、コールバックやイベントを通じて呼び出し元に通知する非同期APIとして実装されてもかまいません（MAY）。[OpenTelemetry SDKの作者](/works/otel-specs-ja/spec/overview/#sdk)は、シャットダウンのタイムアウトを設定可能にするかどうかを決めてもかまいません（MAY）。

`Shutdown`は、登録されているすべての[MetricReader](#metricreader)と[MetricExporter](#metricexporter)インスタンスに対して`Shutdown`を呼び出すことによって、少なくともMUST実装されるものとします。

### ForceFlush

このメソッドは、プロバイダーが、対応する[Push Metric Exporter](#push-metric-exporter)を持つ登録済みの[MetricReader](#metricreader)インスタンスに通知し、メトリクスの収集と送信のためにできる限りのことを行わせる手段を提供します。注: [Pull Metric Exporter](#pull-metric-exporter)は、スクレイパーから要求されたときにのみデータを送信できるため、`ForceFlush`はほとんど意味を持ちません。

`ForceFlush`は、`ForceFlush`を実装している登録済みの[MetricReader](#metricreader)インスタンスすべてに対して`ForceFlush`をMUST呼び出すものとします。

`ForceFlush`は、呼び出し元に成功、失敗、タイムアウトのいずれであったかを知らせる手段をSHOULD提供するものとします。`ForceFlush`は、エラー状態がある場合は何らかの**ERROR**ステータスを返すべきであり（SHOULD）、エラー状態がない場合は何らかの**NO ERROR**ステータスを返すべきです（SHOULD）。言語実装は、**ERROR**と**NO ERROR**をどのようにモデル化するかを決めてもかまいません（MAY）。

`ForceFlush`は、何らかのタイムアウト内に完了または中断すべきです（SHOULD）。`ForceFlush`は、ブロッキングAPIとして実装されても、コールバックやイベントを通じて呼び出し元に通知する非同期APIとして実装されてもかまいません（MAY）。[OpenTelemetry SDKの作者](/works/otel-specs-ja/spec/overview/#sdk)は、フラッシュのタイムアウトを設定可能にするかどうかを決めてもかまいません（MAY）。

### View

`View`は、SDKによって出力されるメトリクスをカスタマイズする柔軟性をSDKの利用者に提供します。`View`が必要となる例をいくつか示します。

* どの[Instrument](../api/#instrument)を処理・無視するかをカスタマイズする。例えば、[計装対象ライブラリ](../../glossary/#instrumented-library)が温度と湿度の両方を提供できるとしても、アプリケーション開発者が温度だけを必要としている場合があります。
* 集約をカスタマイズする。Instrumentに関連付けられたデフォルトの集約が利用者の要求を満たさない場合です。例えば、HTTPクライアントライブラリはデフォルトでHTTPクライアントのリクエスト所要時間を[Histogram](../api/#histogram)として公開しますが、アプリケーション開発者が発信リクエストの総数だけを必要としている場合があります。
* メトリクスに報告される属性をカスタマイズする。例えば、HTTPサーバーライブラリはHTTPの動詞（GET、POSTなど）とHTTPステータスコード（200、301、404など）を公開しますが、アプリケーション開発者はHTTPステータスコードだけを気にかけている場合があります（例えばHTTPステータスコードごとのHTTPリクエストの総数を報告する）。アプリケーション開発者がいかなる属性も必要としない極端な場合もあり得ます（例えば、受信したすべてのリクエストの総数だけを取得する）。

SDKは、利用者が`MeterProvider`に対するViewを作成できる機能をMUST提供するものとします。この機能は、入力として[Instrumentの選択基準](#instrumentの選択基準)と、その結果得られる[ストリーム設定](#ストリーム設定)をMUST受け付けるものとします。

SDKは、`MeterProvider`にViewを登録する手段をMUST提供するものとします。

#### Instrumentの選択基準

Instrumentの選択基準とは、あるViewをInstrumentに適用するかどうかを決定する述語です。

基準は加算的に扱われるべきです（SHOULD）。これは、Viewが適用されるためにはInstrumentが提供されたすべての基準に一致する必要があることを意味します。例えば、基準が_instrument name == "Foobar"_と_instrument type is Histogram_である場合、これは_(instrument name == "Foobar") AND (instrument type is Histogram)_として扱われます。

SDKは以下の基準をMUST受け付けるものとします。

* `name`: 一致させるInstrumentの名前。この`name`は、以下の方法でInstrumentに一致するよう評価されます。

  1. `name`の値が`*`である場合、この基準はすべてのInstrumentに一致します。
  2. `name`の値がInstrumentとまったく同じである場合、この基準はそのInstrumentに一致します。

  さらに、SDKは以下の文字を使った`name`基準のワイルドカードパターンマッチングをサポートしてもかまいません（MAY）。

  * 疑問符（`?`）: 任意の1文字に一致します
  * アスタリスク（`*`）: 何もない場合を含む任意の数の任意の文字に一致します

  ワイルドカードパターンマッチングがサポートされている場合、`name`基準は、そのワイルドカードパターンがInstrumentの名前に一致すると評価されれば一致します。

  SDKが一般にワイルドカードをサポートしていない場合でも、特別な単一のアスタリスク（`*`）文字がすべてのInstrumentに一致することはMUST認識するものとします。

  利用者は`name`を提供できますが、それは利用者の裁量に委ねられます。したがって、Instrument選択基準のパラメータは`name`を受け付ける形で構造化する必要がありますが、利用者にそれを提供することをMUST NOT義務付けるものとします。
* `type`: 一致させるInstrumentの種別。`type`の値がInstrumentの種別と同じである場合、この基準はそのInstrumentに一致します。

  利用者は`type`を提供できますが、それは利用者の裁量に委ねられます。したがって、Instrument選択基準のパラメータは`type`を受け付ける形で構造化する必要がありますが、利用者にそれを提供することをMUST NOT義務付けるものとします。
* `unit`: `unit`の値がInstrumentの単位と同じである場合、この基準はそのInstrumentに一致します。

  利用者は`unit`を提供できますが、それは利用者の裁量に委ねられます。したがって、Instrument選択基準のパラメータは`unit`を受け付ける形で構造化する必要がありますが、利用者にそれを提供することをMUST NOT義務付けるものとします。
* `meter_name`: `meter_name`の値がInstrumentを作成したMeterと同じである場合、この基準はそのInstrumentに一致します。

  利用者は`meter_name`を提供できますが、それは利用者の裁量に委ねられます。したがって、Instrument選択基準のパラメータは`meter_name`を受け付ける形で構造化する必要がありますが、利用者にそれを提供することをMUST NOT義務付けるものとします。
* `meter_version`: `meter_version`の値がInstrumentを作成したMeterと同じバージョンである場合、この基準はそのInstrumentに一致します。

  利用者は`meter_version`を提供できますが、それは利用者の裁量に委ねられます。したがって、Instrument選択基準のパラメータは`meter_version`を受け付ける形で構造化する必要がありますが、利用者にそれを提供することをMUST NOT義務付けるものとします。
* `meter_schema_url`: `meter_schema_url`の値がInstrumentを作成したMeterと同じスキーマURLである場合、この基準はそのInstrumentに一致します。

  利用者は`meter_schema_url`を提供できますが、それは利用者の裁量に委ねられます。したがって、Instrument選択基準のパラメータは`meter_schema_url`を受け付ける形で構造化する必要がありますが、利用者にそれを提供することをMUST NOT義務付けるものとします。

SDKは追加の基準を受け付けてもかまいません（MAY）。例えば、強い型付けを持つ言語では、点の型に関する基準をサポートしてもかまいません（例えば、基底の数値が整数か有理数かに基づいてInstrumentを選択できるようにする）。利用者はSDKが受け付けるこうした追加の基準を提供できますが、それは利用者の裁量に委ねられます。したがって、Instrument選択基準は、これらの基準を受け付ける形で構造化してかまいませんが、利用者にそれらの提供をMUST NOT義務付けるものとします。

#### ストリーム設定

ストリーム設定とは、`MeterProvider`がテレメトリーパイプラインを定義するために使う[メトリックストリーム](/works/otel-specs-ja/spec/metrics/data-model/#events--data-stream--timeseries)を定義するパラメータです。

SDKは以下のストリーム設定パラメータをMUST受け付けるものとします。

* `name`: 使用すべきメトリックストリーム名。

  競合を避けるため、`name`が提供される場合、そのViewは最大1個のInstrumentを選択するInstrumentセレクターを持つべきです（SHOULD）。ストリーム設定`name`パラメータを持つViewのInstrument選択基準が複数のInstrumentを選択できる場合（すなわちワイルドカード）、SDKは初期化時の[エラー処理の原則](/works/otel-specs-ja/spec/error-handling/#エラー処理の基本原則)に従って早期に失敗してもかまいません（MAY）。

  利用者は`name`を提供できますが、それは利用者の裁量に委ねられます。したがって、ストリーム設定のパラメータは`name`を受け付ける形で構造化する必要がありますが、利用者にそれを提供することをMUST NOT義務付けるものとします。利用者が`name`の値を提供しない場合、デフォルトでそのViewが一致するInstrumentの名前がMUST使用されるものとします。

  ストリーム設定を介して提供される`name`は、[Instrument名の構文](../api/#instrument名の構文)に準拠することはREQUIREDではなく、SDKはこの構文に対してそれを検証することをMUST NOT行うものとします。
* `description`: 使用すべきメトリックストリームの説明。

  利用者は`description`を提供できますが、それは利用者の裁量に委ねられます。したがって、ストリーム設定のパラメータは`description`を受け付ける形で構造化する必要がありますが、利用者にそれを提供することをMUST NOT義務付けるものとします。利用者が`description`の値を提供しない場合、デフォルトでそのViewが一致するInstrumentの説明がMUST使用されるものとします。
* `attribute_keys`: これは、少なくとも、メトリックストリームで捕捉される測定値に対する属性キーの許可リストです。この許可リストには、保持しなければならない属性を識別する属性キーが含まれ、他のすべての属性はMUST無視されるものとします。

  実装は、このパラメータに対して追加の属性フィルタリング機能を受け付けてもかまいません（MAY）。

  利用者は`attribute_keys`を提供できますが、それは利用者の裁量に委ねられます。したがって、ストリーム設定のパラメータは`attribute_keys`を受け付ける形で構造化する必要がありますが、利用者にそれらを提供することをMUST NOT義務付けるものとします。利用者が値を提供しない場合、SDKは代わりにInstrumentに設定された[`Attributes`](../api/#instrumentのadvisoryパラメータ) advisoryパラメータをSHOULD使用するものとします。`Attributes` advisoryパラメータが存在しない場合、すべての属性がMUST保持されるものとします。

  さらに、実装は属性キーの除外リストの設定をSHOULDサポートするものとします。この除外リストには、除外しなければならない属性を識別する属性キーが含まれ、他のすべての属性はMUST保持されるものとします。属性キーが許可リストと除外リストの両方に含まれる場合、SDKは初期化時の[エラー処理の原則](/works/otel-specs-ja/spec/error-handling/#エラー処理の基本原則)に従って早期に失敗してもかまいません（MAY）。

  > [!NOTE]
  > View設定によってメトリックストリームから除去された属性キー（例えば機密データを含む属性を除去するため）は、*フィルタリングされた属性*としてExemplarに引き続きエクスポートされる場合があります。これが望ましくない場合、`AlwaysOff` `ExemplarFilter`を設定してExemplarを無効にすることも、カスタムの`ExemplarFilter`や`ExemplarReservoir`を設定してExemplarとしてサンプリングされる測定値を制御することもできます。

  SDKのドキュメントは、View設定によってメトリックストリームから除外された属性がフィルタリングされた属性としてExemplarに引き続きエクスポートされる場合があることを利用者にSHOULD伝えるものとし、Exemplarサンプリングを無効化・設定する方法を記述すべきです（SHOULD）。

* `aggregation`: メトリックストリームのデータを集約する際に使う[集約](#aggregation)関数の名前。

  利用者は`aggregation`を提供できますが、それは利用者の裁量に委ねられます。したがって、ストリーム設定のパラメータは`aggregation`を受け付ける形で構造化する必要がありますが、利用者にそれを提供することをMUST NOT義務付けるものとします。利用者が`aggregation`の値を提供しない場合、`MeterProvider`は、[MetricReader](#metricreader)インスタンスに応じてInstrument種別に基づいて設定可能な[デフォルト集約](#default-aggregation)をMUST適用するものとします。
* `exemplar_reservoir`: `MeterProvider`がexemplarを格納する際に使うexemplarレザバーを生成する関数型。この関数型は、集約によって異なるレザバーを選択できるようにする、集約選択機能に類似したファクトリまたはコールバックである必要があります。

  利用者は`exemplar_reservoir`を提供できますが、それは利用者の裁量に委ねられます。したがって、ストリーム設定のパラメータは`exemplar_reservoir`を受け付ける形で構造化する必要がありますが、利用者にそれを提供することをMUST NOT義務付けるものとします。利用者が`exemplar_reservoir`の値を提供しない場合、`MeterProvider`は[デフォルトのexemplarレザバー](#exemplarのデフォルト)をMUST適用するものとします。
* `aggregation_cardinality_limit`: 単一のInstrumentによって1回の収集サイクルで出力できるデータポイントの最大数を定義する正の整数値。以下の[カーディナリティ制限](#cardinality-limits)を参照してください。

  利用者は`aggregation_cardinality_limit`を提供できますが、それは利用者の裁量に委ねられます。したがって、ストリーム設定のパラメータは`aggregation_cardinality_limit`を受け付ける形で構造化する必要がありますが、利用者にそれを提供することをMUST NOT義務付けるものとします。利用者が`aggregation_cardinality_limit`の値を提供しない場合、`MeterProvider`は、`MetricReader`に設定された[デフォルトの集約カーディナリティ制限](#metricreader)をMUST適用するものとします。

#### Measurementの処理

SDKは、Instrumentで行われたMeasurementをどのように処理するかを決定するために、以下の論理をSHOULD使用するものとします。

* そのInstrumentを「所有」する`MeterProvider`を特定する。
* `MeterProvider`に登録された`View`がない場合、そのInstrumentを取り、[MetricReader](#metricreader)インスタンスの`aggregation`プロパティに応じてInstrument種別に基づくデフォルトのAggregationを適用する。[Instrument advisoryパラメータ](#instrument-advisory-parameters)があれば、それはMUST尊重されるものとする。
* `MeterProvider`に1つ以上の`View`が登録されている場合。
  * Instrumentが選択基準に一致する可能性がある場合、それぞれのViewについて。
    * 同じ一致するInstrumentに登録されている他のViewとは独立に、そのViewのストリーム設定を適用しようとする（すなわちViewはマージされない）。これにより、ストリーム設定が重複しないプロパティを指定していても（例えば、あるViewが`aggregation`を設定し、別のViewが`attribute_keys`を設定し、両方がストリーム`name`をInstrumentが設定するデフォルトのままにしている場合）、[メトリックIDが衝突する](/works/otel-specs-ja/spec/metrics/data-model/#opentelemetry-protocol-data-model-producer-recommendations)可能性があります。Viewの適用がメトリックIDの衝突を招く場合、実装はそのViewを適用して警告を発すべきです（SHOULD）。セマンティックエラーを生じさせずにViewを適用することができない場合（例えば、Viewが非同期Instrumentに[Explicit bucket histogram aggregation](#explicit-bucket-histogram-aggregation)を使うように設定する場合）、実装は警告を発し、そのViewが適用されなかったかのように処理を続けるべきです（SHOULD）。ViewとInstrument advisoryパラメータの両方が[ストリーム設定](#ストリーム設定)の同じ側面を指定している場合、Viewで定義された設定はadvisoryパラメータよりMUST優先されるものとします。
  * Instrumentが登録されているどの`View`にも一致しない場合、SDKはデフォルトの集約とtemporalityを使ってそのInstrumentを有効化すべきです（SHOULD）。利用者は、[Drop aggregation](#drop-aggregation)を使ったすべてに一致するViewを設定することで、デフォルトでInstrumentを無効化できます。

#### Viewの例

`MeterProvider`に対してViewを作成するSDKの機能の例を示します。

```python
# Python
'''
+------------------+
| MeterProvider    |
|   Meter A        |
|     Counter X    |
|     Histogram Y  |
|   Meter B        |
|     Gauge Z      |
+------------------+
'''

# metrics from X and Y (reported as Foo and Bar) will be exported
meter_provider
    .add_view("X")
    .add_view("Foo", instrument_name="Y")
    .add_view(
        "Bar",
        instrument_name="Y",
        aggregation=HistogramAggregation(buckets=[5.0, 10.0, 25.0, 50.0, 100.0]))
    .add_metric_reader(PeriodicExportingMetricReader(ConsoleExporter()))
```

```python
# all the metrics will be exported using the default configuration
meter_provider.add_metric_reader(PeriodicExportingMetricReader(ConsoleExporter()))
```

```python
# all the metrics will be exported using the default configuration
meter_provider
    .add_view("*") # a wildcard view that matches everything
    .add_metric_reader(PeriodicExportingMetricReader(ConsoleExporter()))
```

```python
# Counter X will be exported as cumulative sum
meter_provider
    .add_view("X", aggregation=SumAggregation())
    .add_metric_reader(PeriodicExportingMetricReader(ConsoleExporter()))
```

```python
# Counter X will be exported as a delta sum and the default attributes
# Counter X, Histogram Y, and Gauge Z will be exported with 2 attributes (a and b)
# A warning will be emitted for conflicting metric identities on Counter X (as two Views matching that Instrument
# are configured with the same default name X) and streams from both views will be exported
meter_provider
    .add_view("X", aggregation=SumAggregation())
    .add_view("*", attribute_keys=["a", "b"]) # wildcard view matches everything, including X
    .add_metric_reader(PeriodicExportingMetricReader(ConsoleExporter()),
              temporality=lambda kind: Delta if kind in [Counter, AsyncCounter, Histogram] else Cumulative)
```

```python
# Only Counter X will be exported, with the default configuration (match-all drop aggregation does not result in
# conflicting metric identities)
meter_provider
    .add_view("X")
    .add_view("*", aggregation=DropAggregation()) # a wildcard view to disable all instruments
    .add_metric_reader(PeriodicExportingMetricReader(ConsoleExporter()))
```

### Aggregation

`Aggregation`は、[View](#view)を通じて設定され、Instrumentから得られる[Measurement](../api/#measurement)から[集約されたメトリクス](/works/otel-specs-ja/spec/metrics/data-model/#opentelemetry-protocol-data-model)を計算する方法と手段をSDKに伝えます。

注: 「_aggregation_」という用語は「_aggregator_」の代わりに使われています。実装者は将来SDKがカスタム集約実装を許容するようになった際のために、「aggregator」という用語を予約しておくことがRECOMMENDEDです。

`Aggregation`は、操作（すなわちSum、Histogram、Min、Maxのような[分解可能な集約関数](https://en.wikipedia.org/wiki/Aggregate_function#Decomposable_aggregate_functions)）と、任意の設定パラメータのオーバーライドを指定します。任意の設定パラメータのオーバーライドで上書きされない限り、その操作のデフォルトの設定パラメータ値が使われます。

注: 実装者は、Aggregationとその任意の設定パラメータの意味を表すために、自分の言語にとって最良のイディオマティックな方法を選んでもかまいません（MAY）。

例: Viewは文字列名（すなわち"ExplicitBucketHistogram"）でAggregationを指定します。

```python
# Use Histogram with custom boundaries
meter_provider
  .add_view(
    "X",
    aggregation="ExplicitBucketHistogram",
    aggregation_params={"Boundaries": [0, 10, 100]}
    )
```

例: Viewはクラスや型のインスタンスでAggregationを指定します。

```c#
// Use Histogram with custom boundaries
meterProviderBuilder
  .AddView(
    instrumentName: "X",
    aggregation: new ExplicitBucketHistogramAggregation(
      boundaries: new double[] { 0.0, 10.0, 100.0 }
    )
  );
```

SDKは、[メトリクスデータモデル](/works/otel-specs-ja/spec/metrics/data-model/)の[メトリックポイント](/works/otel-specs-ja/spec/metrics/data-model/#metric-points)をサポートするため、以下の`Aggregation`をMUST提供するものとします。

- [Drop](#drop-aggregation)
- [Default](#default-aggregation)
- [Sum](#sum-aggregation)
- [Last Value](#last-value-aggregation)
- [Explicit Bucket Histogram](#explicit-bucket-histogram-aggregation)

SDKは、以下の`Aggregation`をSHOULD提供するものとします。

- [Base2 Exponential Bucket Histogram](#base2-exponential-bucket-histogram-aggregation)

#### Drop Aggregation

Drop Aggregationは、このAggregationに対するすべてのInstrument Measurementを無視・破棄するようSDKに伝えます。

このAggregationには設定パラメータがありません。

#### Default Aggregation

Default Aggregationは、Instrumentの`kind`を使って集約を選択し、`advisory`パラメータを使って集約の設定パラメータに影響を与えるようSDKに伝えます（「選択される集約」の列に記載の通りです）。

| Instrumentの種別 | 選択される集約 |
| --- | --- |
| [Counter](../api/#counter) | [Sum Aggregation](#sum-aggregation) |
| [非同期Counter](../api/#非同期counter) | [Sum Aggregation](#sum-aggregation) |
| [UpDownCounter](../api/#updowncounter) | [Sum Aggregation](#sum-aggregation) |
| [非同期UpDownCounter](../api/#非同期updowncounter) | [Sum Aggregation](#sum-aggregation) |
| [Gauge](../api/#gauge) | [Last Value Aggregation](#last-value-aggregation) |
| [非同期Gauge](../api/#非同期gauge) | [Last Value Aggregation](#last-value-aggregation) |
| [Histogram](../api/#histogram) | [Explicit Bucket Histogram Aggregation](#explicit-bucket-histogram-aggregation)。提供されている場合は`ExplicitBucketBoundaries` [advisoryパラメータ](../api/#instrumentのadvisoryパラメータ)を伴います |

このAggregationには設定パラメータがありません。

#### Sum Aggregation

Sum Aggregationは、[Sum Metric Point](/works/otel-specs-ja/spec/metrics/data-model/#sums)のデータを収集するようSDKに伝えます。

集約の単調性はInstrumentの種別によって決まります。

| Instrumentの種別 | `SumType` |
| --- | --- |
| [Counter](../api/#counter) | Monotonic |
| [UpDownCounter](../api/#updowncounter) | Non-Monotonic |
| [Histogram](../api/#histogram) | Monotonic |
| [Gauge](../api/#gauge) | Non-Monotonic |
| [非同期Gauge](../api/#非同期gauge) | Non-Monotonic |
| [非同期Counter](../api/#非同期counter) | Monotonic |
| [非同期UpDownCounter](../api/#非同期updowncounter) | Non-Monotonic |

このAggregationには設定パラメータがありません。

このAggregationは、SDKに以下を収集するよう伝えます。

- `Measurement`値の算術和。

#### Last Value Aggregation

Last Value Aggregationは、[Gauge Metric Point](/works/otel-specs-ja/spec/metrics/data-model/#gauge)のデータを収集するようSDKに伝えます。

このAggregationには設定パラメータがありません。

このAggregationは、SDKに以下を収集するよう伝えます。

- 最後の`Measurement`。
- 最後の`Measurement`のタイムスタンプ。

#### Histogram Aggregations

すべてのhistogram Aggregationは、SDKに以下を収集するよう伝えます。

- 母集団における`Measurement`値の数。
- 母集団における`Measurement`値の算術和。これは、負の測定値を記録するInstrument（例えば`UpDownCounter`や`ObservableGauge`）とともに使われる場合はSHOULD NOT収集されるものとします。
- 母集団における（任意の）最小`Measurement`値。
- 母集団における（任意の）最大`Measurement`値。

##### Explicit Bucket Histogram Aggregation

Explicit Bucket Histogram Aggregationは、明示的な境界値の集合をヒストグラムのバケット分けに使って、[Histogram Metric Point](/works/otel-specs-ja/spec/metrics/data-model/#histogram)のデータを収集するようSDKに伝えます。

このAggregationは以下の設定パラメータに従います。

| キー | 値 | デフォルト値 | 説明 |
| --- | --- | --- | --- |
| Boundaries | double\[\] | [ 0, 5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000, 7500, 10000 ] | 増加する値の配列で、明示的なバケット境界値を表します。<br><br>デフォルト値は以下のバケットを表します（Prometheusクライアント、例えば[Java](https://github.com/prometheus/client_java/blob/6730f3e32199d6bf0e963b306ff69ef08ac5b178/simpleclient/src/main/java/io/prometheus/client/Histogram.java#L88)や[Go](https://github.com/prometheus/client_golang/blob/83d56b1144a0c2eb10d399e7abbae3333bebc463/prometheus/histogram.go#L68)のデフォルトバケットに大きく影響を受けています）：<br>(-&infin;, 0], (0, 5.0], (5.0, 10.0], (10.0, 25.0], (25.0, 50.0], (50.0, 75.0], (75.0, 100.0], (100.0, 250.0], (250.0, 500.0], (500.0, 750.0], (750.0, 1000.0], (1000.0, 2500.0], (2500.0, 5000.0], (5000.0, 7500.0], (7500.0, 10000.0], (10000.0, +&infin;)。SDKは、境界が明示的に提供されない場合、異なるものを使う十分な理由がない限り（例えば安定版SDKリリースにおける後方互換性の理由から）、デフォルト値をSHOULD使用するものとします。 |
| RecordMinMax | true, false | true | 最小値と最大値を記録するかどうか。 |

明示的なバケットは、その上限境界によって示されます。バケットは下限境界を含まず、上限境界を含みます（正の無限大の場合を除く）。測定値は、その値以上の境界を持つ最大番号のバケットに含まれると定義されます。

##### Base2 Exponential Bucket Histogram Aggregation

Base2 Exponential Histogram Aggregationは、底が2の指数関数式を使ってバケット境界を決定し、解像度を制御する整数の`scale`パラメータを使う[Exponential Histogram Metric Point](/works/otel-specs-ja/spec/metrics/data-model/#exponentialhistogram)のデータを収集するようSDKに伝えます。実装は、データに応じて必要なだけscaleを調整します。

このAggregationは以下の設定パラメータに従います。

| キー | 値 | デフォルト値 | 説明 |
| --- | --- | --- | --- |
| MaxSize | integer | 160 | 特別なゼロバケットを数えない、正・負それぞれの範囲におけるバケットの最大数。 |
| MaxScale | integer | 20 | 最大の`scale`係数。 |
| RecordMinMax | true, false | true | 最小値と最大値を記録するかどうか。 |

160バケットというデフォルト値は、1msから100sまでのロングテールなレイテンシー分布を5%未満の相対誤差でカバーできる高解像度ヒストグラムのデフォルトサポートを確立するために選ばれています。160は`10 * 2**K`に因数分解できるため、スケール`K`における最大のコントラストは比較的単純に導出できます。

| スケール | 10 * 2**K バケットでの最大データコントラスト |
| --- | --- |
| K+2 | 5.657 (2**(10/4)) |
| K+1 | 32 (2**(10/2)) |
| K | 1024 (2**10) |
| K-1 | 1048576 (2**20) |

以下の表は、160バケットに対する理想的なスケールが入力範囲の関数としてどのように計算されるかを示しています。

| 入力範囲 | コントラスト | 理想スケール | 底 | 相対誤差 |
| --- | --- | --- | --- | --- |
| 1ms - 4ms | 4 | 6 | 1.010889 | 0.542% |
| 1ms - 20ms | 20 | 5 | 1.021897 | 1.083% |
| 1ms - 1s | 10**3 | 4 | 1.044274 | 2.166% |
| 1ms - 100s | 10**5 | 3 | 1.090508 | 4.329% |
| 1μs - 10s | 10**7 | 2 | 1.189207 | 8.643% |

相対誤差は、バケット幅の半分をバケットの中点で割ったものとして計算されることに注意してください。これはすべてのバケットで同じです。[1, base)のバケットを使うと、`(bucketWidth / 2) / bucketMidpoint = ((base - 1) / 2) / ((base + 1) / 2) = (base - 1) / (base + 1)`となります。

このAggregationは「理想」スケールという概念を使います。理想スケールは以下のいずれかです。

1. `MaxScale`（設定パラメータを参照）。一般に、スケールが他に制約されない単一値のヒストグラムAggregationで使われます。
2. 正または負の範囲のいずれかで入力データの全範囲を表現するために必要なバケット数が最大数を超えない、最大のスケール値。

###### すべての正規値の処理

実装は、IEEE浮動小数点数値の正規範囲全体（すなわち+Inf、-Inf、NaN値を除くすべての値）を受け付けることがREQUIREDです。

実装は、非正規の値（すなわち+Inf、-Inf、NaN）を`sum`、`min`、`max`フィールドに組み込むべきではありません（SHOULD NOT）。これらの値は有効なバケットに対応しないためです。

実装は、非正規化数をゼロから離れる方向に最も近い正規値へ丸めてもかまいません（MAY）。

###### 最小・最大スケールのサポート

実装は、自動スケールパラメータが超えることのない、妥当な最小・最大スケールパラメータをMUST維持するものとします。最大スケールは`MaxScale`設定パラメータによって定義されます。

###### 単一の測定値に対する最大スケールの使用

ヒストグラムが正または負の範囲のいずれかに1つ以下の値しか含まない場合、実装は最大スケールをSHOULD使用するものとします。

###### 理想スケールの維持

実装は、最大サイズ（バケットの最大数）という制約の中で可能な限り最良の解像度を維持するために、必要に応じてヒストグラムのスケールをSHOULD調整するものとします。最良の解像度（最高のスケール）は、正または負の範囲のバケット数が最大サイズの半分を超え、スケールを1増やすことがサイズの制約上不可能になる場合に達成されます。

### 非同期コールバック内での観測

コールバック関数は、実行中のコールバックによって行われる、あるいは生成される観測が、収集を実行している特定の`MetricReader`にのみ適用されるように、その`MetricReader`のためにMUST呼び出されるものとします。

実装は、登録されたコールバックの外部での非同期Instrument APIの使用をSHOULD無視するものとします。

実装は、コールバックの無期限の実行を防ぐためにタイムアウトをSHOULD使用するものとします。

実装は、次の収集ラウンドを開始する前に、あるInstrumentに対するすべてのコールバックの実行をMUST完了するものとします。

実装は、成功したコールバックの中で観測されなかった、以前に観測された属性の集合について集約されたメトリックデータをSHOULD NOT生成するものとします。連続する収集にわたるメトリクスの永続性についての詳細は[MetricReader](#metricreader)を参照してください。

### 開始タイムスタンプ

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

タイムシリーズの開始タイムスタンプは、このタイムシリーズに対する測定値が記録され得た最初の瞬間を最もよく表すタイムスタンプです。

delta集約の場合、開始タイムスタンプは前回の収集インターバルのタイムスタンプと等しくなるか、そのInstrumentにとってこれが最初の収集インターバルである場合はInstrumentの作成時刻と等しくなるMUSTものとします。これは、あるInstrumentに対するdelta temporality集約を持つすべてのデータポイントが同じ開始タイムスタンプをMUST共有することを意味します。

累積タイムシリーズは、すべての収集インターバルに対して一貫した開始タイムスタンプをMUST使用するものとします。同期Instrumentについて、開始タイムスタンプはそのシリーズの最初の測定値の時刻であるべきです（SHOULD）。非同期Instrumentについて、開始タイムスタンプは以下であるべきです（SHOULD）。
  - 最初のシリーズの測定値が最初の収集インターバルで発生した場合は、そのInstrumentの作成時刻。
  - そうでない場合は、最初のシリーズの測定値より前の収集インターバルのタイムスタンプ。

### Cardinality limits

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

SDKは、カーディナリティ制限を設定できることをSHOULDサポートするものとします。属性の一意な組み合わせの数はカーディナリティと呼ばれます。あるメトリクスについて、カーディナリティ制限は、1回の収集サイクルで収集できる[メトリックポイント](/works/otel-specs-ja/spec/metrics/data-model/#metric-points)の数に対するハードリミットです。カーディナリティ制限の適用は、属性フィルタリングがある場合はその_後_にSHOULD行われるものとします。これにより、利用者は[View](#view)を使って不要な属性をフィルタリングし、カーディナリティ制限に達することを防げます。

#### 設定

あるAggregationのカーディナリティ制限は、以下の3つの方法のいずれかで定義されます。

1. Aggregationが作成される対象のInstrumentに一致する基準を持つ[View](#view)が、そのストリームに対して`aggregation_cardinality_limit`の値を定義している場合、その値をSHOULD使用するものとします。
2. 一致するViewがないが、`MetricReader`がAggregationの作成対象のInstrumentに基づいたデフォルトのカーディナリティ制限値を定義している場合、その値をSHOULD使用するものとします。
3. 前述のいずれの値も定義されていない場合、デフォルト値の2000をSHOULD使用するものとします。

#### Overflow attribute

オーバーフロー属性の集合が定義されており、これは`otel.metric.overflow`という単一の属性を含み、その（ブーリアン）値は`true`です。これは、制限のために独立して集約できなかった[Measurement](../api/#measurement)の合成集約を報告するために使われます。

SDKは、カーディナリティ制限に達する前にオーバーフロー属性の集合を持つAggregatorをMUST作成するものとし、正しいAggregatorを作成できなかった[Measurement](../api/#measurement)を集約するためにそれをMUST使用するものとします。SDKは、非オーバーフローの一意な属性集合の最大数が制限以下である場合にオーバーフローが発生しないことをMUST保証するものとします。

#### 同期Instrumentのカーディナリティ制限

累積temporalityを持つ同期Instrumentに対するAggregatorは、オーバーフローの開始前に観測されたすべての属性集合をエクスポートし続けることをMUST行うものとします。オーバーフロー前に観測されなかった属性集合に対応する[Measurement](../api/#measurement)は、（オーバーフロー属性のみによって記述される）単一のデータポイントに反映されます。

delta集約temporalityを持つ同期Instrumentに対するAggregatorは、規定されたカーディナリティ制限を維持するために、出力する属性集合の任意の部分集合を選んでもかまいません（MAY）。

集約temporalityにかかわらず、SDKは、すべての[Measurement](../api/#measurement)が、正しい属性集合に関連付けられたAggregatorか、オーバーフロー属性集合に関連付けられたAggregatorのいずれか、ちょうど1つのAggregatorに反映されることをMUST保証するものとします。

[Measurement](../api/#measurement)は、オーバーフロー中に二重にカウントされたり、破棄されたりすることはMUST NOTあるものとします。

#### 非同期Instrumentのカーディナリティ制限

非同期Instrumentに対するAggregatorは、temporalityにかかわらず、カーディナリティを制限する際にコールバック内で最初に観測された属性をSHOULD優先するものとします。

## Meter

異なるMeterは、[Instrumentの重複登録](#duplicate-instrument-registration)を検知する目的において、別個の名前空間としてMUST扱われるものとします。

**ステータス**: [Development](../../document-status/) - `Meter`は、[Meterの作成](#meterの作成)の際に計算された[MeterConfig](#meterconfig)に従ってMUST振る舞うものとします。`MeterProvider`が[MeterConfigurator](#meterconfigurator)の更新をサポートする場合、更新時に`Meter`は新しい`MeterConfig`に従って振る舞うようMUST更新されるものとします。

### MeterConfig

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

`MeterConfig`は、`Meter`の振る舞いのさまざまな設定可能な側面を定義します。これは以下のパラメータから構成されます。

* `enabled`: Meterが有効かどうかを示すブーリアン値。

  明示的に設定されていない場合、`enabled`パラメータはデフォルトで`true`であるべきです（SHOULD）（すなわち`Meter`はデフォルトで有効です）。

  `Meter`が無効化されている場合、それは[No-op Meter](/works/otel-specs-ja/spec/metrics/noop/#meter)と同等にMUST振る舞うものとします。

  `enabled`の値は、Instrumentが[Enabled](../api/#enabled)であるかどうかを解決するためにMUST使用されるものとします。詳細は[Instrument enabled](#instrument-enabled)を参照してください。

実装が、これらのパラメータへの変更を`Enabled`の呼び出し元に即座に反映させることを保証する必要はありません。しかし、変更は最終的にMUST反映されるものとします。

### Duplicate instrument registration

_重複したInstrumentの登録_は、同じMeterProviderの同一のMeterに対して、同じ[`name`](../api/#instrument名の構文)を持つ複数のInstrumentが作成されるが、[識別に関わるフィールド](../api/#instrument)が異なる場合に発生します。

これが発生した場合でも、利用者は重複したInstrumentで測定を行える必要があります。これは、たとえ[データモデルにおけるセマンティックエラー](/works/otel-specs-ja/spec/metrics/data-model/#opentelemetry-protocol-data-model-producer-recommendations)を引き起こすことになっても、Meterが機能するInstrumentをMUST返すものとし、そのInstrumentはデータをエクスポートできることが期待されることを意味します。

さらに、利用者はこのエラーについて知らされる必要があります。したがって、重複したInstrumentの登録が発生し、それがViewで修正されない場合、警告がSHOULD発せられるものとします。発せられる警告は、可能であれば競合を解決する方法についての情報をSHOULD含むものとします。

1. 潜在的な競合が複数の`description`プロパティに関わる場合、設定されたViewを通じて`description`を設定することで警告をSHOULD回避できるものとします。
2. 潜在的な競合が、サポートされているViewセレクター（例えば名前、Instrumentの種別）によって区別できるInstrumentに関わる場合、リネームするViewのレシピが警告にSHOULD含まれるものとします。
3. それ以外の場合（例えば複数の単位の使用）、SDKはデータをそのまま通過させ、両方の`Metric`オブジェクトを報告し、重複したInstrumentの登録を説明する一般的な警告をSHOULD発するものとします。

重複したInstrumentの登録の結果として同一または異なるInstrumentインスタンスが返されるかどうか、あるいはどのような条件下でそうなるかは規定されていません。Instrumentに適用される_同一_という用語は、すべての[識別に関わるフィールド](../api/#instrument)が等しいインスタンスを表します。Instrumentに適用される_別個_という用語は、少なくとも1つのフィールドの値が異なるインスタンスを表します。

[データモデルからの推奨事項](/works/otel-specs-ja/spec/metrics/data-model/#opentelemetry-protocol-data-model-producer-recommendations)に対応するため、SDKはエクスポートパイプラインにおいて[同一のInstrument](../api/#instrument)からのデータをMUST集約するものとします。

#### 名前の競合

Instrumentの[`name`](../api/#instrument名の構文)は、大文字小文字を区別しないと定義されています。SDKがこの`name`を表現するために大文字小文字を区別するエンコーディングを使う場合、利用者が同じ`name`の複数の大文字小文字の形を渡すと、重複したInstrumentの登録が発生します。これが発生した場合、Meterは最初に見られたInstrument名を使ったInstrumentをMUST返すものとし、上述の通り適切なエラーをログに記録するものとします。

例えば、利用者が`requestCount`という名前のInstrumentを作成し、その後同じ`Meter`に対して`RequestCount`という名前のInstrumentを作成する別のリクエストを行った場合、両方の場合において`requestCount`という名前のInstrumentが利用者に返される必要があり、2番目のリクエストに対してログメッセージが発せられる必要があります。

### Instrumentの名前

Meterがinstrumentを作成する際、[Instrument名の構文](../api/#instrument名の構文)に準拠しているかをInstrumentの名前をSHOULD検証するものとします。

Instrumentの名前がこの構文に準拠しない場合、Meterは無効な名前について利用者に通知するエラーをSHOULD発するものとします。有効なInstrumentも返されるかどうかは規定されていません。

### Instrumentの単位

Meterがinstrumentを作成する際、Instrumentの単位を検証すべきではありません（SHOULD NOT）。単位が提供されない場合、あるいは単位がnullの場合、Meterはそれを空の単位文字列と同じようにMUST扱うものとします。

### Instrumentの説明

Meterがinstrumentを作成する際、Instrumentの説明を検証すべきではありません（SHOULD NOT）。説明が提供されない場合、あるいは説明がnullの場合、Meterはそれを空の説明文字列と同じようにMUST扱うものとします。

### Instrument advisory parameters

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

Meterがinstrumentを作成する際、Instrument advisoryパラメータをSHOULD検証するものとします。advisoryパラメータが有効でない場合、Meterは利用者に通知するエラーをSHOULD発し、そのパラメータが提供されなかったかのように処理を続けるものとします。

異なるadvisoryパラメータを持つ複数の[同一のInstrument](../api/#instrument)が作成された場合、Meterは最初に見られたadvisoryパラメータを使ったInstrumentをMUST返すものとし、[重複したInstrumentの登録](#duplicate-instrument-registration)に記述された通り適切なエラーをログに記録するものとします。

[View](#view)とadvisoryパラメータの両方が[ストリーム設定](#ストリーム設定)の同じ側面を指定している場合、Viewで定義された設定はadvisoryパラメータよりMUST優先されるものとします。

#### Instrument advisoryパラメータ: `ExplicitBucketBoundaries`

このadvisoryパラメータは、[Explicit Bucket Histogram](#explicit-bucket-histogram-aggregation)集約が使われる場合に適用されます。

一致するViewがExplicit Bucket Histogram集約を（バケット境界の有無にかかわらず）指定している場合、`ExplicitBucketBoundaries` advisoryパラメータは無視されます。

一致するViewがない場合、または一致するViewが[デフォルトの集約](#default-aggregation)を選択している場合、`ExplicitBucketBoundaries` advisoryパラメータがMUST使用されるものとします。どちらも提供されない場合は、デフォルトのバケット境界が適用されます。

#### Instrument advisoryパラメータ: `Attributes`

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

このadvisoryパラメータは、すべての集約に適用されます。

`Attributes`（[属性キー](https://opentelemetry.io/docs/specs/otel/common/#attribute)のリスト）は、メトリックストリームを生成するために集約される測定値に対して推奨される属性キーの集合を指定します。

利用者がView経由で属性キーを提供している場合、それらのキーが優先されます。Viewが設定されていない場合、または一致するViewが属性キーを指定していない場合、advisoryパラメータが使われるべきです。どちらも提供されない場合、すべての属性が保持されなければなりません。

### Instrument enabled

同期Instrumentの[`Enabled`](../api/#enabled)は、以下のいずれかの場合に`false`をMUST返すものとします。

- **ステータス**: [Development](../../document-status/) - そのInstrumentを作成した`Meter`の[MeterConfig](#meterconfig)が`enabled=false`パラメータを持つ場合。
- そのInstrumentに対する[解決済みのView](#measurementの処理)すべてが[Drop Aggregation](#drop-aggregation)で設定されている場合。

それ以外の場合は`true`をSHOULD返すものとします。追加の最適化や機能をサポートするために`false`を返してもかまいません（MAY）。

注: 利用者が設定を変更しない場合、デフォルトで`MeterConfig.enabled=true`であり、Instrumentは一致するViewがない場合デフォルトの集約を使うため、`Enabled`は`true`を返します。

### Instrument bind

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

束縛済みInstrumentは、各測定値に対して事前に束縛された[Attributes](https://opentelemetry.io/docs/specs/otel/common/#attribute)を伴って、対応する束縛されていない記録操作を呼び出すのと同一にMUST振る舞うものとします。

[属性の処理](#measurementの処理)と[カーディナリティ制限](#cardinality-limits)の評価は、bind時にMUST実行されるものとします。`Bind`への各呼び出しは、その時点でのカーディナリティの状態に対して独立にMUST評価されるものとします。結果として、同一の属性を持つ`Bind`への別々の呼び出しが、各呼び出し時点でのカーディナリティの状態に基づいて異なるAggregator（例えば片方は具体的なシリーズへ、もう片方は[オーバーフローシリーズ](#overflow-attribute)へ）に解決されることがあります。解決されたAggregatorは固定でMUSTあるものとし、収集サイクルをまたいで変化してはなりません（MUST NOT）。

束縛済みInstrumentで記録された測定値は、[Exemplar](#exemplar)サンプリングの対象にMUSTなるものとします。各記録に関連付けられた[Context](https://opentelemetry.io/docs/specs/otel/context/)（暗黙的か明示的かにかかわらず）は、exemplarの[TraceBased](#tracebased)フィルタリングにMUST使用されるものとし、[ExemplarReservoir](#exemplarreservoir)のofferメソッドにMUST渡されるものとします。

SDKは、束縛済みInstrument上での属性を伴わない記録が、記録ごとのマップ検索を回避することをMUST保証するものとします。

## 属性の制限

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

Metricsに属する属性は、現時点では[属性制限の共通ルール](https://opentelemetry.io/docs/specs/otel/common/#attribute-limits)の対象外です。属性の切り詰めや削除は、メトリックタイムシリーズの識別に影響を与える可能性があり、この論点はさらなる分析を必要とします。

## Exemplar

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

Exemplarは、集約されたデータに対する例示データポイントです。これらは、そうでなければ一般的な集約に対して、具体的なコンテキストを提供します。Exemplarは、集約されたメトリックデータと、測定値が記録された元のAPI呼び出しとの間の相関を可能にします。Exemplarは、`Span`からも導出できるメトリクスに限らず、任意のメトリクスにおけるトレース・メトリクス間の相関のために機能します。Exemplarは、Instrumentの種別（非同期Instrumentを含む）にかかわらず、集約中に（例えばView設定によって）削除される属性も保持します。

[Exemplar](/works/otel-specs-ja/spec/metrics/data-model/#exemplars)は、記録された[Measurement](../api/#measurement)であり、以下の情報を公開します。

- API呼び出しによって記録された`Measurement`の`value`。
- `Measurement`を記録するためにAPI呼び出しが行われた`time`。
- メトリックデータポイントにまだ含まれていない、`Measurement`に関連付けられた[Attributes](https://opentelemetry.io/docs/specs/otel/common/#attribute)の集合。
- 同期Instrumentについては、API呼び出し時点における`Measurement`の、アクティブな[Context内のSpan](/works/otel-specs-ja/spec/trace/api/#コンテキストからの親スパンの決定)に関連付けられた[TraceIdとSpanId](/works/otel-specs-ja/spec/trace/api/#traceidとspanidの取得)。

例えば、利用者が属性`X`と`Y`を保持するように`View`を設定しているが、以下のように測定値を記録した場合を考えます。

```javascript
const span = tracer.startSpan('makeRequest');
api.context.with(api.trace.setSpan(api.context.active(), span), () => {
  // Record a measurement.
  cache_miss_counter.add(1, {"X": "x-value", "Y": "y-value", "Z": "z-value"});
  ...
  span.end();
})
```

その場合、OTLPにおけるexemplarの出力は以下から構成されます。

- `value`は1。
- `add`メソッドが呼び出された`time`。
- 結果として得られるメトリックポイントに保持されない`{"Z": "z-value"}`という`Attributes`。
- `makeRequest`スパンのトレースID・スパンID。

一方、counterのメトリックデータポイントは属性`X`と`Y`を保持します。

Metric SDKは、`ExemplarFilter`と`ExemplarReservoir`のフックを通じて測定値から`Exemplar`をサンプリングする仕組みをMUST提供するものとします。

`Exemplar`サンプリングはデフォルトで有効になっているべきです（SHOULD）。`Exemplar`サンプリングが無効な場合、SDKはexemplarサンプリングに関連するオーバーヘッドを持ってはなりません（MUST NOT）。

Metric SDKは、exemplarサンプリングがメトリック集約の設定を活用できることをMUST許容するものとします。例えば、ヒストグラムのExemplarサンプリングはバケット境界を活用できるべきです。

Metric SDKは、Exemplarサンプリングのための設定を、特に以下についてSHOULD提供するものとします。

- `ExemplarFilter`: どの測定値がexemplarになれるかをフィルタリングする。
- `ExemplarReservoir`: exemplarの格納とサンプリング。

### ExemplarFilter

`ExemplarFilter`の設定は、利用者が組み込みのExemplarFilterのいずれかを選択できることをMUST許容するものとします。`ExemplarFilter`はどの測定値が`Exemplar`になる_資格がある_かを決定しますが、実際に測定値がexemplarになり格納されるかどうかの最終的な決定は`ExemplarReservoir`が行います。

ExemplarFilterは、SDKにおける`MeterProvider`の設定パラメータであるべきです（SHOULD）。デフォルト値は`TraceBased`であるべきです（SHOULD）。フィルタの設定は[環境変数の仕様](/works/otel-specs-ja/spec/configuration/sdk-environment-variables/#exemplar)にSHOULD従うものとします。

OpenTelemetry SDKは以下のフィルタをMUSTサポートするものとします。

- [AlwaysOn](#alwayson)
- [AlwaysOff](#alwaysoff)
- [TraceBased](#tracebased)

#### AlwaysOn

すべての測定値をExemplarになる資格があるとするExemplarFilterです。

#### AlwaysOff

いかなる測定値もExemplarになる資格がないとするExemplarFilterです。このExemplarFilterを使うことは、Exemplar機能を無効化することと同等です。

#### TraceBased

サンプリングされた親スパンのコンテキストで記録された測定値をExemplarになる資格があるとするExemplarFilterです。

### ExemplarReservoir

`ExemplarReservoir`インターフェースは、レザバーに測定値を提供するメソッドと、蓄積されたExemplarを収集する別のメソッドをMUST提供するものとします。

新しい`ExemplarReservoir`は、集約とView設定によって決定される、既知のタイムシリーズごとにMUST作成されるものとします。このデータポイントとその識別に関わる属性の集合は、関連するタイムシリーズポイントと呼ばれます。

「offer」メソッドは、以下を含む測定値をSHOULD受け付けるものとします。

- 測定値の`value`。
- 測定値の`Attributes`の完全な集合。
- 測定値の[Context](https://opentelemetry.io/docs/specs/otel/context/)。これは[Baggage](https://opentelemetry.io/docs/specs/otel/baggage/api/)と現在アクティブな[Span](/works/otel-specs-ja/spec/trace/api/#span)を含みます。
- 測定が行われたことを最もよく表す`timestamp`。

「offer」メソッドは、完全なコンテキストを記録する必要なく、関連するトレースとスパンの情報を取得できるべきです（SHOULD）。つまり、現在のスパンコンテキストとbaggageは、この時点で検査できます。

「offer」メソッドは、与えられたすべての測定値を格納する必要はなく、`ExemplarFilter`を超えて追加でサンプリングしてもかまいません（MAY）。

「offer」メソッドは、レザバーが関連付けられているタイムシリーズから外れたフィルタリング済みの`Attributes`の部分集合を受け付けてもかまいません（MAY）。これはAPIに明確にドキュメント化される必要があり（MUST）、レザバーが実施する追加のサンプリングが「offer」メソッド内の測定値からすべての属性にアクセスできるように、レザバーはそのタイムシリーズポイントに関連付けられた`Attributes`を構築時に与えられるMUSTものとします。SDKの作者は、この選択肢が自分たちの実装に最も適しているかどうかをベンチマークすることが推奨されます。

「collect」メソッドは、蓄積された`Exemplar`をMUST返すものとします。Exemplarは、それが記録されるメトリックポイントの`AggregationTemporality`に従うことが期待されます。つまり、あるメトリックデータポイントに対して報告されるExemplarは、そのポイントの開始・終了タイムスタンプの範囲内で発生したものであるべきです（SHOULD）。SDKは、「collect」がdelta temporality集約の収集のために内部ストレージをリセットするべきかどうか、あるいはより最適な実装を使うべきかどうかを自由に決められます。

`Exemplar`は、集約やView設定によって関連するタイムシリーズに対して保持されない、測定値の中で利用可能な属性をMUST保持するものとします。`Exemplar`上の属性と、その関連するメトリックデータポイント上で利用可能な属性を結合すると、元のサンプル測定値からの属性の完全な集合が得られるはずです。

`ExemplarReservoir`は、exemplarをサンプリングする際にメモリ割り当てをSHOULD避けるものとします。

### Exemplarのデフォルト

SDKは、2種類の組み込みexemplarレザバーをMUST含むものとします。

1. `SimpleFixedSizeExemplarReservoir`
2. `AlignedHistogramBucketExemplarReservoir`

デフォルトでは、

- 2個より多いバケットを持つexplicit bucket histogram集約は、`AlignedHistogramBucketExemplarReservoir`をSHOULD使用するものとします。
- Base2 Exponential Histogram Aggregationは、集約に設定された最大バケット数と20のうち小さい方（例えば`min(20, max_buckets)`）と等しいレザバーを持つ`SimpleFixedSizeExemplarReservoir`をSHOULD使用するものとします。
- 他のすべての集約は`SimpleFixedSizeExemplarReservoir`をSHOULD使用するものとします。

Exemplarのデフォルトレザバーは、[マイナーバージョンの増加](/works/otel-specs-ja/spec/versioning-and-stability/#マイナーバージョンの増加)で変更されてもかまいません（MAY）。返されるexemplarの形や統計的性質については何の保証もありません。

#### SimpleFixedSizeExemplarReservoir

このレザバーは、これまでに見た測定値の数に基づいて、提供された測定値をサンプリングすべきかどうかを決定する、均一に重み付けされたサンプリングアルゴリズムをMUST使用するものとします。例えば、[単純なレザバーサンプリングアルゴリズム](https://en.wikipedia.org/wiki/Reservoir_sampling)を使えます。

  ```
  if num_measurements_seen < num_buckets then
    bucket = num_measurements_seen
  else
    bucket = random_integer(0, num_measurements_seen)
  end
  if bucket < num_buckets then
    reservoir[bucket] = measurement
  end
  num_measurements_seen += 1
  ```

サンプリング計算のうち状態を持つ部分は、収集サイクルごとにSHOULDリセットされるものとします。上記の例では、これは`num_measurements_seen`のカウントがレザバーが収集されるたびにリセットされることを意味します。

このExemplarレザバーは、レザバーのサイズに対する設定パラメータを取ってもかまいません（MAY）。サイズの設定が提供されない場合、デフォルトサイズは、競合を減らすために、並行して実行可能なスレッド数（例えばCPU数）であってもかまいません（MAY）。それ以外の場合、デフォルトサイズ`1`がSHOULD使用されるものとします。

#### AlignedHistogramBucketExemplarReservoir

このExemplarレザバーは、Histogramの設定である設定パラメータをMUST取るものとします。この実装は、ヒストグラムバケット内に収まる測定値を最大1つMUST格納するものとし、バケットがこれまでに見た測定値の数に基づいて、提供された測定値をサンプリングすべきかどうかを決定する均一に重み付けされたサンプリングアルゴリズムをSHOULD使用するものとします。あるいは、実装は代わりにヒストグラムバケット内に収まる最後に見た測定値を保持してもかまいません（MAY）。

レザバーは、以下のような単純なアルゴリズムと同等の方法で測定値を受け付けます。

  ```
  bucket = find_histogram_bucket(measurement)
  num_measurements_seen_bucket = num_measurements_seen[bucket]
  if random_integer(0, num_measurements_seen_bucket) == 0 then
    reservoir[bucket] = measurement
  end
  num_measurements_seen[bucket] += 1

  def find_histogram_bucket(measurement):
    for boundary, idx in bucket_boundaries do
      if value <= boundary then
        return idx
      end
    end
    return boundaries.length
  ```

このExemplarレザバーは、レザバーが使うバケット境界に対する設定パラメータを取ってもかまいません（MAY）。レザバーのサイズは常にバケット境界の数に1を加えたものです。この設定パラメータは、[Explicit Bucket Histogram Aggregation](#explicit-bucket-histogram-aggregation)にバケット境界を指定する場合と同じ形式をSHOULD持つものとします。

### カスタムExemplarReservoir

SDKは、SDKの利用者が自分自身のExemplarReservoir実装を提供できる仕組みをMUST提供するものとします。この拡張は、メトリックの[View](#view)に対して設定可能でMUSTあるものとしますが、個々のレザバーはメトリック・タイムシリーズごとにMUST依然としてインスタンス化されるものとします（[ExemplarReservoir - 2番目の段落](#exemplarreservoir)を参照）。

## MetricReader

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

`MetricReader`は、OpenTelemetry Metrics SDKの共通の設定可能な側面を提供し、以下の能力を決定するSDK実装オブジェクトです。

* 要求に応じてSDKと登録済みの[MetricProducer](#metricproducer)からメトリクスを収集する。
* SDKからの[ForceFlush](#forceflush)と[Shutdown](#shutdown)の信号を処理する。

SDKを設定する際に`MetricReader`を構築するために、少なくとも以下がSHOULD提供されるものとします。

* 使用する`exporter`。これは`MetricExporter`のインスタンスです。
* デフォルトの出力`aggregation`（任意）。これはInstrument種別の関数です。この関数は`exporter`から取得されるべきです（SHOULD）。設定されていない場合、[デフォルトの集約](#default-aggregation)がSHOULD使用されるものとします。
* 出力`temporality`（任意）。これはInstrument種別の関数です。この関数は`exporter`から取得されるべきです（SHOULD）。設定されていない場合、Cumulative temporalityがSHOULD使用されるものとします。
* 使用するデフォルトの集約[カーディナリティ制限](#cardinality-limits)（任意）。これはInstrument種別の関数です。設定されていない場合、デフォルト値の2000がSHOULD使用されるものとします。
* **ステータス**: [Development](../../document-status/) - `MetricReader#Collect`の間にメトリクスと属性に適用する[MetricFilter](#metricfilter)。
* メトリクスを収集する対象として、SDKからのメトリクスに加えて、0個以上の[MetricProducer](#metricproducer)（任意）。

**ステータス**: [Development](../../document-status/) - `MetricReader`は、`Produce`操作を呼び出す際に、[MetricFilter](#metricfilter)をSDKまたは登録された[MetricProducer](#metricproducer)にSHOULD提供するものとします。

[MetricReader.Collect](#collect)メソッドは、汎用の`MetricExporter`インスタンスが明示的に収集を開始することを許容します。これは一般にpullベースのメトリクス収集で使われます。`MetricReader`の一般的な実装である[periodic exporting MetricReader](#periodic-exporting-metricreader)は、通常pushベースのメトリクス収集で使われるためにSHOULD提供されるものとします。

`MetricReader`は、OpenTelemetryの[Instrument](../api/#instrument)からのデータポイントが、Instrument種別ごとに設定された集約temporalityで出力されることをMUST保証するものとします。Cumulative集約temporalityを持つ同期Instrumentについて、これは[DeltaからCumulativeへの変換](/works/otel-specs-ja/spec/metrics/supplementary-guidelines/#synchronous-example-cumulative-aggregation-temporality)集約temporalityを意味します。Delta temporalityを持つ非同期Instrumentについて、これは[CumulativeからDeltaへの変換](/works/otel-specs-ja/spec/metrics/supplementary-guidelines/#asynchronous-example-delta-temporality)集約temporalityを意味します。

`MetricReader`は、非SDKの[MetricProducer](#metricproducer)からのデータポイントが設定された集約temporalityで出力されることを保証する必要はありません。これらのデータポイントはOpenTelemetryのInstrumentを使って収集されたものではないためです。

`MetricReader`のInstrument種別の関数としての`temporality`の選択は、収集をまたいだメトリックデータポイントの永続性に影響します。Cumulative集約temporalityを持つ同期Instrumentについて、新しい測定値が記録されたかどうかにかかわらず、[MetricReader.Collect](#collect)は以前の収集で公開されたデータポイントをMUST受け取るものとします。Delta集約temporalityを持つ同期Instrumentについて、[MetricReader.Collect](#collect)は前回の収集以降に記録された測定値を持つデータポイントのみをMUST受け取るものとします。Delta集約またはCumulative集約temporalityを持つ非同期Instrumentについて、[MetricReader.Collect](#collect)は前回の収集以降に記録された測定値を持つデータポイントのみをMUST受け取るものとします。これらのルールは、[ポイントの種別](/works/otel-specs-ja/spec/metrics/data-model/#point-kinds)に集約temporalityフィールドを含むメトリクスだけでなく、すべてのメトリクスに適用されます。

`MetricReader`のInstrument種別の関数としての`temporality`の選択は、[MetricReader.Collect](#collect)によって受け取られるメトリクスデータポイントの開始タイムスタンプ（すなわち`StartTimeUnixNano`）にも影響します。Cumulative集約temporalityを持つInstrumentについて、[MetricReader.Collect](#collect)への連続する呼び出しによって受け取られる連続するデータポイントは、同じ開始タイムスタンプをMUST繰り返すものとします（例えば`(T0, T1], (T0, T2], (T0, T3]`）。Delta集約temporalityを持つInstrumentについて、[MetricReader.Collect](#collect)への連続する呼び出しによって受け取られる連続するデータポイントは、開始タイムスタンプをMUST進めるものとします（例えば`(T0, T1], (T1, T2], (T2, T3]`）。終了タイムスタンプ（すなわち`TimeUnixNano`）は、メトリックデータポイントが有効になった時刻、つまり[MetricReader.Collect](#collect)が呼び出された時刻と常に等しくなければなりません（MUST）。これらのルールは、[ポイントの種別](/works/otel-specs-ja/spec/metrics/data-model/#point-kinds)に集約temporalityフィールドを含むメトリクスだけでなく、すべてのメトリクスに適用されます。詳細は[データモデルのtemporality](/works/otel-specs-ja/spec/metrics/data-model/#temporality)を参照してください。

SDKは、同じ`MeterProvider`に複数の`MetricReader`インスタンスが登録されることをMUSTサポートするものとし、あるMetricReaderインスタンスに対する[MetricReader.Collect](#collect)の呼び出しは、他のMetricReaderインスタンスに副作用を及ぼすべきではありません（SHOULD NOT）。例えば、あるMetricReaderインスタンスが[deltaのtemporality](/works/otel-specs-ja/spec/metrics/data-model/#temporality)を持つメトリックデータポイントを受け取っている場合、SDKはこの特定のMetricReaderインスタンスに対して**のみ**時間範囲を更新することが期待されます（例えば(T<sub>n</sub>, T<sub>n+1</sub>]から(T<sub>n+1</sub>, T<sub>n+2</sub>]へ）。

SDKは、`MetricReader`インスタンスを複数の`MeterProvider`インスタンスに登録することをMUST NOT許容するものとします。

```text
+-----------------+            +--------------+
|                 | Metrics... |              |
| In-memory state +------------> MetricReader |
|                 |            |              |
+-----------------+            +--------------+

+-----------------+            +--------------+
|                 | Metrics... |              |
| In-memory state +------------> MetricReader |
|                 |            |              |
+-----------------+            +--------------+
```

SDKは、`MetricReader`が[MeterProvider.ForceFlush](#forceflush)と[MeterProvider.Shutdown](#shutdown)に応答できるようにする方法をSHOULD提供するものとします。[OpenTelemetry SDKの作者](/works/otel-specs-ja/spec/overview/#sdk)は、例えば`OnForceFlush`や`OnShutdown`コールバック関数として、言語にとってイディオマティックなアプローチを決めてもかまいません（MAY）。

### MetricReaderの操作

#### Collect

SDKと登録済みの[MetricProducer](#metricproducer)からメトリクスを収集します。[非同期SDK Instrument](../api/#非同期instrument-api)が関わっている場合、そのコールバック関数がトリガーされます。

`Collect`は、呼び出し元に成功、失敗、タイムアウトのいずれであったかを知らせる手段をSHOULD提供するものとします。`Collect`操作が一部のInstrumentで失敗またはタイムアウトした場合、SDKは正常に収集された結果と失敗理由のリストを呼び出し元に返してもかまいません（MAY）。

`Collect`には必須のパラメータはありませんが、[OpenTelemetry SDKの作者](/works/otel-specs-ja/spec/overview/#sdk)はパラメータ（例えばコールバック、フィルタ、タイムアウト）を追加してもかまいません（MAY）。[OpenTelemetry SDKの作者](/works/otel-specs-ja/spec/overview/#sdk)は返り値の型を選んでも、何も返さなくてもかまいません（MAY）。

`Collect`は、登録済みの[MetricProducer](#metricproducer)に対して[Produce](#produce-batch)をSHOULD呼び出すものとします。`Produce`からのメトリックポイントのバッチが[Resource](/works/otel-specs-ja/spec/resource/sdk/)情報を含む場合、`Collect`は、代わりにMeterProviderインスタンスを構築する際に提供された`Resource`でMetricProducerからの`Resource`を置き換えてもかまいません（MAY）。

注: `MetricReader.Collect`の実装はSDKによって提供されることが期待されるため、可能であれば利用者が誤ってそれを上書きしてしまうことを防ぐことがRECOMMENDEDです（例えばC++やJavaにおける`final`、C#における`sealed`）。

#### Shutdown

このメソッドは、`MetricReader`が必要なクリーンアップを行うための手段を提供します。

`Shutdown`は、`MetricReader`インスタンスごとにMUST一度だけ呼び出されるものとします。`Shutdown`の呼び出し後、`Collect`へのその後の呼び出しは許可されません。SDKは、可能であればこれらの呼び出しに対して何らかの失敗をSHOULD返すものとします。

`Shutdown`は、呼び出し元に成功、失敗、タイムアウトのいずれであったかを知らせる手段をSHOULD提供するものとします。

`Shutdown`は、何らかのタイムアウト内に完了または中断すべきです（SHOULD）。`Shutdown`は、ブロッキングAPIとして実装されても、コールバックやイベントを通じて呼び出し元に通知する非同期APIとして実装されてもかまいません（MAY）。[OpenTelemetry SDKの作者](/works/otel-specs-ja/spec/overview/#sdk)は、シャットダウンのタイムアウトを設定可能にするかどうかを決めてもかまいません（MAY）。

### Periodic exporting MetricReader

これは、利用者が設定可能な時間インターバルに基づいてメトリクスを収集し、設定された[Push Metric Exporter](#push-metric-exporter)にメトリクスを渡す`MetricReader`の実装です。

設定可能なパラメータ:

* `exportIntervalMillis` - 連続する2回の収集の間の時間インターバル（ミリ秒）。デフォルト値は60000（ミリ秒）です。
* `exportTimeoutMillis` - エクスポートがキャンセルされるまでにどのくらいの時間実行できるか。デフォルト値は30000（ミリ秒）です。
* **ステータス**: [Development](../../document-status/) - `maxExportBatchSize` - 1回のエクスポートに提供されるバッチ内のメトリックデータポイントの最大数。

**ステータス**: [Development](../../document-status/) - `maxExportBatchSize`が設定されている場合、リーダーは、メトリックデータポイントのバッチをより小さなバッチに分割することによって、`Export`に提供されるバッチが`maxExportBatchSize`を超えないことをMUST保証するものとします。最初のメトリックデータのバッチは、同じメトリクスに属するデータポイントが異なるバッチに分割されることになっても、できるだけ多くの`maxExportBatchSize`サイズの「フル」バッチにMUST分割されるものとします。リーダーは、メトリックポイントが順序通りに送信されるように、単一の`Collect()`からのすべてのメトリックデータポイントが、その後の`Collect()`からのメトリックデータポイントより前に`Export`に提供されることをMUST保証するものとします。リーダーは、異なる`Collect()`呼び出しからのメトリクスを`Export`に提供する同じバッチに結合してはなりません（MUST NOT）。

リーダーは、`MetricExporter`の`Export`への呼び出しが並行して呼び出されないことを保証するためにMUST同期するものとします。

periodic exporting MetricReaderの実装の1つは、`MetricReader`を継承し、要求された`exportIntervalMillis`で継承された`Collect()`メソッドを呼び出すバックグラウンドタスクを開始することです。リーダーの`Collect()`メソッドは、他の呼び出し元によっても呼び出される場合があります。例えば、

* 利用者がpushエクスポーターと30秒のインターバルでperiodic exporting MetricReaderを設定します。
* 最初の30秒のインターバルで、バックグラウンドタスクが`Collect()`を呼び出し、メトリクスをpushエクスポーターに渡します。
* 15秒後、利用者がこのリーダーだけについてメトリクスをフラッシュすることを決めます。彼らは`Collect()`を呼び出し、メトリクスをpushエクスポーターに渡します。
* さらに15秒後（2回目の30秒インターバルの終わり）、バックグラウンドタスクが`Collect()`を呼び出し、メトリクスをpushエクスポーターに渡します。

#### ForceFlush

このメソッドは、periodic exporting MetricReaderが、メトリクスの収集と送信のためにできる限りのことを行える手段を提供します。

`ForceFlush`は、メトリクスを収集し、必要であればバッチに分割し、各バッチに対して[`Export(batch)`](#exportbatch)を呼び出し、設定された[Push Metric Exporter](#push-metric-exporter)に対して[`ForceFlush()`](#forceflush-2)をSHOULD呼び出すものとします。タイムアウトが既に切れている場合、`ForceFlush`は[`Export(batch)`](#exportbatch)の呼び出しをスキップしてもかまいません（MAY）が、タイムアウトが過ぎていても設定された[Push Metric Exporter](#push-metric-exporter)に対する[`ForceFlush()`](#forceflush-2)の呼び出しはSHOULD行うものとします。

`ForceFlush`は、呼び出し元に成功、失敗、タイムアウトのいずれであったかを知らせる手段をSHOULD提供するものとします。`ForceFlush`は、エラー状態がある場合は何らかの**ERROR**ステータスを返すべきであり（SHOULD）、エラー状態がない場合は何らかの**NO ERROR**ステータスを返すべきです（SHOULD）。言語実装は、**ERROR**と**NO ERROR**をどのようにモデル化するかを決めてもかまいません（MAY）。

`ForceFlush`は、何らかのタイムアウト内に完了または中断すべきです（SHOULD）。`ForceFlush`は、ブロッキングAPIとして実装されても、コールバックやイベントを通じて呼び出し元に通知する非同期APIとして実装されてもかまいません（MAY）。

## MetricExporter

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

`MetricExporter`は、プロトコル固有のエクスポーターがOpenTelemetry SDKに組み込まれ、テレメトリーデータの送信をサポートできるようにするために実装しなければならないインターフェースをMUST定義するものとします。

Metric Exporterには常に_関連付けられた_MetricReaderがあります。OpenTelemetry Metric SDKで使われる`aggregation`と`temporality`のプロパティは、関連付けられたMetricReaderを通じてMetric Exporterを登録する際に決定されます。OpenTelemetryの言語実装は、Exporterが使う[MetricReader](#metricreader)を自動的に設定することをサポートしてもかまいません（MAY）。

このインターフェースの目標は、プロトコル依存のテレメトリーエクスポーターの実装負荷を最小化することです。プロトコルエクスポーターは、主に単純なテレメトリーデータのエンコーダーおよび送信者であることが期待されます。

Metric Exporterは[集約されたメトリクスデータ](/works/otel-specs-ja/spec/metrics/data-model/#timeseries-model)にアクセスできます。Metric Exporterは、この状況がMetricReaderの設定変更によって修正できるため、サポートされていないAggregationやAggregation Temporalityを持つ`MetricReader`が出力するデータについてエラー状態をSHOULD報告するものとします。

[Push Metric Exporter](#push-metric-exporter)や[Pull Metric Exporter](#pull-metric-exporter)、あるいはそれらの混合が、あるMeterProviderに同時に複数設定され、各エクスポーターに対して1つの`MetricReader`を使うことがあります。異なるエクスポーターは異なるスケジュールで動作できます。例えば、

* Exporter Aは、1分ごとにデータを送信するpushエクスポーターです。
* Exporter Bは、5秒ごとにデータを送信するpushエクスポーターです。
* Exporter Cは、HTTP経由のスクレイパーに反応するpullエクスポーターです。
* Exporter Dは、名前付きパイプ経由の別のスクレイパーに反応するpullエクスポーターです。

### Push Metric Exporter

Push Metric Exporterは、対となる[MetricReader](#metricreader)から受け取ったメトリックデータを送信します。例をいくつか示します。

* 利用者が設定したスケジュールに基づいてデータを送信する（例えば1分ごと）。これは、エクスポーターを[periodic exporting MetricReader](#periodic-exporting-metricreader)と組み合わせることでMAY実現できます。
* 重大なエラーがあるときにデータを送信する。

以下の図は、`Push Metric Exporter`のSDK内の他のコンポーネントとの関係を示しています。

```text
+-----------------+            +---------------------------------+
|                 | Metrics... |                                 |
| In-memory state +------------> Periodic exporting MetricReader |
|                 |            |                                 |
+-----------------+            |    +-----------------------+    |
                               |    |                       |    |
                               |    | MetricExporter (push) +-------> Another process
                               |    |                       |    |
                               |    +-----------------------+    |
                               |                                 |
                               +---------------------------------+
```

#### インターフェース定義

Push Metric Exporterは以下の関数をMUSTサポートするものとします。

##### Export(batch)

[メトリックポイント](/works/otel-specs-ja/spec/metrics/data-model/#metric-points)のバッチをエクスポートします。この関数を実装するプロトコルエクスポーターは、一般に、データを宛先へシリアライズして送信することが期待されます。

SDKは、各`Metric Point`に関連付けられた[Meter](../api/#meter)情報（例えば名前、バージョンなど）を取得する方法をエクスポーターにMUST提供するものとします。

`Export`は、同じエクスポーターインスタンスに対する他の`Export`呼び出しと同時に呼び出されてはなりません。

`Export`は無期限にブロックしてはならず（MUST NOT）、タイムアウトしてエラー結果（Failure）を返すまでの妥当な上限がMUSTなければならないものとします。

エクスポーターに必要なリトライロジックは、エクスポーターの責務です。デフォルトのSDKはリトライロジックを実装すべきではありません（SHOULD NOT）。必要なロジックは、メトリクスが送信される特定のプロトコルとバックエンドに大きく依存する可能性が高いためです。

**パラメータ:**

`batch` - [メトリックポイント](/works/otel-specs-ja/spec/metrics/data-model/#metric-points)のバッチ。バッチの正確なデータ型は言語固有であり、通常は何らかのリストです。`Metric Point`の正確な型は言語固有であり、通常は高いパフォーマンスのために最適化されています。例をいくつか示します。

```text
       +--------+ +--------+     +--------+
Batch: | Metric | | Metric | ... | Metric |
       +---+----+ +--------+     +--------+
           |
           +--> name, unit, description, meter information, ...
           |
           |                  +-------------+ +-------------+     +-------------+
           +--> MetricPoints: | MetricPoint | | MetricPoint | ... | MetricPoint |
                              +-----+-------+ +-------------+     +-------------+
                                    |
                                    +--> timestamps, attributes, value (or buckets), exemplars, ...
```

詳細については、Metrics Data Model仕様の[メトリックポイント](/works/otel-specs-ja/spec/metrics/data-model/#metric-points)の節を参照してください。

注: 実装者は、[protoファイル](https://github.com/open-telemetry/opentelemetry-proto/blob/main/opentelemetry/proto/metrics/v1/metrics.proto)から生成されるデータ型を直接使うのではなく、それを_基にした_`Metric`データ型を[データモデル](/works/otel-specs-ja/spec/metrics/data-model/)を基に設計することが強く推奨されます（protoファイルから生成される型は後方互換性が保証されていないためです）。

返り値: `ExportResult`

`ExportResult`は以下のいずれかです。

* `Success` - バッチが正常にエクスポートされました。プロトコルエクスポーターにとって、これは通常、データが送信され宛先サーバーに配信されたことを意味します。
* `Failure` - エクスポートに失敗しました。バッチは破棄されなければなりません。例えば、バッチに不正なデータが含まれていてシリアライズできない場合に発生します。

注: この結果は、言語実装にとってイディオマティックであれば、非同期の仕組みやコールバックを介して返されてもかまいません。

##### ForceFlush

これは、`ForceFlush`の呼び出しより前にエクスポーターが受け取ったすべての`Metrics`のエクスポートが、可能な限り早く（できればこのメソッドから戻る前に）完了すべきであることを示すヒントです（SHOULD）。

`ForceFlush`は、呼び出し元に成功、失敗、タイムアウトのいずれであったかを知らせる手段をSHOULD提供するものとします。

`ForceFlush`は、絶対に必要な場合にのみ呼び出されるべきです（SHOULD）。例えば、一部のFaaSプロバイダーが、呼び出し後にエクスポーターが完了したメトリクスをエクスポートする前にプロセスを一時停止する可能性がある場合などです。

`ForceFlush`は、何らかのタイムアウト内に完了または中断すべきです（SHOULD）。`ForceFlush`は、ブロッキングAPIとして実装されても、コールバックやイベントを通じて呼び出し元に通知する非同期APIとして実装されてもかまいません。[OpenTelemetry SDKの作者](/works/otel-specs-ja/spec/overview/#sdk)は、フラッシュのタイムアウトを設定可能にするかどうかを決めてもかまいません（MAY）。

##### Shutdown

エクスポーターをシャットダウンします。SDKがシャットダウンされるときに呼び出されます。これは、エクスポーターが必要なクリーンアップを行う機会です。

Shutdownは、`MetricExporter`インスタンスごとにSHOULD一度だけ呼び出されるものとします。`Shutdown`の呼び出し後、`Export`へのその後の呼び出しは許可されず、Failure結果を返すべきです（SHOULD）。

`Shutdown`は無期限にブロックすべきではありません（SHOULD NOT）（例えばデータをフラッシュしようとして宛先が利用できない場合）。[OpenTelemetry SDKの作者](/works/otel-specs-ja/spec/overview/#sdk)は、シャットダウンのタイムアウトを設定可能にするかどうかを決めてもかまいません（MAY）。

### Pull Metric Exporter

Pull Metric Exporterは、メトリクスのスクレイパーに反応し、受動的にデータを報告します。このパターンは[Prometheus](https://prometheus.io/)によって広く採用されています。

自分自身のスケジュールでデータを送信できる[Push Metric Exporter](#push-metric-exporter)とは異なり、pullエクスポーターはスクレイパーから要求されたときにのみデータを送信でき、`ForceFlush`は意味を持ちません。

実装者は、自分の言語にとって最良のイディオマティックな設計を選んでもかまいません（MAY）。例えば、一貫性のために[Push Metric Exporterインターフェース](#push-metric-exporter)の設計を一般化してそれを使うことも、pullエクスポーターを[MetricReader](#metricreader)としてモデル化することも、まったく異なるpullエクスポーターインターフェースを設計することもできます。pullエクスポーターがMetricReaderとしてモデル化される場合、実装者は命名の混乱を避けるためにMetricExporterインターフェースをPushMetricExporterと名付けてもかまいません（MAY）。

以下の図は、`Pull Metric Exporter`がSDK内の他のコンポーネントとどのようにやり取りするようモデル化できるかの例を示しています。

* pullエクスポーターをMetricReaderとしてモデル化する

  ```text
  +-----------------+            +-----------------------------+
  |                 | Metrics... |                             |
  | In-memory state +------------> PrometheusExporter (pull)   +---> Another process (scraper)
  |                 |            | (modeled as a MetricReader) |
  +-----------------+            |                             |
                                 +-----------------------------+
  ```

* pushとpull両方のエクスポーターに同じMetricExporter設計を使う

  ```text
  +-----------------+            +-----------------------------+
  |                 | Metrics... |                             |
  | In-memory state +------------> Exporting MetricReader      |
  |                 |            |                             |
  +-----------------+            |  +-----------------------+  |
                                 |  |                       |  |
                                 |  | MetricExporter (pull) +------> Another process (scraper)
                                 |  |                       |  |
                                 |  +-----------------------+  |
                                 |                             |
                                 +-----------------------------+
  ```

## MetricProducer

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

`MetricProducer`は、サードパーティのメトリクスソースへのブリッジが実装しなければならないインターフェースを定義し、それによってOpenTelemetryの[MetricReader](#metricreader)に集約されたメトリックデータのソースとして組み込めるようにします。SDKのインメモリ状態は、便宜上`MetricProducer`インターフェースを実装してもかまいません（MAY）。

`MetricProducer`の実装は、生成されるメトリクスの`AggregationTemporality`に対する設定をSHOULD受け付けるものとします。SDKの作者は、deltaとcumulativeのtemporality間の変換を容易にするユーティリティライブラリを提供してもかまいません（MAY）。

```text
+-----------------+            +--------------+
|                 | Metrics... |              |
| In-memory state +------------> MetricReader |
|                 |            |              |
+-----------------+            |              |
                               |              |
+-----------------+            |              |
|                 | Metrics... |              |
| MetricProducer  +------------>              |
|                 |            |              |
+-----------------+            +--------------+
```

新しいOpenTelemetryのインテグレーションが追加される場合、APIが優先されるインテグレーションポイントです。`MetricProducer`は、事前処理済みのデータをブリッジするインテグレーションのためだけに意図されています。

### インターフェース定義

`MetricProducer`は以下の関数をMUSTサポートするものとします。

#### Produce batch

`Produce`は、MetricProducerから呼び出し元にメトリクスを提供します。`Produce`は、任意の`metricFilter`パラメータでフィルタリングされた[メトリックポイント](/works/otel-specs-ja/spec/metrics/data-model/#metric-points)のバッチをMUST返すものとします。実装は、可能な限り多くの性能向上（メモリ割り当て、内部的なメトリクス取得など）を得るために、できるだけ早くフィルタをSHOULD使用するものとします。

[メトリックポイント](/works/otel-specs-ja/spec/metrics/data-model/#metric-points)のバッチがリソース情報を含む場合、`Produce`はパラメータとしてリソースをSHOULD要求するものとします。`Produce`には他に必須のパラメータはありませんが、[OpenTelemetry SDKの作者](/works/otel-specs-ja/spec/overview/#sdk)は必須または任意のパラメータ（例えばタイムアウト）を追加してもかまいません（MAY）。

`Produce`は、呼び出し元に成功、失敗、タイムアウトのいずれであったかを知らせる手段をSHOULD提供するものとします。`Produce`操作が失敗した場合、`MetricProducer`は正常に収集された結果と失敗理由のリストを返してもかまいません（MAY）。

[メトリックポイント](/works/otel-specs-ja/spec/metrics/data-model/#metric-points)のバッチが[`InstrumentationScope`](https://opentelemetry.io/docs/specs/otel/common/instrumentation-scope/)情報を含められる場合、`Produce`は`MetricProducer`を識別する単一のInstrumentationScopeをSHOULD含むものとします。

**パラメータ:**

**ステータス**: [Development](../../document-status/) `metricFilter`: 任意の[MetricFilter](#metricfilter)。

## MetricFilter

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

`MetricFilter`は、[MetricReader](#metricreader)に登録された[MetricProducer](#metricproducer)、あるいはSDKの[MetricProducer](#metricproducer)が、その`Produce`操作内で集約されたデータポイント（[メトリックポイント](/works/otel-specs-ja/spec/metrics/data-model/#metric-points)）をフィルタリングできるようにするインターフェースを定義します。フィルタリングは、パフォーマンス上の理由から[MetricProducer](#metricproducer)で行われます。

`MetricFilter`は、その`TestMetric`操作によって、メトリックストリーム全体をフィルタリングすることを許容します（そのすべての属性集合を破棄・許可する）。この操作はメトリックストリーム情報（スコープ、名前、種別、単位）を受け取り、`Accept`、`Drop`、`Accept_Partial`のいずれかの列挙値を返します。後者が返された場合、`TestAttributes`操作がそのメトリックストリームの属性集合ごとに呼び出され、その（メトリックストリーム、属性）の組に対するデータポイントが[MetricProducer](#metricproducer)の`Produce`操作の結果に許可されるかどうかを決定する列挙値を返します。

### インターフェース定義

`MetricFilter`は以下の関数をMUSTサポートするものとします。

#### TestMetric

この操作は、各[MetricProducer](#metricproducer)の`Produce`操作において、メトリックストリームごとに1回呼び出されます。

**パラメータ:**

- `instrumentationScope`: メトリックストリームのinstrumentation scope
- `name`: メトリックストリームの名前
- `kind`: メトリックストリームの[種別](/works/otel-specs-ja/spec/metrics/data-model/#point-kinds)
- `unit`: メトリックストリームの単位

返り値: `MetricFilterResult`

`MetricFilterResult`は以下のいずれかです。

* `Accept` - 与えられたメトリックストリームのすべての属性が許可されます（フィルタリングされません）。これは、属性集合ごとに`TestAttributes`操作を呼び出す必要がないため「短絡」を提供します。
* `Drop` - 与えられたメトリックストリームのすべての属性が許可されません（フィルタリングされ破棄されます）。これは、属性集合ごとに`TestAttributes`操作を呼び出す必要がなく、それらのデータポイントを（同期・非同期にかかわらず）収集する必要もないため「短絡」を提供します。例えば、このInstrumentのコールバックは呼び出される必要がありません。
* `Accept_Partial` - 一部の属性は許可され一部は許可されないため、そのInstrumentの属性集合ごとに`TestAttributes`操作を呼び出す必要があります。

#### TestAttributes

与えられたメトリックストリームと属性集合について、それが許可されるかフィルタリングされるかを決定する操作です。

この操作は、`TestMetric`操作が与えられたメトリックストリームの引数（`instrumentationScope`、`name`、`kind`、`unit`）に対して`Accept_Partial`を返した場合にのみ呼び出されるべきです（SHOULD）。

**パラメータ:**

- `instrumentationScope`: メトリックストリームのinstrumentation scope
- `name`: メトリックストリームの名前
- `kind`: メトリックストリームの種別
- `unit`: メトリックストリームの単位
- `attributes`: 属性

返り値: `AttributesFilterResult`

`AttributesFilterResult`は以下のいずれかです。

* `Accept` - この与えられた`attributes`は許可されます（フィルタリングされません）。
* `Drop` - この与えられた`attributes`は許可されません（フィルタリングされ破棄されます）。

## デフォルトと設定

SDKは、[SDK環境変数](/works/otel-specs-ja/spec/configuration/sdk-environment-variables/)仕様に従って設定をMUST提供するものとします。

## 数値限界の処理

SDKは、[OpenTelemetryにおけるエラー処理](/works/otel-specs-ja/spec/error-handling/)に従って、数値限界を適切な方法でMUST処理するものとします。

SDKが[Instrument](../api/#instrument)から浮動小数点数値を受け取る場合、可能なすべての値をMUST処理するものとします。例えば、言語のランタイムが[IEEE 754](https://en.wikipedia.org/wiki/IEEE_754)をサポートしている場合、SDKはNaNと無限大を処理する必要があります。

SDKが入力の限界をどのように処理する_か_は規定されていません。SDKの作者は、各値がAPIから来るたびにチェックを行うのではなく、より良いパフォーマンスのために言語ランタイムの振る舞いを活用・追従してもかまいません（MAY）。

SDKが出力の限界（例えば整数オーバーフロー）をどのように処理する_か_は規定されていません。SDKの作者は、エラーや例外が処理されている限り、言語ランタイムの振る舞いに依存してもかまいません（MAY）。

## 互換性の要件

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

すべてのメトリクスコンポーネントは、破壊的変更を導入せずに既存のコンポーネントへ新しいメソッドを追加できることをSHOULD許容するものとします。

すべてのメトリクスSDKのメソッドは、可能な場合、破壊的変更を導入せずに既存のメソッドへ任意のパラメータを追加できることをSHOULD許容するものとします。

## 並行性の要件

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

並行実行をサポートする言語について、Metrics SDKは特定の保証と安全性を提供します。

**MeterProvider** - Meterの作成、`ForceFlush`、`Shutdown`は、並行して呼び出されてもMUST安全であるものとします。

**ExemplarReservoir** - すべてのメソッドは、並行して呼び出されてもMUST安全であるものとします。

**MetricReader** - `Collect`、`ForceFlush`（periodic exporting MetricReaderの場合）、`Shutdown`は、並行して呼び出されてもMUST安全であるものとします。

**MetricExporter** - `ForceFlush`と`Shutdown`は、並行して呼び出されてもMUST安全であるものとします。

## セルフオブザーバビリティ

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

Metrics SDKは、[SDKのセルフオブザーバビリティ](/works/otel-specs-ja/spec/self-observability/)をSHOULDサポートするものとします。

## 参考文献

- [OTEP0113 メトリクスへのExemplarの統合](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/oteps/metrics/0113-exemplars.md)
- [OTEP0126 設定可能なバッチ処理と集約（基本的なView）に対するSDKサポートの提案](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/oteps/metrics/0126-Configurable-Metric-Aggregations.md)
- [OTEP0146 メトリクスAPI/SDKプロトタイピングのシナリオ](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/oteps/metrics/0146-metrics-prototype-scenarios.md)

