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


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

## 概要

メトリクスAPIは、以下の主要なコンポーネントから構成されます。

* [MeterProvider](#meterprovider)はAPIのエントリーポイントです。`Meter`へのアクセスを提供します。
* [Meter](#meter)は`Instrument`の作成を担います。
* [Instrument](#instrument)は[Measurement](#measurement)の報告を担います。

メトリクスAPIで計装されたプロセス内のオブジェクト階層の例を示します。

```text
+-- MeterProvider(default)
    |
    +-- Meter(name='io.opentelemetry.runtime', version='1.0.0')
    |   |
    |   +-- Instrument<Asynchronous Gauge, int>(name='cpython.gc', attributes=['generation'], unit='kB')
    |   |
    |   +-- instruments...
    |
    +-- Meter(name='io.opentelemetry.contrib.mongodb.client', version='2.3.0')
        |
        +-- Instrument<Counter, int>(name='client.exception', attributes=['type'], unit='1')
        |
        +-- Instrument<Histogram, double>(name='client.duration', attributes=['server.address', 'server.port'], unit='ms')
        |
        +-- instruments...

+-- MeterProvider(custom)
    |
    +-- Meter(name='bank.payment', version='23.3.5')
        |
        +-- instruments...
```

## MeterProvider

`Meter`は`MeterProvider`を使って取得できます。

通常、`MeterProvider`は中央の一箇所からアクセスされることが期待されます。したがって、APIはグローバルなデフォルトの`MeterProvider`を設定・登録およびアクセスする方法をSHOULD提供するものとします。

### MeterProviderの操作

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

* `Meter`の取得

#### Meterの取得

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

* `name`: [Instrumentation Scope](/works/otel-specs-ja/spec/common/instrumentation-scope/)の名前を指定します。例えば[Instrumentation Library](../../glossary/#instrumentation-library)（`io.opentelemetry.contrib.mongodb`など）、パッケージ、モジュール、クラス名です。アプリケーションやライブラリに組み込みのOpenTelemetry計装がある場合、[Instrumented library](../../glossary/#instrumented-library)と[Instrumentation library](../../glossary/#instrumentation-library)は同じライブラリを指すことができます。このシナリオでは、`name`はそのライブラリまたはアプリケーション内のモジュール名やコンポーネント名を表します。
* `version`: そのスコープにバージョンがある場合（例えばライブラリのバージョン）、Instrumentation Scopeのバージョンを指定します。値の例: `1.0.0`。

  ユーザーは`version`を提供できますが、それはユーザーの裁量に委ねられます。したがって、このAPIは`version`を受け付ける形で構造化する必要がありますが、ユーザーにそれを提供することをMUST NOT義務付けるものとします。
* [1.4.0以降] `schema_url`: 発行されるテレメトリーに記録すべきSchema URLを指定します。

  ユーザーは`schema_url`を提供できますが、それはユーザーの裁量に委ねられます。したがって、このAPIは`schema_url`を受け付ける形で構造化する必要がありますが、ユーザーにそれを提供することをMUST NOT義務付けるものとします。
* [1.13.0以降] `attributes`: 発行されるテレメトリーに関連付けるInstrumentation Scopeの属性を指定します。

  ユーザーはInstrumentation Scopeに関連付ける属性を提供できますが、それはユーザーの裁量に委ねられます。したがって、このAPIは、属性が無い場合を含め可変数の属性を受け付ける形でMUST構造化されるものとします。

*identical*（同一）という用語をMeterに適用した場合、すべてのパラメータが等しいインスタンスを表します。*distinct*（別個）という用語をMeterに適用した場合、少なくとも1つのパラメータの値が異なるインスタンスを表します。

## Meter

meterは[Instrument](#instrument)の作成を担います。

注: `Meter`は設定の責務を負うべきではありません（SHOULD NOT）。これは代わりに`MeterProvider`の責務であるべきです。

### Meterの操作

`Meter`は、新しい[Instrument](#instrument)を作成する以下の関数をMUST提供するものとします。

* [新しいCounterの作成](#counter作成)
* [新しい非同期Counterの作成](#非同期counter作成)
* [新しいHistogramの作成](#histogram作成)
* [新しいGaugeの作成](#gauge作成)
* [新しい非同期Gaugeの作成](#非同期gauge作成)
* [新しいUpDownCounterの作成](#updowncounter作成)
* [新しい非同期UpDownCounterの作成](#非同期updowncounter作成)

Instrument作成に関するさらなる情報は、以下の各節も参照してください。

## Instrument

Instrumentは[Measurement](#measurement)を報告するために使われます。各Instrumentは以下のパラメータを持ちます。

* Instrumentの[`name`](#instrument名の構文)
* Instrumentの`kind` - [Counter](#counter)か他の種別のいずれか、同期か非同期か
* 任意の測定[`unit`](#instrumentの単位)
* 任意の[`description`](#instrumentの説明)
* 任意の[`advisory`](#instrumentのadvisoryパラメータ)パラメータ（**mixed**）

Instrumentは、作成時にMeterと関連付けられます。Instrumentは`name`、`kind`、`unit`、`description`によって識別されます。

整数と浮動小数点数の区別のような言語レベルの機能は、識別に関わる要素としてSHOULD考慮されるものとします。

*identical*（同一）という用語をInstrumentに適用した場合、識別に関わるすべてのフィールドが等しいインスタンスを表します。

### 一般的な特性

#### Instrument名の構文

Instrumentの名前の構文は、以下の[Augmented Backus-Naur Form](https://datatracker.ietf.org/doc/html/rfc5234)を使って定義されます。

```abnf
instrument-name = ALPHA 0*254 ("_" / "." / "-" / "/" / ALPHA / DIGIT)

ALPHA = %x41-5A / %x61-7A; A-Z / a-z
DIGIT = %x30-39 ; 0-9
```

* nullや空文字列ではありません。
* 大文字小文字を区別しないASCII文字列です。
* 最初の文字はアルファベット文字でなければなりません。
* それ以降の文字は、英数字、'_'、'.'、'-'、'/'に属していなければなりません。
* 最大255文字までです。

#### Instrumentの単位

`unit`は、Instrumentの作者が提供する任意の文字列です。APIはこれを不透明な文字列としてSHOULD扱うものとします。

* 大文字小文字を区別するASCII文字列でなければなりません（例えば`kb`と`kB`は異なる単位です）（MUST）。
* 最大63文字までです。63という数字は、パフォーマンスが重要な場面において、単位の文字列（一部の言語ランタイムにおける`\0`終端文字を含む）を固定サイズの配列や構造体として保存・比較できるよう選ばれています。

#### Instrumentの説明

`description`は、Instrumentの作者が提供する任意の自由形式のテキストです。APIはこれを不透明な文字列としてMUST扱うものとします。

* 基本的にUTF-8の最初の3バイト（あるいは`utf8mb3`）のみである[BMP（Unicodeの第0面）](https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane)をMUSTサポートするものとします。[OpenTelemetry APIの作者](../../overview/#api)は、さらに多くのUnicode[面](https://en.wikipedia.org/wiki/Plane_(Unicode))をサポートするかどうかを決めてもかまいません（MAY）。
* 少なくとも1023文字をMUSTサポートするものとします。[OpenTelemetry APIの作者](../../overview/#api)は、さらに多くをサポートするかどうかを決めてもかまいません（MAY）。

#### Instrumentのadvisoryパラメータ

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

`advisory`パラメータは、Instrumentの作者が提供する任意の推奨事項の集合であり、最小限の設定で有用な出力を提供できるよう実装を助けることを目的としています。他のパラメータと異なる点は、実装が`advisory`パラメータを無視してもかまわない（MAY）ことです。

OpenTelemetry SDKは、`advisory`パラメータを[こちら](/works/otel-specs-ja/spec/metrics/sdk/#instrument-advisory-parameters)に記述された通りにMUST処理するものとします。

`advisory`パラメータは一般的なものもあれば、特定のInstrumentの`kind`にのみ受け付けられるものもあります。

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

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

Histogram Instrumentの種別に適用されます。

`ExplicitBucketBoundaries`（`double[]`）は、[明示的バケットHistogramメトリックデータポイント](/works/otel-specs-ja/spec/metrics/data-model/#histogram)へ集約する場合に使用する、推奨されるバケット境界の集合です。

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

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

すべてのInstrumentの種別に適用されます。

`Attributes`（[属性キー](/works/otel-specs-ja/spec/common/#attribute)のリスト）は、結果として得られるメトリクスに使用することが推奨される属性キーの集合です。

#### 同期Instrumentと非同期Instrument

Instrumentは、同期か非同期かによって分類されます。

* 同期Instrument（例えば[Counter](#counter)）は、アプリケーション・ビジネス処理ロジックとインラインで呼び出されることを意図しています。例えば、HTTPクライアントは、受信したバイト数を記録するためにCounterを使うことができます。同期Instrumentによって記録された[Measurement](#measurement)は、[Context](/works/otel-specs-ja/spec/context/)に関連付けることができます。

* 非同期Instrument（例えば[非同期Gauge](#非同期gauge)）は、ユーザーがコールバック関数を登録する手段を提供し、そのコールバック関数は必要に応じてのみ呼び出されます（参照として、SDKの[collection](/works/otel-specs-ja/spec/metrics/sdk/#collect)を参照してください）。例えば、組み込みソフトウェアは、15秒ごとにセンサーから温度を収集するために非同期gaugeを使うことができ、これはコールバック関数が15秒ごとにしか呼び出されないことを意味します。非同期Instrumentによって記録された[Measurement](#measurement)は、[Context](/works/otel-specs-ja/spec/context/)に関連付けることができません。

*同期*と*非同期*という用語は、[非同期パターン](https://en.wikipedia.org/wiki/Asynchronous_method_invocation)とは関係がないことに注意してください。

##### 同期Instrument API

同期Instrumentを構築するAPIは、以下のパラメータをMUST受け付けるものとします。

* Instrumentの`name`。

  `name`はユーザーによって提供される必要があります。可能であれば、APIはユーザーがこのパラメータを提供することを義務付けるようSHOULD構造化されるものとします。この義務を構造的に強制できない場合、APIはこのパラメータが必要であることをユーザーに伝える形でMUSTドキュメント化されるものとします。

  APIは、`name`パラメータが[Instrument名の構文](#instrument名の構文)に準拠する必要があることをユーザーに伝える形でSHOULDドキュメント化されるものとします。APIは`name`を検証すべきではなく（SHOULD NOT）、それはAPIの実装（例えば[SDK](/works/otel-specs-ja/spec/metrics/sdk/#instrumentの名前)）に委ねられます。
* 測定の`unit`。

  ユーザーは`unit`を提供できますが、それはユーザーの裁量に委ねられます。したがって、このAPIは`unit`を受け付ける形で構造化する必要がありますが、ユーザーにそれを提供することをMUST NOT義務付けるものとします。

  `unit`パラメータは、[Instrumentの単位のルール](#instrumentの単位)をサポートする必要があります。つまり、APIは、ASCII文字エンコーディングをサポートし少なくとも63文字を保持できる、大文字小文字を区別する文字列をMUST受け付けるものとします。APIは`unit`を検証すべきではありません（SHOULD NOT）。
* Instrumentを人間が読める形で記述する`description`。

  ユーザーは`description`を提供できますが、それはユーザーの裁量に委ねられます。したがって、このAPIは`description`を受け付ける形で構造化する必要がありますが、ユーザーにそれを提供することをMUST NOT義務付けるものとします。

  `description`は[Instrumentの説明のルール](#instrumentの説明)をサポートする必要があります。つまり、APIは、少なくとも[BMP（Unicodeの第0面）](https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane)でエンコードされた文字をサポートし、少なくとも1023文字を保持できる文字列をMUST受け付けるものとします。

* Instrumentの`kind`に関連付けられた`advisory`パラメータ。

  ユーザーは`advisory`パラメータを提供できますが、それはユーザーの裁量に委ねられます。したがって、このAPIは`advisory`パラメータを受け付ける形で構造化する必要がありますが、ユーザーにそれを提供することをMUST NOT義務付けるものとします。

  `advisory`パラメータは、[instrument advisoryパラメータ](#instrumentのadvisoryパラメータ)に記述された通り、一般的なパラメータと特定のInstrument `kind`に固有のパラメータとして構造化される必要があります。APIは`advisory`パラメータを検証すべきではありません（SHOULD NOT）。

##### 非同期Instrument API

非同期Instrumentには、[Measurement](#measurement)を報告する責務を持つ関連する`callback`関数があります。コールバック関数は、Meterが観測されるときにのみ呼び出されます。コールバックの実行順序は規定されていません。

非同期Instrumentを構築するAPIは、以下のパラメータをMUST受け付けるものとします。

* Instrumentの`name`。

  `name`はユーザーによって提供される必要があります。可能であれば、APIはユーザーがこのパラメータを提供することを義務付けるようSHOULD構造化されるものとします。この義務を構造的に強制できない場合、APIはこのパラメータが必要であることをユーザーに伝える形でMUSTドキュメント化されるものとします。

  APIは、`name`パラメータが[Instrument名の構文](#instrument名の構文)に準拠する必要があることをユーザーに伝える形でSHOULDドキュメント化されるものとします。APIは`name`を検証すべきではなく（SHOULD NOT）、それはAPIの実装に委ねられます。
* 測定の`unit`。

  ユーザーは`unit`を提供できますが、それはユーザーの裁量に委ねられます。したがって、このAPIは`unit`を受け付ける形で構造化する必要がありますが、ユーザーにそれを提供することをMUST NOT義務付けるものとします。

  `unit`パラメータは、[Instrumentの単位のルール](#instrumentの単位)をサポートする必要があります。つまり、APIは、ASCII文字エンコーディングをサポートし少なくとも63文字を保持できる、大文字小文字を区別する文字列をMUST受け付けるものとします。APIは`unit`を検証すべきではありません（SHOULD NOT）。
* Instrumentを人間が読める形で記述する`description`。

  ユーザーは`description`を提供できますが、それはユーザーの裁量に委ねられます。したがって、このAPIは`description`を受け付ける形で構造化する必要がありますが、ユーザーにそれを提供することをMUST NOT義務付けるものとします。

  `description`は[Instrumentの説明のルール](#instrumentの説明)をサポートする必要があります。つまり、APIは、少なくとも[BMP（Unicodeの第0面）](https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane)でエンコードされた文字をサポートし、少なくとも1023文字を保持できる文字列をMUST受け付けるものとします。
* Instrumentの`kind`に関連付けられた`advisory`パラメータ。

  ユーザーは`advisory`パラメータを提供できますが、それはユーザーの裁量に委ねられます。したがって、このAPIは`advisory`パラメータを受け付ける形で構造化する必要がありますが、ユーザーにそれを提供することをMUST NOT義務付けるものとします。

  `advisory`パラメータは、[instrument advisoryパラメータ](#instrumentのadvisoryパラメータ)に記述された通り、一般的なパラメータと特定のInstrument `kind`に固有のパラメータとして構造化される必要があります。APIは`advisory`パラメータを検証すべきではありません（SHOULD NOT）。
* 作成されたInstrumentの[Measurement](#measurement)を報告する`callback`関数。

  ユーザーは`callback`関数を提供できますが、それはユーザーの裁量に委ねられます。したがって、このAPIは、無しの場合を含め可変数の`callback`関数を受け付ける形でMUST構造化されるものとします。

APIは、新しく作成されたInstrumentに永続的に登録される0個以上の`callback`関数を渡すことによる非同期Instrumentの作成をMUSTサポートするものとします。

Callbackとは、OpenTelemetry APIを通じて`callback`関数が登録されるたびに作成される概念的なエンティティです。

APIは、作成後に非同期Instrumentに関連付けられた`callback`関数の登録をSHOULDサポートするものとします。

APIが非同期Instrument作成後の`callback`関数の登録をサポートする場合、ユーザーは何らかの手段でその登録後に特定のコールバックの登録をMUST取り消せるものとします。

Instrumentの集合に関連付けられ現在登録されているすべてのCallbackは、そのInstrumentの集合のデータを読み取る前に、収集ごとに正確に1回MUST評価されるものとします。

Callback関数は、エンドユーザー向けに以下のようにMUSTドキュメント化されるものとします。

- Callback関数はリエントラントセーフであるべきです（SHOULD）。SDKは、各MetricReaderについて独立にコールバックを評価することを想定しています。
- Callback関数は無期限の時間を要すべきではありません（SHOULD NOT）。
- Callback関数は、登録されたすべてのコールバックにわたって、重複する観測（同じ`attributes`を持つ複数の`Measurement`）をSHOULD NOT行うものとします。

コールバックがこれらの推奨事項のいずれかに違反した場合の結果として生じる振る舞いは、API層では明示的に規定されていません。

[OpenTelemetry APIの作者](../../overview/#api)は、コールバック関数から測定値を捕捉するイディオマティックな方法を決めてもかまいません（MAY）。以下にいくつかの例を示します。

* 個々の`Measurement`の値のリスト（あるいはタプル、ジェネレーター、列挙子など）を返す。
* コールバックの仮引数として*Observable Result*を渡し、`result.Observe()`によって個々の`Measurement`の値を捕捉する。

Instrument作成時に登録されたコールバックは、その作成中の単一のInstrumentにMUST適用されるものとします。

Instrument作成後に登録されたコールバックは、複数のInstrumentに関連付けられてもかまいません（MAY）。

複数Instrumentに対応するCallbackのイディオマティックなAPIは、観測された各`Measurement`値に対応するInstrumentをMUST区別するものとします。

複数Instrumentに対応するCallbackは、登録の時点で、同一の`Meter`インスタンスから得られる宣言済みの非同期Instrumentの集合とMUST関連付けられるものとします。この、InstrumentがCallbackと宣言的に関連付けられていなければならないという要件により、SDKは設定された[View](/works/otel-specs-ja/spec/metrics/sdk/#view)によって使用中のInstrumentを評価するために必要なCallbackのみを実行できます。

APIは、単一のCallbackからの観測が論理的に単一の瞬間に発生しているものとしてMUST扱うものとし、これにより記録される際、単一のコールバックからの観測は同一のタイムスタンプでMUST報告されるものとします。

APIは、コールバックへ`state`を渡す何らかの方法をSHOULD提供するものとします。[OpenTelemetry APIの作者](../../overview/#api)は、イディオマティックな方法を決めてもかまいません（MAY）（例えばコールバック関数への追加のパラメータとする、ラムダのクロージャで捕捉する、その他の方法）。

### 一般的な操作

すべての[同期Instrument](#同期instrument-api)は、以下を行う関数をSHOULD提供するものとします。

* [Instrumentが`Enabled`かどうかの報告](#enabled)

すべての[同期Instrument](#同期instrument-api)は以下を提供してもかまいません（MAY）。

* （**Development**）[属性の集合へのBind](#bind)

#### Enabled

ユーザーが測定値を記録する際に計算コストの高い操作を行うことを避けられるようにするため、[同期Instrument](#同期instrument-api)はこの`Enabled` APIをSHOULD提供するものとします。

このAPIには現在必須のパラメータはありません。将来パラメータが追加される可能性があるため、APIはパラメータを追加できる形でMUST構造化されるものとします。

このAPIは言語にとってイディオマティックなブール型をMUST返すものとします。返り値が`true`の場合、指定された引数に対してInstrumentが有効であることを意味し、`false`の場合は指定された引数に対してInstrumentが無効であることを意味します。

返される値は常に静的ではなく、時間とともに変化することがあります。このAPIは、計装作者が最新の応答を得るために測定値を記録するたびにこのAPIを呼び出す必要があるとドキュメント化されるべきです（SHOULD）。

#### Bind

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

`Bind` APIは、返される束縛済みInstrumentで記録されるすべての測定値に、固定された[Attributes](/works/otel-specs-ja/spec/common/#attribute)の集合を関連付けます。属性は各記録時ではなくbind時に解決されるため、実装は記録ごとの属性処理と検索のオーバーヘッドを避けられます。

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

* 返される束縛済みInstrumentで記録されるすべての測定値に関連付ける[Attributes](/works/otel-specs-ja/spec/common/#attribute)。

  ユーザーは束縛済みInstrumentに関連付ける属性を提供できますが、それはユーザーの裁量に委ねられます。したがって、このAPIは、無しの場合を含め可変数の属性を受け付ける形でMUST構造化されるものとします。

このAPIは、それらの属性に束縛されたInstrumentを表す言語イディオマティックな型をMUST返すものとします。

返される束縛済みInstrumentは、そのInstrumentの中核となる記録操作をMUSTサポートするものとします。Instrumentの種別によって、束縛済みInstrument上の記録操作が決まります。

* [Counter](#counter): [Add](#add)
* [Histogram](#histogram): [Record](#record)
* [Gauge](#gauge): [Record](#record-1)
* [UpDownCounter](#updowncounter): [Add](#add-1)

これは、専用の束縛済みInstrument型を導入することで実現してもよく（MAY）、既存のInstrumentインターフェースを再利用することで実現してもかまいません（MAY）。既存のInstrumentインターフェースを再利用する場合、`Bind` APIは、返される束縛済みInstrument上で属性を伴う記録操作を呼び出すとbindによるパフォーマンス上の利点が失われることをユーザーに伝える形でMUSTドキュメント化されるものとします。

束縛済みInstrumentで記録された測定値は、[Context](/works/otel-specs-ja/spec/context/)に関連付けることができます。

[OpenTelemetry APIの作者](../../overview/#api)が検討しうる例をいくつか示します。

```java
// Java

LongCounter rolls = meter.counterBuilder("dice.rolls")
    .setDescription("The number of times each side of the die was rolled")
    .setUnit("{roll}")
    .build();

var face1 = rolls.bind(Attributes.of(AttributeKey.longKey("roll.value"), 1L));
var face6 = rolls.bind(Attributes.of(AttributeKey.longKey("roll.value"), 6L));

face1.add(1);
face6.add(1);
```

### Counter

`Counter`は、非負の増分をサポートする[同期Instrument](#同期instrument-api)です。

`Counter`の使用例:

* 受信したバイト数を数える
* 完了したリクエスト数を数える
* 作成されたアカウント数を数える
* 実行されたチェックポイント数を数える
* HTTP 5xxエラーの数を数える

#### Counter作成

[`Meter`](#meter)を使う以外に、`Counter`を作成するAPIはMUST NOT存在するものとします。これは`CreateCounter`と呼んでもかまいません（MAY）。強い型付けが望まれる場合、[OpenTelemetry APIの作者](../../overview/#api)は、例えば`CreateUInt64Counter`、`CreateDoubleCounter`、`CreateCounter<UInt64>`、`CreateCounter<double>`のような言語にとってイディオマティックな名前を決めてもかまいません（MAY）。

[同期Instrumentの一般的な要件](#同期instrument-api)を参照してください。

[OpenTelemetry APIの作者](../../overview/#api)が検討しうる例をいくつか示します。

```python
# Python

exception_counter = meter.create_counter(name="exceptions", description="number of exceptions caught", value_type=int)
```

```csharp
// C#

var counterExceptions = meter.CreateCounter<UInt64>("exceptions", description="number of exceptions caught");

readonly struct PowerConsumption
{
    [HighCardinality]
    string customer;
};

var counterPowerUsed = meter.CreateCounter<double, PowerConsumption>("power_consumption", unit="kWh");
```

#### Counterの操作

##### Add

Counterを固定量だけ増加させます。

このAPIは値をSHOULD NOT返すものとします（特定のプログラミング言語やシステムで必要な場合、`null`や`undefined`のようなダミーの値を返してもかまいません（MAY））。

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

* 数値の増分値。

  増分値はユーザーによって提供される必要があります。可能であれば、このAPIはユーザーがこのパラメータを提供することを義務付けるようSHOULD構造化されるものとします。この義務を構造的に強制できない場合、このAPIはこのパラメータが必要であることをユーザーに伝える形でMUSTドキュメント化されるものとします。

  増分値は非負であることが期待されます。このAPIは、この値が非負であることが期待されるとユーザーに伝える形でSHOULDドキュメント化されるものとします。このAPIはこの値を検証すべきではなく（SHOULD NOT）、それはAPIの実装に委ねられます。
* 増分値に関連付ける[Attributes](/works/otel-specs-ja/spec/common/#attribute)。

  ユーザーは増分値に関連付ける属性を提供できますが、それはユーザーの裁量に委ねられます。したがって、このAPIは、無しの場合を含め可変数の属性を受け付ける形でMUST構造化されるものとします。

[OpenTelemetry APIの作者](../../overview/#api)は、柔軟な[属性](/works/otel-specs-ja/spec/common/#attribute)を引数として渡すことを許容してもかまいません（MAY）。属性の名前と型が[counter作成](#counter作成)時に提供される場合、[OpenTelemetry APIの作者](../../overview/#api)は、より効率的な方法（例えばコールスタック上に確保される強く型付けされた構造体、タプルなど）で属性値を渡すことを許容してもかまいません（MAY）。APIは、Instrument作成時にすべての可能な属性名を登録する代わりに、呼び出し元が呼び出し時に柔軟な属性を提供することをMUST許容するものとします。[OpenTelemetry APIの作者](../../overview/#api)が検討しうる例をいくつか示します。

```python
# Python

exception_counter.add(1, {"exception_type": "IOError", "handled_by_user": True})
exception_counter.add(1, exception_type="IOError", handled_by_user=True)
```

```csharp
// C#

counterExceptions.Add(1, ("exception_type", "FileLoadException"), ("handled_by_user", true));

counterPowerUsed.Add(13.5, new PowerConsumption { customer = "Tom" });
counterPowerUsed.Add(200, new PowerConsumption { customer = "Jerry" }, ("is_green_energy", true));
```

### 非同期Counter

非同期Counterは、Instrumentが観測される際に[単調に](https://en.wikipedia.org/wiki/Monotonic_function)増加する値を報告する[非同期Instrument](#非同期instrument-api)です。

非同期Counterの使用例:

* [CPU時間](https://wikipedia.org/wiki/CPU_time)。各スレッド、各プロセス、あるいはシステム全体について報告できます。例えば「ユーザーモードで実行されているプロセスAのCPU時間（秒単位で測定）」です。
* 各プロセスの[ページフォールト](https://wikipedia.org/wiki/Page_fault)の数。

#### 非同期Counter作成

[`Meter`](#meter)を使う以外に、非同期Counterを作成するAPIはMUST NOT存在するものとします。これは`CreateObservableCounter`と呼んでもかまいません（MAY）。強い型付けが望まれる場合、[OpenTelemetry APIの作者](../../overview/#api)は、例えば`CreateUInt64ObservableCounter`、`CreateDoubleObservableCounter`、`CreateObservableCounter<UInt64>`、`CreateObservableCounter<double>`のような言語にとってイディオマティックな名前を決めてもかまいません（MAY）。

強い理由がない限り、`ObservableCounter`（あるいは`observable_counter`のような言語にとってイディオマティックな変種）という名前を使うことが強く推奨されます。この名前は、[非同期パターン](https://en.wikipedia.org/wiki/Asynchronous_method_invocation)や[オブザーバーパターン](https://en.wikipedia.org/wiki/Observer_pattern)とは何の関係もないことに注意してください。

[非同期Instrumentの一般的な要件](#非同期instrument-api)を参照してください。

注: 増分・差分の値を取る[Counter.Add()](#add)とは異なり、コールバック関数はcounterの絶対値を報告します。counterの変化率を求めるには、連続する測定値の差分が使われます。

[OpenTelemetry APIの作者](../../overview/#api)は、イディオマティックな方法を決めてもかまいません（MAY）。以下にいくつかの例を示します。

* `Measurement`のリスト（あるいはタプル、ジェネレーター、列挙子など）を返す。
* observable resultの引数を使って、個々の`Measurement`を報告できるようにする。

ユーザーコードは、1回のコールバック内で同じ`attributes`を持つ複数の`Measurement`を提供しないことが推奨されます。もしそれが発生した場合、[OpenTelemetry SDKの作者](../../overview/#sdk)は、それを[SDK](../#sdk)でどう処理するかを決めてもかまいません（MAY）。例えば、コールバックの呼び出し中に`value=1, attributes={pid:4, bitness:64}`と`value=2, attributes={pid:4, bitness:64}`という2つの測定値が報告された場合、[OpenTelemetry SDKの作者](../../overview/#sdk)は、単純にそれらをそのまま通過させる（下流のコンシューマーが重複を処理できるようにする）か、データ全体をドロップするか、最後の値を選ぶか、その他の方法を決めてもかまいません（MAY）。APIは、単一のコールバックからの観測が論理的に単一の瞬間に発生しているものとしてMUST扱うものとし、これにより記録される際、単一のコールバックからの観測は同一のタイムスタンプでMUST報告されるものとします。

APIは、コールバックへ`state`を渡す何らかの方法をSHOULD提供するものとします。[OpenTelemetry APIの作者](../../overview/#api)は、イディオマティックな方法を決めてもかまいません（MAY）（例えばコールバック関数への追加のパラメータとする、ラムダのクロージャで捕捉する、その他の方法）。

[OpenTelemetry APIの作者](../../overview/#api)が検討しうる例をいくつか示します。

```python
# Python

def pf_callback():
    # Note: in the real world these would be retrieved from the operating system
    return (
        (8,        ("pid", 0),   ("bitness", 64)),
        (37741921, ("pid", 4),   ("bitness", 64)),
        (10465,    ("pid", 880), ("bitness", 32)),
    )

meter.create_observable_counter(name="PF", description="process page faults", pf_callback)
```

```python
# Python

def pf_callback(result):
    # Note: in the real world these would be retrieved from the operating system
    result.Observe(8,        ("pid", 0),   ("bitness", 64))
    result.Observe(37741921, ("pid", 4),   ("bitness", 64))
    result.Observe(10465,    ("pid", 880), ("bitness", 32))

meter.create_observable_counter(name="PF", description="process page faults", pf_callback)
```

```csharp
// C#

// A simple scenario where only one value is reported

interface IAtomicClock
{
    UInt64 GetCaesiumOscillates();
}

IAtomicClock clock = AtomicClock.Connect();

meter.CreateObservableCounter<UInt64>("caesium_oscillates", () => clock.GetCaesiumOscillates());
```

#### 非同期Counterの操作

非同期Counterは、[非同期Counter作成](#非同期counter作成)時に登録される`callback`を通じて測定値を報告するイディオマティックなインターフェースを使います。

非同期Instrument作成後に登録されるコールバック関数については、APIは登録解除の仕組みをサポートすることが要求されます。例えば、`register_callback`から返されるオブジェクトが、`unregister()`メソッドを直接サポートできます。

```python
# Python
class Device:
    """A device with one counter"""

    def __init__(self, meter, x):
        self.x = x
        counter = meter.create_observable_counter(name="usage", description="count of items used")
        self.cb = counter.register_callback(self.counter_callback)

    def counter_callback(self, result):
        result.Observe(self.read_counter(), {'x', self.x})

    def read_counter(self):
        return 100  # ...

    def stop(self):
        self.cb.unregister()
```

### Histogram

`Histogram`は、統計的に意味を持つ可能性のある任意の値を報告するために使える[同期Instrument](#同期instrument-api)です。ヒストグラム、サマリー、パーセンタイルといった統計量を意図しています。

`Histogram`の使用例:

* リクエストの所要時間
* レスポンスペイロードのサイズ

#### Histogram作成

[`Meter`](#meter)を使う以外に、`Histogram`を作成するAPIはMUST NOT存在するものとします。これは`CreateHistogram`と呼んでもかまいません（MAY）。強い型付けが望まれる場合、[OpenTelemetry APIの作者](../../overview/#api)は、例えば`CreateUInt64Histogram`、`CreateDoubleHistogram`、`CreateHistogram<UInt64>`、`CreateHistogram<double>`のような言語にとってイディオマティックな名前を決めてもかまいません（MAY）。

[同期Instrumentの一般的な要件](#同期instrument-api)を参照してください。

[OpenTelemetry APIの作者](../../overview/#api)が検討しうる例をいくつか示します。

```python
# Python

http_server_duration = meter.create_histogram(
    name="http.server.duration",
    description="measures the duration of the inbound HTTP request",
    unit="ms",
    value_type=float)
```

```csharp
// C#

var httpServerDuration = meter.CreateHistogram<double>(
    "http.server.duration",
    description: "measures the duration of the inbound HTTP request",
    unit: "ms"
    );
```

#### Histogramの操作

##### Record

指定された量で統計を更新します。

このAPIは値をSHOULD NOT返すものとします（特定のプログラミング言語やシステムで必要な場合、`null`や`undefined`のようなダミーの値を返してもかまいません（MAY））。

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

* 記録する数値。

  値はユーザーによって提供される必要があります。可能であれば、このAPIはユーザーがこのパラメータを提供することを義務付けるようSHOULD構造化されるものとします。この義務を構造的に強制できない場合、このAPIはこのパラメータが必要であることをユーザーに伝える形でMUSTドキュメント化されるものとします。

  値は非負であることが期待されます。このAPIは、この値が非負であることが期待されるとユーザーに伝える形でSHOULDドキュメント化されるものとします。このAPIはこの値を検証すべきではなく（SHOULD NOT）、それはAPIの実装に委ねられます。
* 値に関連付ける[Attributes](/works/otel-specs-ja/spec/common/#attribute)。

  ユーザーは値に関連付ける属性を提供できますが、それはユーザーの裁量に委ねられます。したがって、このAPIは、無しの場合を含め可変数の属性を受け付ける形でMUST構造化されるものとします。

[OpenTelemetry APIの作者](../../overview/#api)は、柔軟な[属性](/works/otel-specs-ja/spec/common/#attribute)を個々の引数として渡すことを許容してもかまいません（MAY）。[OpenTelemetry APIの作者](../../overview/#api)は、より効率的な方法（例えばコールスタック上に確保される強く型付けされた構造体、タプルなど）で属性値を渡すことを許容してもかまいません（MAY）。[OpenTelemetry APIの作者](../../overview/#api)が検討しうる例をいくつか示します。

```python
# Python

http_server_duration.Record(50, {"http.request.method": "POST", "url.scheme": "https"})
http_server_duration.Record(100, http_method="GET", http_scheme="http")
```

```csharp
// C#

httpServerDuration.Record(50, ("http.request.method", "POST"), ("url.scheme", "https"));
httpServerDuration.Record(100, new HttpRequestAttributes { method = "GET", scheme = "http" });
```

### Gauge

`Gauge`は、変化が生じたときに加算的でない値（例えばバックグラウンドの騒音レベル - 複数の部屋の騒音レベルの値を記録して合計することには意味がありません）を記録するために使える[同期Instrument](#同期instrument-api)です。

注: 値が加算的である場合（例えばプロセスのヒープサイズ - 複数のプロセスからヒープサイズを報告して合計し、全体のヒープ使用量を得ることには意味があります）は、[UpDownCounter](#非同期updowncounter)を使ってください。

注: 同期Gaugeは通常、変更イベントへのサブスクリプションを通じて測定値が公開される場合に使われます（すなわち`backgroundNoiseLevel.onChange(value -> gauge.record(value))`）。測定値がアクセサを介して公開される場合は、[非同期Gauge](#非同期gauge)を使って、コールバック関数内でアクセサを呼び出してください（すなわち`createObservableGauge(observable -> observable.record(backgroundNoiseLevel.getCurrentValue()))`）。

Gaugeの使用例:

* バックグラウンドの騒音レベルの変更イベントへのサブスクリプション
* CPUファン速度の変更イベントへのサブスクリプション

#### Gauge作成

[`Meter`](#meter)を使う以外に、`Gauge`を作成するAPIはMUST NOT存在するものとします。これは`CreateGauge`と呼んでもかまいません（MAY）。強い型付けが望まれる場合、[OpenTelemetry APIの作者](../../overview/#api)は、例えば`CreateUInt64Gauge`、`CreateDoubleGauge`、`CreateGauge<UInt64>`、`CreateGauge<double>`のような言語にとってイディオマティックな名前を決めてもかまいません（MAY）。

[同期Instrumentの一般的な要件](#同期instrument-api)を参照してください。

[OpenTelemetry APIの作者](../../overview/#api)が検討しうる例をいくつか示します。

```java
// Java

DoubleGauge backgroundNoiseLevel = meter.gaugeBuilder("facility.noise.level")
    .setDescription("Background noise level of rooms")
    .setUnit("B")
    .build();
```

#### Gaugeの操作

##### Record

Gaugeの現在値を記録します。

このAPIは値をSHOULD NOT返すものとします（特定のプログラミング言語やシステムで必要な場合、`null`や`undefined`のようなダミーの値を返してもかまいません（MAY））。

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

* 数値。現在の絶対値。

  値はユーザーによって提供される必要があります。可能であれば、このAPIはユーザーがこのパラメータを提供することを義務付けるようSHOULD構造化されるものとします。この義務を構造的に強制できない場合、このAPIはこのパラメータが必要であることをユーザーに伝える形でMUSTドキュメント化されるものとします。
* 値に関連付ける[Attributes](/works/otel-specs-ja/spec/common/#attribute)。

  ユーザーは値に関連付ける属性を提供できますが、それはユーザーの裁量に委ねられます。したがって、このAPIは、無しの場合を含め可変数の属性を受け付ける形でMUST構造化されるものとします。

[OpenTelemetry APIの作者](../../overview/#api)は、柔軟な[属性](/works/otel-specs-ja/spec/common/#attribute)を引数として渡すことを許容してもかまいません（MAY）。属性の名前と型が[gauge作成](#gauge作成)時に提供される場合、[OpenTelemetry APIの作者](../../overview/#api)は、より効率的な方法（例えばコールスタック上に確保される強く型付けされた構造体、タプルなど）で属性値を渡すことを許容してもかまいません（MAY）。APIは、Instrument作成時にすべての可能な属性名を登録する代わりに、呼び出し元が呼び出し時に柔軟な属性を提供することをMUST許容するものとします。[OpenTelemetry APIの作者](../../overview/#api)が検討しうる例をいくつか示します。

```java
// Java
Attributes roomA = Attributes.builder().put("room.id", "Rack A");
Attributes roomB = Attributes.builder().put("room.id", "Rack B");

backgroundNoiseLevel.record(4.3, roomA);
backgroundNoiseLevel.record(2.5, roomB);
```

### 非同期Gauge

非同期Gaugeは、Instrumentが観測される際に加算的でない値（例えば部屋の温度 - 複数の部屋の温度の値を報告して合計することには意味がありません）を報告する[非同期Instrument](#非同期instrument-api)です。

注: 値が加算的な場合（例えばプロセスのヒープサイズ - 複数のプロセスからヒープサイズを報告して合計し、全体のヒープ使用量を得ることには意味があります）は、[非同期Counter](#非同期counter)や[非同期UpDownCounter](#非同期updowncounter)を使ってください。

非同期Gaugeの使用例:

* 現在の部屋の温度
* CPUファン速度

#### 非同期Gauge作成

[`Meter`](#meter)を使う以外に、非同期Gaugeを作成するAPIはMUST NOT存在するものとします。これは`CreateObservableGauge`と呼んでもかまいません（MAY）。強い型付けが望まれる場合、[OpenTelemetry APIの作者](../../overview/#api)は、例えば`CreateUInt64ObservableGauge`、`CreateDoubleObservableGauge`、`CreateObservableGauge<UInt64>`、`CreateObservableGauge<double>`のような言語にとってイディオマティックな名前を決めてもかまいません（MAY）。

強い理由がない限り、`ObservableGauge`（あるいは`observable_gauge`のような言語にとってイディオマティックな変種）という名前を使うことが強く推奨されます。この名前は、[非同期パターン](https://en.wikipedia.org/wiki/Asynchronous_method_invocation)や[オブザーバーパターン](https://en.wikipedia.org/wiki/Observer_pattern)とは何の関係もないことに注意してください。

[非同期Instrumentの一般的な要件](#非同期instrument-api)を参照してください。

[OpenTelemetry APIの作者](../../overview/#api)が検討しうる例をいくつか示します。

```python
# Python

def cpu_frequency_callback():
    # Note: in the real world these would be retrieved from the operating system
    return (
        (3.38, ("cpu", 0), ("core", 0)),
        (3.51, ("cpu", 0), ("core", 1)),
        (0.57, ("cpu", 1), ("core", 0)),
        (0.56, ("cpu", 1), ("core", 1)),
    )

meter.create_observable_gauge(
    name="cpu.frequency",
    description="the real-time CPU clock speed",
    callback=cpu_frequency_callback,
    unit="GHz",
    value_type=float)
```

```python
# Python

def cpu_frequency_callback(result):
    # Note: in the real world these would be retrieved from the operating system
    result.Observe(3.38, ("cpu", 0), ("core", 0))
    result.Observe(3.51, ("cpu", 0), ("core", 1))
    result.Observe(0.57, ("cpu", 1), ("core", 0))
    result.Observe(0.56, ("cpu", 1), ("core", 1))

meter.create_observable_gauge(
    name="cpu.frequency",
    description="the real-time CPU clock speed",
    callback=cpu_frequency_callback,
    unit="GHz",
    value_type=float)
```

```csharp
// C#

// A simple scenario where only one value is reported

meter.CreateObservableGauge<double>("temperature", () => sensor.GetTemperature());
```

#### 非同期Gaugeの操作

非同期Gaugeは、[非同期Gauge作成](#非同期gauge作成)時に登録される`callback`を通じて測定値を報告するイディオマティックなインターフェースを使います。

非同期Instrument作成後に登録されるコールバック関数については、APIは登録解除の仕組みをサポートすることが要求されます。例えば、`register_callback`から返されるオブジェクトが、`unregister()`メソッドを直接サポートできます。

```python
# Python
class Device:
    """A device with one gauge"""

    def __init__(self, meter, x):
        self.x = x
        gauge = meter.create_observable_gauge(name="pressure", description="force/area")
        self.cb = gauge.register_callback(self.gauge_callback)

    def gauge_callback(self, result):
        result.Observe(self.read_gauge(), {'x', self.x})

    def read_gauge(self):
        return 100  # ...

    def stop(self):
        self.cb.unregister()
```

### UpDownCounter

`UpDownCounter`は、増加と減少をサポートする[同期Instrument](#同期instrument-api)です。

注: 値が[単調に](https://en.wikipedia.org/wiki/Monotonic_function)増加する場合は、代わりに[Counter](#counter)を使ってください。

`UpDownCounter`の使用例:

* アクティブなリクエストの数
* キュー内のアイテムの数

`UpDownCounter`は、絶対値が事前に計算されていない、あるいは「現在の値」の取得に余分な労力が必要となるシナリオを意図しています。事前計算された値がすでに利用可能な場合や、「現在の値」のスナップショットの取得が簡単な場合は、代わりに[非同期UpDownCounter](#非同期updowncounter)を使ってください。

UpDownCounterは、**コレクションのサイズ**を増分的に数えることをサポートします。例えば、"color"と"material"の属性ごとに、追加・削除される並行バッグ内のアイテム数を報告する場合です。

| Color    | Material     | Count |
| -------- | -----------  | ----- |
| Red      | Aluminum     | 1     |
| Red      | Steel        | 2     |
| Blue     | Aluminum     | 0     |
| Blue     | Steel        | 5     |
| Yellow   | Aluminum     | 0     |
| Yellow   | Steel        | 3     |

```python
# Python

items_counter = meter.create_up_down_counter(
    name="store.inventory",
    description="the number of the items available")

def restock_item(color, material):
    inventory.add_item(color=color, material=material)
    items_counter.add(1, {"color": color, "material": material})
    return true

def sell_item(color, material):
    succeeded = inventory.take_item(color=color, material=material)
    if succeeded:
        items_counter.add(-1, {"color": color, "material": material})
    return succeeded
```

#### UpDownCounter作成

[`Meter`](#meter)を使う以外に、`UpDownCounter`を作成するAPIはMUST NOT存在するものとします。これは`CreateUpDownCounter`と呼んでもかまいません（MAY）。強い型付けが望まれる場合、[OpenTelemetry APIの作者](../../overview/#api)は、例えば`CreateInt64UpDownCounter`、`CreateDoubleUpDownCounter`、`CreateUpDownCounter<Int64>`、`CreateUpDownCounter<double>`のような言語にとってイディオマティックな名前を決めてもかまいません（MAY）。

[同期Instrumentの一般的な要件](#同期instrument-api)を参照してください。

[OpenTelemetry APIの作者](../../overview/#api)が検討しうる例をいくつか示します。

```python
# Python

customers_in_store = meter.create_up_down_counter(
    name="grocery.customers",
    description="measures the current customers in the grocery store",
    value_type=int)
```

```csharp
// C#

var customersInStore = meter.CreateUpDownCounter<int>(
    "grocery.customers",
    description: "measures the current customers in the grocery store",
    );
```

#### UpDownCounterの操作

##### Add

UpDownCounterを固定量だけ増加または減少させます。

このAPIは値をSHOULD NOT返すものとします（特定のプログラミング言語やシステムで必要な場合、`null`や`undefined`のようなダミーの値を返してもかまいません（MAY））。

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

* 加算する数値。

  値はユーザーによって提供される必要があります。可能であれば、このAPIはユーザーがこのパラメータを提供することを義務付けるようSHOULD構造化されるものとします。この義務を構造的に強制できない場合、このAPIはこのパラメータが必要であることをユーザーに伝える形でMUSTドキュメント化されるものとします。
* 値に関連付ける[Attributes](/works/otel-specs-ja/spec/common/#attribute)。

  ユーザーは値に関連付ける属性を提供できますが、それはユーザーの裁量に委ねられます。したがって、このAPIは、無しの場合を含め可変数の属性を受け付ける形でMUST構造化されるものとします。

[OpenTelemetry APIの作者](../../overview/#api)は、柔軟な[属性](/works/otel-specs-ja/spec/common/#attribute)を個々の引数として渡すことを許容してもかまいません（MAY）。[OpenTelemetry APIの作者](../../overview/#api)は、より効率的な方法（例えばコールスタック上に確保される強く型付けされた構造体、タプルなど）で属性値を渡すことを許容してもかまいません（MAY）。[OpenTelemetry APIの作者](../../overview/#api)が検討しうる例をいくつか示します。

```python
# Python
customers_in_store.add(1, {"account.type": "commercial"})
customers_in_store.add(-1, account_type="residential")
```

```csharp
// C#
customersInStore.Add(1, ("account.type", "commercial"));
customersInStore.Add(-1, new Account { Type = "residential" });
```

### 非同期UpDownCounter

非同期UpDownCounterは、Instrumentが観測される際に加算的な値（例えばプロセスのヒープサイズ - 複数のプロセスからヒープサイズを報告して合計し、全体のヒープ使用量を得ることには意味があります）を報告する[非同期Instrument](#非同期instrument-api)です。

注: 値が[単調に](https://en.wikipedia.org/wiki/Monotonic_function)増加する場合は代わりに[非同期Counter](#非同期counter)を使ってください。値が非加算的な場合は代わりに[非同期Gauge](#非同期gauge)を使ってください。

非同期UpDownCounterの使用例:

* プロセスのヒープサイズ
* ロックフリーな循環バッファ内のアイテムのおおよその数

#### 非同期UpDownCounter作成

[`Meter`](#meter)を使う以外に、非同期UpDownCounterを作成するAPIはMUST NOT存在するものとします。これは`CreateObservableUpDownCounter`と呼んでもかまいません（MAY）。強い型付けが望まれる場合、[OpenTelemetry APIの作者](../../overview/#api)は、例えば`CreateUInt64ObservableUpDownCounter`、`CreateDoubleObservableUpDownCounter`、`CreateObservableUpDownCounter<UInt64>`、`CreateObservableUpDownCounter<double>`のような言語にとってイディオマティックな名前を決めてもかまいません（MAY）。

強い理由がない限り、`ObservableUpDownCounter`（あるいは`observable_up_down_counter`のような言語にとってイディオマティックな変種）という名前を使うことが強く推奨されます。この名前は、[非同期パターン](https://en.wikipedia.org/wiki/Asynchronous_method_invocation)や[オブザーバーパターン](https://en.wikipedia.org/wiki/Observer_pattern)とは何の関係もないことに注意してください。

[非同期Instrumentの一般的な要件](#非同期instrument-api)を参照してください。

注: 増分・差分の値を取る[UpDownCounter.Add()](#add-1)とは異なり、コールバック関数は非同期UpDownCounterの絶対値を報告します。非同期UpDownCounterの変化率を求めるには、連続する測定値の差分が使われます。

[OpenTelemetry APIの作者](../../overview/#api)が検討しうる例をいくつか示します。

```python
# Python

def ws_callback():
    # Note: in the real world these would be retrieved from the operating system
    return (
        (8,      ("pid", 0),   ("bitness", 64)),
        (20,     ("pid", 4),   ("bitness", 64)),
        (126032, ("pid", 880), ("bitness", 32)),
    )

meter.create_observable_up_down_counter(
    name="process.workingset",
    description="process working set",
    callback=ws_callback,
    unit="kB",
    value_type=int)
```

```python
# Python

def ws_callback(result):
    # Note: in the real world these would be retrieved from the operating system
    result.Observe(8,      ("pid", 0),   ("bitness", 64))
    result.Observe(20,     ("pid", 4),   ("bitness", 64))
    result.Observe(126032, ("pid", 880), ("bitness", 32))

meter.create_observable_up_down_counter(
    name="process.workingset",
    description="process working set",
    callback=ws_callback,
    unit="kB",
    value_type=int)
```

```csharp
// C#

// A simple scenario where only one value is reported

meter.CreateObservableUpDownCounter<UInt64>("memory.physical.free", () => WMI.Query("FreePhysicalMemory"));
```

#### 非同期UpDownCounterの操作

非同期UpDownCounterは、[非同期Updowncounter作成](#非同期updowncounter作成)時に登録される`callback`を通じて測定値を報告するイディオマティックなインターフェースを使います。

非同期Instrument作成後に登録されるコールバック関数については、APIは登録解除の仕組みをサポートすることが要求されます。例えば、`register_callback`から返されるオブジェクトが、`unregister()`メソッドを直接サポートできます。

```python
# Python
class Device:
    """A device with one up_down_counter"""

    def __init__(self, meter, x):
        self.x = x
        updowncounter = meter.create_observable_up_down_counter(name="queue_size", description="items in process")
        self.cb = updowncounter.register_callback(self.up_down_counter_callback)

    def up_down_counter_callback(self, result):
        result.Observe(self.read_up_down_counter(), {'x', self.x})

    def read_up_down_counter(self):
        return 100  # ...

    def stop(self):
        self.cb.unregister()
```

## Measurement

`Measurement`は、メトリクスAPIを通じてSDKへ報告されるデータポイントを表します。APIとSDK間の相互作用については[メトリクスのプログラミングモデル](../../overview/#メトリックシグナル)を参照してください。

`Measurement`は以下をカプセル化します。

* 値
* [`Attributes`](/works/otel-specs-ja/spec/common/#attribute)

### 複数Instrumentに対応するコールバック

[メトリクスAPIは、単一の登録済みCallbackから複数のInstrumentを使用できるインターフェースをサポートしてもかまいません（MAY）](#非同期instrument-api)。新しいCallbackを登録するAPIは、以下をSHOULD受け付けるものとします。

- `callback`関数
- `callback`関数内で使われるInstrumentのリスト（あるいはタプルなど）。

APIの作者は、`callback`関数について以下のいずれかの形式を使うことがRECOMMENDEDです。

* `callback`関数が返すリスト（あるいはタプルなど）が`(Instrument, Measurement)`のペアを含む。
* Observable Resultの引数が追加の`(Instrument, Measurement)`のペアを受け取る。

このインターフェースは、`/proc`ファイルの読み取りやガベージコレクションサブシステムの調査のような、コストの高いプロセスを通じて得られる複数の測定値を報告する際に、通常より高性能な方法となります。

例を示します。

```Python
# Python
class Device:
    """A device with two instruments"""

    def __init__(self, meter, property):
        self.property = property
        self.usage = meter.create_observable_counter(name="usage", description="count of items used")
        self.pressure = meter.create_observable_gauge(name="pressure", description="force per unit area")

        # Note the two associated instruments are passed to the callback.
        meter.register_callback([self.usage, self.pressure], self.observe)

    def observe(self, result):
        usage, pressure = expensive_system_call()
        result.observe(self.usage, usage, {'property', self.property})
        result.observe(self.pressure, pressure, {'property', self.property})
```

## 互換性の要件

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

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

## 並行性の要件

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

**MeterProvider** - すべてのメソッドは、実装がデフォルトで並行使用に対して安全である必要があるとMUSTドキュメント化されるものとします。

**Meter** - すべてのメソッドは、実装がデフォルトで並行使用に対して安全である必要があるとMUSTドキュメント化されるものとします。

**Instrument** - すべてのメソッドは、実装がデフォルトで並行使用に対して安全である必要があるとMUSTドキュメント化されるものとします。

## 参考文献

- [OTEP0003 事前集約された生メトリクスAPIの統合](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/oteps/metrics/0003-measure-metric-type.md)
- [OTEP0008 メトリクスオブザーバー仕様](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/oteps/metrics/0008-metric-observer.md)
- [OTEP0009 メトリックハンドルAPI仕様](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/oteps/metrics/0009-metric-handles.md)
- [OTEP0010 メトリクスAPIにおける「Cumulative」の「Counter」への改名](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/oteps/metrics/0010-cumulative-to-counter.md)
- [OTEP0049 メトリック`LabelSet`仕様](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/oteps/metrics/0049-metric-label-set.md)
- [OTEP0070 メトリックInstrumentのHandleの「Bound Instrument」への改名](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/oteps/metrics/0070-metric-bound-instrument.md)
- [OTEP0072 メトリクスオブザーバー仕様（改訂）](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/oteps/metrics/0072-metric-observer.md)
- [OTEP0080 メトリクスAPIからのGauge Instrumentの削除](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/oteps/metrics/0080-remove-metric-gauge.md)
- [OTEP0088 メトリックInstrument](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/oteps/metrics/0088-metric-instrument-optional-refinements.md)
- [OTEP0090 メトリクスAPIからのLabelSetオブジェクトの削除](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/oteps/metrics/0090-remove-labelset-from-metrics-api.md)
- [OTEP0098 メトリックInstrumentの説明](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/oteps/metrics/0098-metric-instruments-explained.md)
- [OTEP0108 メトリックInstrumentの命名ガイドライン](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/oteps/metrics/0108-naming-guidelines.md)
- [OTEP0146 メトリクスAPI/SDKプロトタイピングのシナリオ](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/oteps/metrics/0146-metrics-prototype-scenarios.md)

