メトリクスAPI
この記事は英語の原文を日本語に翻訳したものです。原文: https://opentelemetry.io/docs/specs/otel/metrics/api/
翻訳元: open-telemetry/opentelemetry-specification v1.60.0(コミット 29ae8c7)
ステータス: 特記のない限りStable
概要
メトリクスAPIは、以下の主要なコンポーネントから構成されます。
- MeterProviderはAPIのエントリーポイントです。
Meterへのアクセスを提供します。 - Meterは
Instrumentの作成を担います。 - InstrumentはMeasurementの報告を担います。
メトリクスAPIで計装されたプロセス内のオブジェクト階層の例を示します。
+-- 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の名前を指定します。例えばInstrumentation Library(io.opentelemetry.contrib.mongodbなど)、パッケージ、モジュール、クラス名です。アプリケーションやライブラリに組み込みのOpenTelemetry計装がある場合、Instrumented libraryと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の作成を担います。
注: Meterは設定の責務を負うべきではありません(SHOULD NOT)。これは代わりにMeterProviderの責務であるべきです。
Meterの操作
Meterは、新しいInstrumentを作成する以下の関数をMUST提供するものとします。
- 新しいCounterの作成
- 新しい非同期Counterの作成
- 新しいHistogramの作成
- 新しいGaugeの作成
- 新しい非同期Gaugeの作成
- 新しいUpDownCounterの作成
- 新しい非同期UpDownCounterの作成
Instrument作成に関するさらなる情報は、以下の各節も参照してください。
Instrument
InstrumentはMeasurementを報告するために使われます。各Instrumentは以下のパラメータを持ちます。
- Instrumentの
name - Instrumentの
kind- Counterか他の種別のいずれか、同期か非同期か - 任意の測定
unit - 任意の
description - 任意の
advisoryパラメータ(mixed)
Instrumentは、作成時にMeterと関連付けられます。Instrumentはname、kind、unit、descriptionによって識別されます。
整数と浮動小数点数の区別のような言語レベルの機能は、識別に関わる要素としてSHOULD考慮されるものとします。
identical(同一)という用語をInstrumentに適用した場合、識別に関わるすべてのフィールドが等しいインスタンスを表します。
一般的な特性
Instrument名の構文
Instrumentの名前の構文は、以下のAugmented Backus-Naur Formを使って定義されます。
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面)をMUSTサポートするものとします。OpenTelemetry APIの作者は、さらに多くのUnicode面をサポートするかどうかを決めてもかまいません(MAY)。 - 少なくとも1023文字をMUSTサポートするものとします。OpenTelemetry APIの作者は、さらに多くをサポートするかどうかを決めてもかまいません(MAY)。
Instrumentのadvisoryパラメータ
ステータス: Mixed
advisoryパラメータは、Instrumentの作者が提供する任意の推奨事項の集合であり、最小限の設定で有用な出力を提供できるよう実装を助けることを目的としています。他のパラメータと異なる点は、実装がadvisoryパラメータを無視してもかまわない(MAY)ことです。
OpenTelemetry SDKは、advisoryパラメータをこちらに記述された通りにMUST処理するものとします。
advisoryパラメータは一般的なものもあれば、特定のInstrumentのkindにのみ受け付けられるものもあります。
Instrument advisoryパラメータ: ExplicitBucketBoundaries
ステータス: Stable
Histogram Instrumentの種別に適用されます。
ExplicitBucketBoundaries(double[])は、明示的バケットHistogramメトリックデータポイントへ集約する場合に使用する、推奨されるバケット境界の集合です。
Instrument advisoryパラメータ: Attributes
ステータス: Development
すべてのInstrumentの種別に適用されます。
Attributes(属性キーのリスト)は、結果として得られるメトリクスに使用することが推奨される属性キーの集合です。
同期Instrumentと非同期Instrument
Instrumentは、同期か非同期かによって分類されます。
同期Instrument(例えばCounter)は、アプリケーション・ビジネス処理ロジックとインラインで呼び出されることを意図しています。例えば、HTTPクライアントは、受信したバイト数を記録するためにCounterを使うことができます。同期Instrumentによって記録されたMeasurementは、Contextに関連付けることができます。
非同期Instrument(例えば非同期Gauge)は、ユーザーがコールバック関数を登録する手段を提供し、そのコールバック関数は必要に応じてのみ呼び出されます(参照として、SDKのcollectionを参照してください)。例えば、組み込みソフトウェアは、15秒ごとにセンサーから温度を収集するために非同期gaugeを使うことができ、これはコールバック関数が15秒ごとにしか呼び出されないことを意味します。非同期Instrumentによって記録されたMeasurementは、Contextに関連付けることができません。
同期と非同期という用語は、非同期パターンとは関係がないことに注意してください。
同期Instrument API
同期Instrumentを構築するAPIは、以下のパラメータをMUST受け付けるものとします。
Instrumentの
name。nameはユーザーによって提供される必要があります。可能であれば、APIはユーザーがこのパラメータを提供することを義務付けるようSHOULD構造化されるものとします。この義務を構造的に強制できない場合、APIはこのパラメータが必要であることをユーザーに伝える形でMUSTドキュメント化されるものとします。APIは、
nameパラメータがInstrument名の構文に準拠する必要があることをユーザーに伝える形でSHOULDドキュメント化されるものとします。APIはnameを検証すべきではなく(SHOULD NOT)、それはAPIの実装(例えばSDK)に委ねられます。測定の
unit。ユーザーは
unitを提供できますが、それはユーザーの裁量に委ねられます。したがって、このAPIはunitを受け付ける形で構造化する必要がありますが、ユーザーにそれを提供することをMUST NOT義務付けるものとします。unitパラメータは、Instrumentの単位のルールをサポートする必要があります。つまり、APIは、ASCII文字エンコーディングをサポートし少なくとも63文字を保持できる、大文字小文字を区別する文字列をMUST受け付けるものとします。APIはunitを検証すべきではありません(SHOULD NOT)。Instrumentを人間が読める形で記述する
description。ユーザーは
descriptionを提供できますが、それはユーザーの裁量に委ねられます。したがって、このAPIはdescriptionを受け付ける形で構造化する必要がありますが、ユーザーにそれを提供することをMUST NOT義務付けるものとします。descriptionはInstrumentの説明のルールをサポートする必要があります。つまり、APIは、少なくともBMP(Unicodeの第0面)でエンコードされた文字をサポートし、少なくとも1023文字を保持できる文字列をMUST受け付けるものとします。Instrumentの
kindに関連付けられたadvisoryパラメータ。ユーザーは
advisoryパラメータを提供できますが、それはユーザーの裁量に委ねられます。したがって、このAPIはadvisoryパラメータを受け付ける形で構造化する必要がありますが、ユーザーにそれを提供することをMUST NOT義務付けるものとします。advisoryパラメータは、instrument advisoryパラメータに記述された通り、一般的なパラメータと特定のInstrumentkindに固有のパラメータとして構造化される必要があります。APIはadvisoryパラメータを検証すべきではありません(SHOULD NOT)。
非同期Instrument API
非同期Instrumentには、Measurementを報告する責務を持つ関連するcallback関数があります。コールバック関数は、Meterが観測されるときにのみ呼び出されます。コールバックの実行順序は規定されていません。
非同期Instrumentを構築するAPIは、以下のパラメータをMUST受け付けるものとします。
Instrumentの
name。nameはユーザーによって提供される必要があります。可能であれば、APIはユーザーがこのパラメータを提供することを義務付けるようSHOULD構造化されるものとします。この義務を構造的に強制できない場合、APIはこのパラメータが必要であることをユーザーに伝える形でMUSTドキュメント化されるものとします。APIは、
nameパラメータがInstrument名の構文に準拠する必要があることをユーザーに伝える形でSHOULDドキュメント化されるものとします。APIはnameを検証すべきではなく(SHOULD NOT)、それはAPIの実装に委ねられます。測定の
unit。ユーザーは
unitを提供できますが、それはユーザーの裁量に委ねられます。したがって、このAPIはunitを受け付ける形で構造化する必要がありますが、ユーザーにそれを提供することをMUST NOT義務付けるものとします。unitパラメータは、Instrumentの単位のルールをサポートする必要があります。つまり、APIは、ASCII文字エンコーディングをサポートし少なくとも63文字を保持できる、大文字小文字を区別する文字列をMUST受け付けるものとします。APIはunitを検証すべきではありません(SHOULD NOT)。Instrumentを人間が読める形で記述する
description。ユーザーは
descriptionを提供できますが、それはユーザーの裁量に委ねられます。したがって、このAPIはdescriptionを受け付ける形で構造化する必要がありますが、ユーザーにそれを提供することをMUST NOT義務付けるものとします。descriptionはInstrumentの説明のルールをサポートする必要があります。つまり、APIは、少なくともBMP(Unicodeの第0面)でエンコードされた文字をサポートし、少なくとも1023文字を保持できる文字列をMUST受け付けるものとします。Instrumentの
kindに関連付けられたadvisoryパラメータ。ユーザーは
advisoryパラメータを提供できますが、それはユーザーの裁量に委ねられます。したがって、このAPIはadvisoryパラメータを受け付ける形で構造化する必要がありますが、ユーザーにそれを提供することをMUST NOT義務付けるものとします。advisoryパラメータは、instrument advisoryパラメータに記述された通り、一般的なパラメータと特定のInstrumentkindに固有のパラメータとして構造化される必要があります。APIはadvisoryパラメータを検証すべきではありません(SHOULD NOT)。作成されたInstrumentの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の作者は、コールバック関数から測定値を捕捉するイディオマティックな方法を決めてもかまいません(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によって使用中のInstrumentを評価するために必要なCallbackのみを実行できます。
APIは、単一のCallbackからの観測が論理的に単一の瞬間に発生しているものとしてMUST扱うものとし、これにより記録される際、単一のコールバックからの観測は同一のタイムスタンプでMUST報告されるものとします。
APIは、コールバックへstateを渡す何らかの方法をSHOULD提供するものとします。OpenTelemetry APIの作者は、イディオマティックな方法を決めてもかまいません(MAY)(例えばコールバック関数への追加のパラメータとする、ラムダのクロージャで捕捉する、その他の方法)。
一般的な操作
すべての同期Instrumentは、以下を行う関数をSHOULD提供するものとします。
すべての同期Instrumentは以下を提供してもかまいません(MAY)。
- (Development)属性の集合へのBind
Enabled
ユーザーが測定値を記録する際に計算コストの高い操作を行うことを避けられるようにするため、同期InstrumentはこのEnabled APIをSHOULD提供するものとします。
このAPIには現在必須のパラメータはありません。将来パラメータが追加される可能性があるため、APIはパラメータを追加できる形でMUST構造化されるものとします。
このAPIは言語にとってイディオマティックなブール型をMUST返すものとします。返り値がtrueの場合、指定された引数に対してInstrumentが有効であることを意味し、falseの場合は指定された引数に対してInstrumentが無効であることを意味します。
返される値は常に静的ではなく、時間とともに変化することがあります。このAPIは、計装作者が最新の応答を得るために測定値を記録するたびにこのAPIを呼び出す必要があるとドキュメント化されるべきです(SHOULD)。
Bind
ステータス: Development
Bind APIは、返される束縛済みInstrumentで記録されるすべての測定値に、固定されたAttributesの集合を関連付けます。属性は各記録時ではなくbind時に解決されるため、実装は記録ごとの属性処理と検索のオーバーヘッドを避けられます。
このAPIは以下のパラメータをMUST受け付けるものとします。
返される束縛済みInstrumentで記録されるすべての測定値に関連付けるAttributes。
ユーザーは束縛済みInstrumentに関連付ける属性を提供できますが、それはユーザーの裁量に委ねられます。したがって、このAPIは、無しの場合を含め可変数の属性を受け付ける形でMUST構造化されるものとします。
このAPIは、それらの属性に束縛されたInstrumentを表す言語イディオマティックな型をMUST返すものとします。
返される束縛済みInstrumentは、そのInstrumentの中核となる記録操作をMUSTサポートするものとします。Instrumentの種別によって、束縛済みInstrument上の記録操作が決まります。
これは、専用の束縛済みInstrument型を導入することで実現してもよく(MAY)、既存のInstrumentインターフェースを再利用することで実現してもかまいません(MAY)。既存のInstrumentインターフェースを再利用する場合、Bind APIは、返される束縛済みInstrument上で属性を伴う記録操作を呼び出すとbindによるパフォーマンス上の利点が失われることをユーザーに伝える形でMUSTドキュメント化されるものとします。
束縛済みInstrumentで記録された測定値は、Contextに関連付けることができます。
OpenTelemetry APIの作者が検討しうる例をいくつか示します。
// 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です。
Counterの使用例:
- 受信したバイト数を数える
- 完了したリクエスト数を数える
- 作成されたアカウント数を数える
- 実行されたチェックポイント数を数える
- HTTP 5xxエラーの数を数える
Counter作成
Meterを使う以外に、Counterを作成するAPIはMUST NOT存在するものとします。これはCreateCounterと呼んでもかまいません(MAY)。強い型付けが望まれる場合、OpenTelemetry APIの作者は、例えばCreateUInt64Counter、CreateDoubleCounter、CreateCounter<UInt64>、CreateCounter<double>のような言語にとってイディオマティックな名前を決めてもかまいません(MAY)。
同期Instrumentの一般的な要件を参照してください。
OpenTelemetry APIの作者が検討しうる例をいくつか示します。
# Python
exception_counter = meter.create_counter(name="exceptions", description="number of exceptions caught", value_type=int)
// 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。
ユーザーは増分値に関連付ける属性を提供できますが、それはユーザーの裁量に委ねられます。したがって、このAPIは、無しの場合を含め可変数の属性を受け付ける形でMUST構造化されるものとします。
OpenTelemetry APIの作者は、柔軟な属性を引数として渡すことを許容してもかまいません(MAY)。属性の名前と型がcounter作成時に提供される場合、OpenTelemetry APIの作者は、より効率的な方法(例えばコールスタック上に確保される強く型付けされた構造体、タプルなど)で属性値を渡すことを許容してもかまいません(MAY)。APIは、Instrument作成時にすべての可能な属性名を登録する代わりに、呼び出し元が呼び出し時に柔軟な属性を提供することをMUST許容するものとします。OpenTelemetry APIの作者が検討しうる例をいくつか示します。
# Python
exception_counter.add(1, {"exception_type": "IOError", "handled_by_user": True})
exception_counter.add(1, exception_type="IOError", handled_by_user=True)
// 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が観測される際に単調に増加する値を報告する非同期Instrumentです。
非同期Counterの使用例:
非同期Counter作成
Meterを使う以外に、非同期Counterを作成するAPIはMUST NOT存在するものとします。これはCreateObservableCounterと呼んでもかまいません(MAY)。強い型付けが望まれる場合、OpenTelemetry APIの作者は、例えばCreateUInt64ObservableCounter、CreateDoubleObservableCounter、CreateObservableCounter<UInt64>、CreateObservableCounter<double>のような言語にとってイディオマティックな名前を決めてもかまいません(MAY)。
強い理由がない限り、ObservableCounter(あるいはobservable_counterのような言語にとってイディオマティックな変種)という名前を使うことが強く推奨されます。この名前は、非同期パターンやオブザーバーパターンとは何の関係もないことに注意してください。
非同期Instrumentの一般的な要件を参照してください。
注: 増分・差分の値を取るCounter.Add()とは異なり、コールバック関数はcounterの絶対値を報告します。counterの変化率を求めるには、連続する測定値の差分が使われます。
OpenTelemetry APIの作者は、イディオマティックな方法を決めてもかまいません(MAY)。以下にいくつかの例を示します。
Measurementのリスト(あるいはタプル、ジェネレーター、列挙子など)を返す。- observable resultの引数を使って、個々の
Measurementを報告できるようにする。
ユーザーコードは、1回のコールバック内で同じattributesを持つ複数のMeasurementを提供しないことが推奨されます。もしそれが発生した場合、OpenTelemetry SDKの作者は、それをSDKでどう処理するかを決めてもかまいません(MAY)。例えば、コールバックの呼び出し中にvalue=1, attributes={pid:4, bitness:64}とvalue=2, attributes={pid:4, bitness:64}という2つの測定値が報告された場合、OpenTelemetry SDKの作者は、単純にそれらをそのまま通過させる(下流のコンシューマーが重複を処理できるようにする)か、データ全体をドロップするか、最後の値を選ぶか、その他の方法を決めてもかまいません(MAY)。APIは、単一のコールバックからの観測が論理的に単一の瞬間に発生しているものとしてMUST扱うものとし、これにより記録される際、単一のコールバックからの観測は同一のタイムスタンプでMUST報告されるものとします。
APIは、コールバックへstateを渡す何らかの方法をSHOULD提供するものとします。OpenTelemetry APIの作者は、イディオマティックな方法を決めてもかまいません(MAY)(例えばコールバック関数への追加のパラメータとする、ラムダのクロージャで捕捉する、その他の方法)。
OpenTelemetry APIの作者が検討しうる例をいくつか示します。
# 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
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)
// 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作成時に登録されるcallbackを通じて測定値を報告するイディオマティックなインターフェースを使います。
非同期Instrument作成後に登録されるコールバック関数については、APIは登録解除の仕組みをサポートすることが要求されます。例えば、register_callbackから返されるオブジェクトが、unregister()メソッドを直接サポートできます。
# 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です。ヒストグラム、サマリー、パーセンタイルといった統計量を意図しています。
Histogramの使用例:
- リクエストの所要時間
- レスポンスペイロードのサイズ
Histogram作成
Meterを使う以外に、Histogramを作成するAPIはMUST NOT存在するものとします。これはCreateHistogramと呼んでもかまいません(MAY)。強い型付けが望まれる場合、OpenTelemetry APIの作者は、例えばCreateUInt64Histogram、CreateDoubleHistogram、CreateHistogram<UInt64>、CreateHistogram<double>のような言語にとってイディオマティックな名前を決めてもかまいません(MAY)。
同期Instrumentの一般的な要件を参照してください。
OpenTelemetry APIの作者が検討しうる例をいくつか示します。
# 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)
// 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。
ユーザーは値に関連付ける属性を提供できますが、それはユーザーの裁量に委ねられます。したがって、このAPIは、無しの場合を含め可変数の属性を受け付ける形でMUST構造化されるものとします。
OpenTelemetry APIの作者は、柔軟な属性を個々の引数として渡すことを許容してもかまいません(MAY)。OpenTelemetry APIの作者は、より効率的な方法(例えばコールスタック上に確保される強く型付けされた構造体、タプルなど)で属性値を渡すことを許容してもかまいません(MAY)。OpenTelemetry APIの作者が検討しうる例をいくつか示します。
# Python
http_server_duration.Record(50, {"http.request.method": "POST", "url.scheme": "https"})
http_server_duration.Record(100, http_method="GET", http_scheme="http")
// C#
httpServerDuration.Record(50, ("http.request.method", "POST"), ("url.scheme", "https"));
httpServerDuration.Record(100, new HttpRequestAttributes { method = "GET", scheme = "http" });
Gauge
Gaugeは、変化が生じたときに加算的でない値(例えばバックグラウンドの騒音レベル - 複数の部屋の騒音レベルの値を記録して合計することには意味がありません)を記録するために使える同期Instrumentです。
注: 値が加算的である場合(例えばプロセスのヒープサイズ - 複数のプロセスからヒープサイズを報告して合計し、全体のヒープ使用量を得ることには意味があります)は、UpDownCounterを使ってください。
注: 同期Gaugeは通常、変更イベントへのサブスクリプションを通じて測定値が公開される場合に使われます(すなわちbackgroundNoiseLevel.onChange(value -> gauge.record(value)))。測定値がアクセサを介して公開される場合は、非同期Gaugeを使って、コールバック関数内でアクセサを呼び出してください(すなわちcreateObservableGauge(observable -> observable.record(backgroundNoiseLevel.getCurrentValue())))。
Gaugeの使用例:
- バックグラウンドの騒音レベルの変更イベントへのサブスクリプション
- CPUファン速度の変更イベントへのサブスクリプション
Gauge作成
Meterを使う以外に、Gaugeを作成するAPIはMUST NOT存在するものとします。これはCreateGaugeと呼んでもかまいません(MAY)。強い型付けが望まれる場合、OpenTelemetry APIの作者は、例えばCreateUInt64Gauge、CreateDoubleGauge、CreateGauge<UInt64>、CreateGauge<double>のような言語にとってイディオマティックな名前を決めてもかまいません(MAY)。
同期Instrumentの一般的な要件を参照してください。
OpenTelemetry APIの作者が検討しうる例をいくつか示します。
// 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。
ユーザーは値に関連付ける属性を提供できますが、それはユーザーの裁量に委ねられます。したがって、このAPIは、無しの場合を含め可変数の属性を受け付ける形でMUST構造化されるものとします。
OpenTelemetry APIの作者は、柔軟な属性を引数として渡すことを許容してもかまいません(MAY)。属性の名前と型がgauge作成時に提供される場合、OpenTelemetry APIの作者は、より効率的な方法(例えばコールスタック上に確保される強く型付けされた構造体、タプルなど)で属性値を渡すことを許容してもかまいません(MAY)。APIは、Instrument作成時にすべての可能な属性名を登録する代わりに、呼び出し元が呼び出し時に柔軟な属性を提供することをMUST許容するものとします。OpenTelemetry APIの作者が検討しうる例をいくつか示します。
// 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です。
注: 値が加算的な場合(例えばプロセスのヒープサイズ - 複数のプロセスからヒープサイズを報告して合計し、全体のヒープ使用量を得ることには意味があります)は、非同期Counterや非同期UpDownCounterを使ってください。
非同期Gaugeの使用例:
- 現在の部屋の温度
- CPUファン速度
非同期Gauge作成
Meterを使う以外に、非同期Gaugeを作成するAPIはMUST NOT存在するものとします。これはCreateObservableGaugeと呼んでもかまいません(MAY)。強い型付けが望まれる場合、OpenTelemetry APIの作者は、例えばCreateUInt64ObservableGauge、CreateDoubleObservableGauge、CreateObservableGauge<UInt64>、CreateObservableGauge<double>のような言語にとってイディオマティックな名前を決めてもかまいません(MAY)。
強い理由がない限り、ObservableGauge(あるいはobservable_gaugeのような言語にとってイディオマティックな変種)という名前を使うことが強く推奨されます。この名前は、非同期パターンやオブザーバーパターンとは何の関係もないことに注意してください。
非同期Instrumentの一般的な要件を参照してください。
OpenTelemetry APIの作者が検討しうる例をいくつか示します。
# 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
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)
// C#
// A simple scenario where only one value is reported
meter.CreateObservableGauge<double>("temperature", () => sensor.GetTemperature());
非同期Gaugeの操作
非同期Gaugeは、非同期Gauge作成時に登録されるcallbackを通じて測定値を報告するイディオマティックなインターフェースを使います。
非同期Instrument作成後に登録されるコールバック関数については、APIは登録解除の仕組みをサポートすることが要求されます。例えば、register_callbackから返されるオブジェクトが、unregister()メソッドを直接サポートできます。
# 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です。
注: 値が単調に増加する場合は、代わりにCounterを使ってください。
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
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を使う以外に、UpDownCounterを作成するAPIはMUST NOT存在するものとします。これはCreateUpDownCounterと呼んでもかまいません(MAY)。強い型付けが望まれる場合、OpenTelemetry APIの作者は、例えばCreateInt64UpDownCounter、CreateDoubleUpDownCounter、CreateUpDownCounter<Int64>、CreateUpDownCounter<double>のような言語にとってイディオマティックな名前を決めてもかまいません(MAY)。
同期Instrumentの一般的な要件を参照してください。
OpenTelemetry APIの作者が検討しうる例をいくつか示します。
# Python
customers_in_store = meter.create_up_down_counter(
name="grocery.customers",
description="measures the current customers in the grocery store",
value_type=int)
// 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。
ユーザーは値に関連付ける属性を提供できますが、それはユーザーの裁量に委ねられます。したがって、このAPIは、無しの場合を含め可変数の属性を受け付ける形でMUST構造化されるものとします。
OpenTelemetry APIの作者は、柔軟な属性を個々の引数として渡すことを許容してもかまいません(MAY)。OpenTelemetry APIの作者は、より効率的な方法(例えばコールスタック上に確保される強く型付けされた構造体、タプルなど)で属性値を渡すことを許容してもかまいません(MAY)。OpenTelemetry APIの作者が検討しうる例をいくつか示します。
# Python
customers_in_store.add(1, {"account.type": "commercial"})
customers_in_store.add(-1, account_type="residential")
// C#
customersInStore.Add(1, ("account.type", "commercial"));
customersInStore.Add(-1, new Account { Type = "residential" });
非同期UpDownCounter
非同期UpDownCounterは、Instrumentが観測される際に加算的な値(例えばプロセスのヒープサイズ - 複数のプロセスからヒープサイズを報告して合計し、全体のヒープ使用量を得ることには意味があります)を報告する非同期Instrumentです。
注: 値が単調に増加する場合は代わりに非同期Counterを使ってください。値が非加算的な場合は代わりに非同期Gaugeを使ってください。
非同期UpDownCounterの使用例:
- プロセスのヒープサイズ
- ロックフリーな循環バッファ内のアイテムのおおよその数
非同期UpDownCounter作成
Meterを使う以外に、非同期UpDownCounterを作成するAPIはMUST NOT存在するものとします。これはCreateObservableUpDownCounterと呼んでもかまいません(MAY)。強い型付けが望まれる場合、OpenTelemetry APIの作者は、例えばCreateUInt64ObservableUpDownCounter、CreateDoubleObservableUpDownCounter、CreateObservableUpDownCounter<UInt64>、CreateObservableUpDownCounter<double>のような言語にとってイディオマティックな名前を決めてもかまいません(MAY)。
強い理由がない限り、ObservableUpDownCounter(あるいはobservable_up_down_counterのような言語にとってイディオマティックな変種)という名前を使うことが強く推奨されます。この名前は、非同期パターンやオブザーバーパターンとは何の関係もないことに注意してください。
非同期Instrumentの一般的な要件を参照してください。
注: 増分・差分の値を取るUpDownCounter.Add()とは異なり、コールバック関数は非同期UpDownCounterの絶対値を報告します。非同期UpDownCounterの変化率を求めるには、連続する測定値の差分が使われます。
OpenTelemetry APIの作者が検討しうる例をいくつか示します。
# 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
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)
// C#
// A simple scenario where only one value is reported
meter.CreateObservableUpDownCounter<UInt64>("memory.physical.free", () => WMI.Query("FreePhysicalMemory"));
非同期UpDownCounterの操作
非同期UpDownCounterは、非同期Updowncounter作成時に登録されるcallbackを通じて測定値を報告するイディオマティックなインターフェースを使います。
非同期Instrument作成後に登録されるコールバック関数については、APIは登録解除の仕組みをサポートすることが要求されます。例えば、register_callbackから返されるオブジェクトが、unregister()メソッドを直接サポートできます。
# 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間の相互作用についてはメトリクスのプログラミングモデルを参照してください。
Measurementは以下をカプセル化します。
複数Instrumentに対応するコールバック
メトリクスAPIは、単一の登録済みCallbackから複数のInstrumentを使用できるインターフェースをサポートしてもかまいません(MAY)。新しいCallbackを登録するAPIは、以下をSHOULD受け付けるものとします。
callback関数callback関数内で使われるInstrumentのリスト(あるいはタプルなど)。
APIの作者は、callback関数について以下のいずれかの形式を使うことがRECOMMENDEDです。
callback関数が返すリスト(あるいはタプルなど)が(Instrument, Measurement)のペアを含む。- Observable Resultの引数が追加の
(Instrument, Measurement)のペアを受け取る。
このインターフェースは、/procファイルの読み取りやガベージコレクションサブシステムの調査のような、コストの高いプロセスを通じて得られる複数の測定値を報告する際に、通常より高性能な方法となります。
例を示します。
# 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の統合
- OTEP0008 メトリクスオブザーバー仕様
- OTEP0009 メトリックハンドルAPI仕様
- OTEP0010 メトリクスAPIにおける「Cumulative」の「Counter」への改名
- OTEP0049 メトリック
LabelSet仕様 - OTEP0070 メトリックInstrumentのHandleの「Bound Instrument」への改名
- OTEP0072 メトリクスオブザーバー仕様(改訂)
- OTEP0080 メトリクスAPIからのGauge Instrumentの削除
- OTEP0088 メトリックInstrument
- OTEP0090 メトリクスAPIからのLabelSetオブジェクトの削除
- OTEP0098 メトリックInstrumentの説明
- OTEP0108 メトリックInstrumentの命名ガイドライン
- OTEP0146 メトリクスAPI/SDKプロトタイピングのシナリオ