2012年に作成されたPrometheusは、2015年以来クラウドネイティブな可観測性のデフォルトとなっています。Prometheusの設計の中心的な部分は、2014年以来安定しているPrometheus公開フォーマット0.0.4と呼ばれるテキストメトリック公開フォーマットです。このフォーマットでは、生成、取り込み、人間による理解を容易にするために特別な配慮がなされています。2020年現在、700以上の公開エクスポーター、数不明の未公開エクスポーター、そして数千のネイティブライブラリ統合がこのフォーマットを使用しています。様々なプロジェクトや企業の数十のインジェスターがその消費をサポートしています。
OpenMetricsでは、IETFに導入することを明確な目的として、仕様の整理と厳格化を進めています。広範かつ自然に採用されている動作中の標準を文書化しつつ、最小限で、ほとんどが後方互換性があり、よく検討された変更を導入しています。2020年現在、すでに多数のエクスポーター、統合、インジェスターがOpenMetricsを使用し、優先的にネゴシエーションしています。
エコシステムにおける広範な採用と重要な調整要件を考慮すると、Prometheus公開フォーマット0.0.4またはOpenMetrics 1.0のいずれかに対する抜本的な変更は、スコープ外とみなされます。
注: OpenMetrics 2.0の開発が進行中です。Prometheus OM 2.0ワーキンググループへの参加方法については、こちらをお読みください。
メトリックは、特定の種類のテレメトリデータです。それらは、データセットの現在の状態のスナップショットを表します。個々のイベントに関するレコードや情報に焦点を当てるログやイベントとは異なります。
OpenMetricsは、主にワイヤーフォーマットであり、そのフォーマットのための特定のトランスポートから独立しています。このフォーマットは、定期的に消費され、連続する公開にわたって意味を持つことが期待されます。
実装者は、特定のプロセスまたはデバイスの文書化されたURLへの単純なHTTP GETリクエストに応答して、OpenMetricsテキストフォーマットでメトリックを公開しなければなりません(MUST)。このエンドポイントは「/metrics」と呼ぶべきです(SHOULD)。実装者は、HTTP経由でオペレーターが構成したエンドポイントにメトリックセットを定期的にプッシュするなど、他の方法でOpenMetrics形式のメトリックを公開してもよいです(MAY)。
この標準は、すべてのシステム状態を数値として表現します。カウント、現在の値、列挙、ブール状態が一般的な例です。メトリックとは異なり、単一のイベントは特定の時刻に発生します。メトリックはデータを時間的に集計する傾向があります。これにより情報が失われる可能性がありますが、オーバーヘッドの削減は、多くの最新の監視システムで一般的に選択されるエンジニアリング上のトレードオフです。
時系列は、時間経過とともに変化する情報の記録です。時系列は任意の文字列やバイナリデータをサポートできますが、このRFCのスコープ内にあるのは数値データのみです。
メトリック時系列の一般的な例としては、ネットワークインターフェースカウンター、デバイス温度、BGP接続状態、アラート状態などがあります。
このセクションは、ABNFセクションと合わせて読まなければなりません(MUST)。両者の間に不一致がある場合、ABNFの制約が優先しなければなりません(MUST)。これは、テキストワイヤーフォーマットがサポートされなければならない(MUST)ため、繰り返しを減らします。
OpenMetricsにおけるメトリック値は、浮動小数点数または整数でなければなりません(MUST)。このフォーマットのインジェスターはfloat64のみをサポートしてもよい(MAY)ことに注意してください。非実数値であるNaN、+Inf、-Infはサポートされなければなりません(MUST)。NaNは欠損値とみなしてはならず(MUST NOT)、ゼロ除算を示すために使用されてもよいです(MAY)。
ブール値は1==true
、0==false
に従わなければなりません(MUST)。
タイムスタンプはUnixエポック秒でなければなりません(MUST)。負のタイムスタンプを使用してもよいです(MAY)。
文字列は、有効なUTF-8文字のみで構成されなければならず(MUST)、長さがゼロであってもよいです(MAY)。NULL (ASCII 0x0) はサポートされなければなりません(MUST)。
ラベルは、文字列で構成されるキーと値のペアです。
アンダースコアで始まるラベル名は予約されており(RESERVED)、この標準で指定されていない限り使用してはなりません(MUST NOT)。ラベル名はABNFセクションの制約に従わなければなりません(MUST)。
空のラベル値は、ラベルが存在しなかったかのように扱われるべきです(SHOULD)。
LabelSetはラベルで構成されなければならず(MUST)、空であってもよいです(MAY)。ラベル名はLabelSet内で一意でなければなりません(MUST)。
各MetricPointは、MetricFamilyのタイプに応じて、一連の値で構成されます。
エグゼンプラは、MetricSet外のデータへの参照です。一般的なユースケースは、プログラムトレースのIDです。
エグゼンプラはLabelSetと値で構成されなければならず(MUST)、タイムスタンプを持ってもよいです(MAY)。それらはMetricPointのLabelSetおよびタイムスタンプとはそれぞれ異なっていてもよいです(MAY)。
ExemplarのLabelSetのラベル名と値の合計長は、128 UTF-8文字コードポイントを超えてはなりません(MUST NOT)。実装の簡素化とテキストフォーマットとプロトフォーマット間の一貫性のために、エグゼンプラのテキストレンダリングにおける",=
などの他の文字はこの制限に含まれません。
インジェスターはエグゼンプラを破棄してもよいです(MAY)。
メトリックは、MetricFamily内で一意のLabelSetによって定義されます。メトリックは、1つ以上のMetricPointのリストを含まなければなりません(MUST)。特定のMetricFamilyに対して同じ名前を持つメトリックは、そのLabelSet内で同じラベル名のセットを持つべきです(SHOULD)。
MetricPointは明示的なタイムスタンプを持つべきではありません(SHOULD NOT)。
メトリックに対して複数のMetricPointが公開される場合、そのMetricPointは単調増加するタイムスタンプを持たなければなりません(MUST)。
MetricFamilyはゼロ以上のメトリックを持ってもよいです(MAY)。MetricFamilyは、名前、HELP、TYPE、およびUNITのメタデータを持たなければなりません(MUST)。MetricFamily内のすべてのメトリックは、一意のLabelSetを持たなければなりません(MUST)。
MetricFamily名は文字列であり、MetricSet内で一意でなければなりません(MUST)。名前はsnake_caseであるべきです(SHOULD)。メトリック名はABNFセクションの制約に従わなければなりません(MUST)。
MetricFamily名に含まれるコロンは、そのMetricFamilyが汎用監視システムの計算または集計の結果であることを示すために予約されています(RESERVED)。
アンダースコアで始まるMetricFamily名は予約されており(RESERVED)、この標準で指定されていない限り使用してはなりません(MUST NOT)。
MetricFamilyの名前は、MetricSet内のテキストフォーマットで、ABNFに従うサンプルメトリック名と他のMetricFamilyの間で潜在的な衝突を引き起こしてはなりません(MUST NOT)。例として、「foo_created」というゲージは、「foo」というカウンターとしてテキストフォーマットで「foo_created」を作成する可能性があります。
エクスポーターは、テキストフォーマットのサンプルメトリック名が使用するサフィックスと混同される可能性のある名前を避けるべきです(SHOULD)。
_total
, _created
_count
, _sum
, _created
, `` (空)_count
, _sum
, _bucket
, _created
_gcount
, _gsum
, _bucket
_info
TypeはMetricFamilyのタイプを指定します。有効な値は「unknown」、「gauge」、「counter」、「stateset」、「info」、「histogram」、「gaugehistogram」、「summary」です。
UnitはMetricFamilyの単位を指定します。空でない場合、アンダースコアで区切られたMetricFamily名のサフィックスでなければなりません(MUST)。さらに、生成ルールによっては、テキストフォーマットでインフィックスになる可能性があることに注意してください。
Helpは文字列であり、空ではないべきです(SHOULD)。これは、人間が理解するためのMetricFamilyの簡単な説明を提供するために使用され、ツールチップとして使用できるほど短いべきです(SHOULD)。
MetricSetは、OpenMetricsによって公開されるトップレベルのオブジェクトです。これはMetricFamilyで構成されなければならず(MUST)、空であってもよいです(MAY)。
各MetricFamily名は一意でなければなりません(MUST)。同じラベル名と値がMetricSet内のすべてのメトリックに表示されるべきではありません(SHOULD NOT)。
MetricSet内でMetricFamilyの特定の順序は必要ありません。エクスポーターは、たとえばパフォーマンスのトレードオフが妥当であればアルファベット順にソートするなど、人間にとって公開を読みやすくしてもよいです(MAY)。
存在する場合、以下の「プッシュベースとプルベースの両方のシステムでターゲットメタデータをサポートする」セクションに従って、「target」というInfo MetricFamilyが最初であるべきです(SHOULD)。
ゲージは、現在使用されているメモリのバイト数やキュー内のアイテム数など、現在の測定値です。ゲージにとって、絶対値がユーザーにとって関心のあるものです。
ゲージタイプのメトリック内のMetricPointは、単一の値を持たなければなりません(MUST)。
ゲージは時間とともに増加、減少、または一定のままであってもよいです(MAY)。たとえ一方向にしか進まなくても、カウンターではなくゲージである可能性があります。ログファイルのサイズは通常増加するだけであり、リソースは減少する可能性があり、キューサイズの制限は一定である場合があります。
ゲージは、列挙型が多くの状態を持ち、時間とともに変化する場合に、列挙型をエンコードするために使用してもよいです(MAY)。これは最も効率的ですが、最もユーザーフレンドリーではありません。
カウンターは、個別のイベントを測定します。一般的な例としては、受信したHTTPリクエスト数、CPU使用秒数、送信バイト数などがあります。カウンターにとって、時間経過とともにどれだけ速く増加しているかがユーザーにとって関心のあることです。
カウンタータイプのメトリック内のMetricPointは、Totalという1つの値を持たなければなりません(MUST)。Totalは非NaNであり、0から始まり、時間とともに単調に減少しない値でなければなりません(MUST)。
カウンタータイプのメトリック内のMetricPointは、Createdというタイムスタンプ値を持つべきです(SHOULD)。これは、インジェスターが新しいメトリックと以前に見たことのない長期間実行されているメトリックとを区別するのに役立ちます。
メトリックのカウンターの合計値におけるMetricPointは、0にリセットされてもよいです(MAY)。存在する場合、対応するCreated時間はリセットのタイムスタンプに設定されなければなりません(MUST)。
メトリックのカウンターの合計値におけるMetricPointは、エグゼンプラを持ってもよいです(MAY)。
StateSetは、ビットセットとも呼ばれる一連の関連するブール値を表します。列挙型をエンコードする必要がある場合、これはStateSetを介して行ってもよいです(MAY)。
StateSetメトリックのポイントは複数の状態を含んでもよく(MAY)、状態ごとに1つのブール値を含まなければなりません(MUST)。状態は文字列である名前を持ちます。
StateSetメトリックのLabelSetは、そのMetricFamilyの名前と同じラベル名を持ってはなりません(MUST NOT)。
StateSetとしてエンコードされる場合、列挙型はMetricPoint内で厳密に1つの真のブール値を持たなければなりません(MUST)。
これは、列挙値が時間とともに変化し、状態の数が数個をはるかに超えない場合に適しています。
StateSetタイプのMetricFamilyは、空のUnit文字列を持たなければなりません(MUST)。
情報メトリックは、プロセスライフサイクル中に変更すべきではない(SHOULD NOT)テキスト情報を公開するために使用されます。一般的な例としては、アプリケーションのバージョン、リビジョン管理コミット、コンパイラのバージョンなどがあります。
情報メトリックのMetricPointはLabelSetを含みます。情報MetricPointのLabelSetは、そのメトリックのLabelSetのラベルの名前と同じラベル名を持ってはなりません(MUST NOT)。
情報メトリックは、ネットワークインターフェースのタイプなど、時間とともに値が変化しない列挙型をエンコードするために使用してもよいです(MAY)。
InfoタイプのMetricFamilyは、空のUnit文字列を持たなければなりません(MUST)。
ヒストグラムは、個別のイベントの分布を測定します。一般的な例としては、HTTPリクエストのレイテンシー、関数の実行時間、I/Oリクエストサイズなどがあります。
ヒストグラムのMetricPointは、少なくとも1つのバケットを含まなければならず(MUST)、SumおよびCreated値を含むべきです(SHOULD)。すべてのバケットは、しきい値と値を持たなければなりません(MUST)。
ヒストグラムのMetricPointは、+Infのしきい値を持つ1つのバケットを持たなければなりません(MUST)。バケットは累積的でなければなりません(MUST)。例えば、秒単位の要求レイテンシーを表すメトリックの場合、しきい値が1、2、3、+Infのバケットの値は、value_1 <= value_2 <= value_3 <= value_+Infに従わなければなりません(MUST)。10個の要求がそれぞれ1秒かかった場合、1、2、3、+Infのバケットの値は10と等しくなければなりません(MUST)。
+Infバケットはすべてのリクエストをカウントします。存在する場合、Sum値は測定されたすべてのイベント値の合計と等しくなければなりません(MUST)。MetricPoint内のバケットのしきい値は一意でなければなりません(MUST)。
意味的に、Sumおよびバケット値はカウンターであるため、NaNまたは負であってはなりません(MUST NOT)。負のしきい値バケットを使用してもよいですが(MAY)、その場合、ヒストグラムのMetricPointは、意味的にカウンターではなくなるため、合計値を含んではなりません(MUST NOT)。バケットのしきい値はNaNと等しくなってはなりません(MUST NOT)。カウントおよびバケット値は整数でなければなりません(MUST)。
ヒストグラムのMetricPointは、Createdというタイムスタンプ値を持つべきです(SHOULD)。これは、インジェスターが新しいメトリックと以前に見たことのない長期間実行されているメトリックとを区別するのに役立ちます。
ヒストグラムのメトリックのLabelSetは、「le」というラベル名を持ってはなりません(MUST NOT)。
バケット値はエグゼンプラを持ってもよいです(MAY)。バケットは累積的であるため、監視システムは、パフォーマンス/サービス妨害対策の理由で、粒度が失われても有効なヒストグラムである限り、+Inf以外のバケットを破棄することができます。
各バケットは、それ以下の値をカバーし、エグゼンプラの値はこの範囲内になければなりません(MUST)。エグゼンプラは最も高い値のバケットに入れられるべきです(SHOULD)。バケットは複数のエグゼンプラを持ってはなりません(MUST NOT)。
ゲージヒストグラムは、現在の分布を測定します。一般的な例としては、アイテムがキューで待機している時間や、キュー内のリクエストのサイズなどがあります。
ゲージヒストグラムのMetricPointは、+Infのしきい値を持つ1つのバケットを持たなければならず(MUST)、Gsum値を含むべきです(SHOULD)。すべてのバケットは、しきい値と値を持たなければなりません(MUST)。
ゲージヒストグラムのバケットは、ヒストグラムと同じすべてのルールに従います。
ゲージヒストグラムのバケットとGsumは概念的にはゲージですが、バケット値は負またはNaNであってはなりません(MUST NOT)。負のしきい値バケットが存在する場合、合計は負であってもよいです(MAY)。GsumはNaNであってはなりません(MUST NOT)。バケット値は整数でなければなりません(MUST)。
ゲージヒストグラムのメトリックのLabelSetは、「le」というラベル名を持ってはなりません(MUST NOT)。
バケット値はエグゼンプラを持ってもよいです。
各バケットは、それ以下の値をカバーし、エグゼンプラの値はこの範囲内になければなりません(MUST)。エグゼンプラは最も高い値のバケットに入れられるべきです(SHOULD)。バケットは複数のエグゼンプラを持ってはなりません(MUST NOT)。
サマリーも個別のイベントの分布を測定し、ヒストグラムが高価すぎる場合や、平均イベントサイズで十分な場合に使用してもよいです(MAY)。
既存のいくつかの計測ライブラリが事前に計算されたクオンタイルを公開し、ヒストグラムをサポートしていないため、後方互換性のために使用してもよいです(MAY)。クオンタイルは集計可能ではなく、ユーザーがカバーする時間枠を推測できないことが多いため、事前に計算されたクオンタイルを使用すべきではありません(SHOULD NOT)。
サマリーのMetricPointは、Count、Sum、Created、および一連のクオンタイルで構成されてもよいです(MAY)。
意味的に、CountとSum値はカウンターであるため、NaNまたは負であってはなりません(MUST NOT)。Countは整数でなければなりません(MUST)。
CountまたはSum値を含むサマリータイプのメトリック内のMetricPointは、Createdというタイムスタンプ値を持つべきです(SHOULD)。これは、インジェスターが新しいメトリックと以前に見たことのない長期間実行されているメトリックとを区別するのに役立ちます。Createdは、クオンタイル値の収集期間に関連してはなりません(MUST NOT)。
クオンタイルは、クオンタイルから値へのマップです。例として、myapp_http_request_duration_secondsというメトリックにおける、値が0.2のクオンタイル0.95があります。これは、95パーセンタイルレイテンシーが未知の時間枠で200msであることを意味します。関連する時間枠にイベントがない場合、クオンタイルの値はNaNでなければなりません(MUST)。クオンタイルのメトリックのLabelSetは「quantile」というラベル名を持ってはなりません(MUST NOT)。クオンタイルは0から1まで(両端を含む)でなければなりません(MUST)。クオンタイル値は負であってはなりません(MUST NOT)。クオンタイル値は最近の値を表すべきです(SHOULD)。通常、これは過去5〜10分間です。
Unknownは使用すべきではありません(SHOULD NOT)。Unknownは、サードパーティシステムから個々のメトリックのタイプを決定することが不可能な場合に使用してもよいです(MAY)。
不明なタイプのメトリックのポイントは、単一の値を持たなければなりません(MUST)。
テキストワイヤーフォーマットはサポートされなければならず(MUST)、デフォルトです。Protobufワイヤーフォーマットはサポートされてもよいですが(MAY)、ネゴシエーション後にのみ使用されなければなりません(MUST ONLY)。
OpenMetricsフォーマットは正規チョムスキー文法であり、迅速かつ小型のパーサーの作成を可能にします。テキストフォーマットは良好に圧縮され、Protobufはすでにバイナリであり効率的にエンコードされています。
部分的または無効な公開は、全体としてエラーとみなされなければなりません(MUST)。
すべてのインジェスター実装は、TLS 1.2以降で保護されたデータを取り込むことができなければなりません(MUST)。すべてのエクスポーターは、TLS 1.2以降で保護されたデータを発信できるべきです(SHOULD)。インジェスター実装は、TLSなしでHTTPからデータを取り込むことができるべきです(SHOULD)。すべての実装は、データを送信するためにTLSを使用すべきです(SHOULD)。
使用するOpenMetricsフォーマットのバージョンのネゴシエーションは帯域外で行われます。例えば、HTTP経由のプルベースの公開では、標準のHTTPコンテンツタイプネゴシエーションが使用され、新しいバージョンが要求されない場合、標準の最も古いバージョン(つまり1.0.0)にデフォルトで設定されなければなりません(MUST)。
プッシュベースのネゴシエーションは、エクスポーターが通常接続を開始するため、本質的に複雑です。プロデューサーは、インジェスターによって別途要求されない限り、標準の最も古いバージョン(つまり1.0.0)を使用しなければなりません(MUST)。
RFC 5234に準拠したABNF
「exposition」はABNFのトップレベルトークンです。
exposition = metricset HASH SP eof [ LF ]
metricset = *metricfamily
metricfamily = *metric-descriptor *metric
metric-descriptor = HASH SP type SP metricname SP metric-type LF
metric-descriptor =/ HASH SP help SP metricname SP escaped-string LF
metric-descriptor =/ HASH SP unit SP metricname SP *metricname-char LF
metric = *sample
metric-type = counter / gauge / histogram / gaugehistogram / stateset
metric-type =/ info / summary / unknown
sample = metricname [labels] SP number [SP timestamp] [exemplar] LF
exemplar = SP HASH SP labels SP number [SP timestamp]
labels = "{" [label *(COMMA label)] "}"
label = label-name EQ DQUOTE escaped-string DQUOTE
number = realnumber
; Case insensitive
number =/ [SIGN] ("inf" / "infinity")
number =/ "nan"
timestamp = realnumber
; Not 100% sure this captures all float corner cases.
; Leading 0s explicitly okay
realnumber = [SIGN] 1*DIGIT
realnumber =/ [SIGN] 1*DIGIT ["." *DIGIT] [ "e" [SIGN] 1*DIGIT ]
realnumber =/ [SIGN] *DIGIT "." 1*DIGIT [ "e" [SIGN] 1*DIGIT ]
; RFC 5234 is case insensitive.
; Uppercase
eof = %d69.79.70
type = %d84.89.80.69
help = %d72.69.76.80
unit = %d85.78.73.84
; Lowercase
counter = %d99.111.117.110.116.101.114
gauge = %d103.97.117.103.101
histogram = %d104.105.115.116.111.103.114.97.109
gaugehistogram = gauge histogram
stateset = %d115.116.97.116.101.115.101.116
info = %d105.110.102.111
summary = %d115.117.109.109.97.114.121
unknown = %d117.110.107.110.111.119.110
BS = "\"
EQ = "="
COMMA = ","
HASH = "#"
SIGN = "-" / "+"
metricname = metricname-initial-char 0*metricname-char
metricname-char = metricname-initial-char / DIGIT
metricname-initial-char = ALPHA / "_" / ":"
label-name = label-name-initial-char *label-name-char
label-name-char = label-name-initial-char / DIGIT
label-name-initial-char = ALPHA / "_"
escaped-string = *escaped-char
escaped-char = normal-char
escaped-char =/ BS ("n" / DQUOTE / BS)
escaped-char =/ BS normal-char
; Any unicode character, except newline, double quote, and backslash
normal-char = %x00-09 / %x0B-21 / %x23-5B / %x5D-D7FF / %xE000-10FFFF
UTF-8を使用しなければなりません(MUST)。バイトオーダーマーク(BOM)を使用してはなりません(MUST NOT)。実装者への重要な注意点として、例えばバイト255は有効なUTF-8ではありませんが、バイト0は有効なUTF-8です。
コンテンツタイプは次のとおりでなければなりません(MUST)。
application/openmetrics-text; version=1.0.0; charset=utf-8
行末はラインフィード(\n)で示されなければならず(MUST)、キャリッジリターン(\r)を含んではなりません(MUST NOT)。公開はEOFで終了しなければならず(MUST)、EOF\n
で終了すべきです(SHOULD)。
完全な公開の例
# TYPE acme_http_router_request_seconds summary
# UNIT acme_http_router_request_seconds seconds
# HELP acme_http_router_request_seconds Latency though all of ACME's HTTP request router.
acme_http_router_request_seconds_sum{path="/api/v1",method="GET"} 9036.32
acme_http_router_request_seconds_count{path="/api/v1",method="GET"} 807283.0
acme_http_router_request_seconds_created{path="/api/v1",method="GET"} 1605281325.0
acme_http_router_request_seconds_sum{path="/api/v2",method="POST"} 479.3
acme_http_router_request_seconds_count{path="/api/v2",method="POST"} 34.0
acme_http_router_request_seconds_created{path="/api/v2",method="POST"} 1605281325.0
# TYPE go_goroutines gauge
# HELP go_goroutines Number of goroutines that currently exist.
go_goroutines 69
# TYPE process_cpu_seconds counter
# UNIT process_cpu_seconds seconds
# HELP process_cpu_seconds Total user and system CPU time spent in seconds.
process_cpu_seconds_total 4.20072246e+06
# EOF
ABNFでエスケープが指示されている場合、以下のエスケープが適用されなければなりません(MUST)。 ラインフィード、\n
(0x0A) -> 文字通り\\n
(バイトコード 0x5c 0x6e) 二重引用符 -> \\"
(バイトコード 0x5c 0x22) バックスラッシュ -> \\\\
(バイトコード 0x5c 0x5c)
バックスラッシュ文字を表すには、二重バックスラッシュを使用すべきです(SHOULD)。未定義のエスケープシーケンスに単一のバックスラッシュを使用すべきではありません(SHOULD NOT)。例として、\\\\a
は\\a
と同等であり、より好ましいです。
整数は小数点を持ってはなりません(MUST NOT)。例としては、23
、0042
、1341298465647914
があります。
浮動小数点数は、小数点を使用するか、科学表記法を使用して表現されなければなりません(MUST)。例としては、8903.123421
や1.89e-7
があります。浮動小数点数は、IEEE 754で定義されている64ビット浮動小数点値の範囲内に収まらなければなりません(MUST)が、仮数部に多くのビットを必要とし、精度が失われる可能性があります(MAY)。これは、ナノ秒分解能のタイムスタンプをエンコードするために使用してもよいです(MAY)。
数値の任意の整数および浮動小数点レンダリングは、「Canonical Numbers」セクションにある「quantile」および「le」ラベル値には使用してはなりません(MUST NOT)。それらは、数値が使用される他の場所で使用してもよいです(MAY)。
ヒストグラムの「le」ラベル値とサマリーメトリックの「quantile」ラベル値の数値は、ラベル値であり、ラベル値は不透明であることを意図している点で特別です。エンドユーザーはこれらの文字列値と直接やり取りする可能性が高く、多くの監視システムはそれらを第一級の数値として扱う能力を欠いているため、与えられた数値がまったく同じテキスト表現を持つことが有益です。
一貫性は非常に望ましいですが、言語とそのランタイムの実際の実装により、これを義務付けることは非現実的です。最も重要な一般的なクオンタイルは0.5、0.95、0.9、0.99、0.999であり、ミリ秒から10.0秒までの値を表すバケット値です。これらは、典型的なウェブサービスにおけるレイテンシーSLAやApdexなどのケースをカバーするためです。10の累乗がカバーされており、固定小数点と指数表記の切り替えが、ランタイム間で異なる場合でも一貫していることを確認しようとしています。ターゲットのレンダリングは、Goのfloat64値のデフォルトレンダリング(つまり%g)と同等であり、小数点や指数がない場合に、それが浮動小数点数であることを明確にするために.0が追加されます。
エクスポーターは、正の無限大を+Infとして出力しなければなりません(MUST)。
エクスポーターは、以下の例に従い、0.0から10.0までの値を0.001刻みで出力すべきです(SHOULD): 0.0 0.001 0.002 0.01 0.1 0.9 0.95 0.99 0.999 1.0 1.7 10.0
エクスポーターは、以下の例に従い、1e-10から1e+10までの値を10の累乗で出力すべきです(SHOULD): 1e-10 1e-09 1e-05 0.0001 0.1 1.0 100000.0 1e+06 1e+10
パーサーは、標準的な値と一貫性がないという理由だけで、標準的な値の範囲外の入力を拒否してはなりません(MUST NOT)。例えば、1.1e-4は0.00011の一貫したレンダリングではありませんが、拒否されてはなりません。
エクスポーターは非標準的な数値に対してこれらのパターンに従うべきであり(SHOULD)、レンダリングアルゴリズムを調整してこれらの値に対して一貫性を持たせることで、他の大部分の値も一貫したレンダリングを持つようになることを意図しています。特定のle/quantile値のみを使用するエクスポーターは、ハードコードすることもできます。Grisu3のような最小限の浮動小数点レンダリングアルゴリズムが容易に入手できないCのような言語では、エクスポーターは異なるレンダリングを使用してもよいです(MAY)。
Cおよびそのprintf実装を共有する他の言語の実装者への警告: %f、%e、%gの標準的な精度は有効数字6桁のみです。完全な精度には、例えばprintf("%.17g", d)
のように有効数字17桁が必要です。
ナノ秒の精度が必要な場合、float64のレンダリングでは十分な精度がないため、タイムスタンプに指数浮動小数点レンダリングを使用すべきではありません(SHOULD NOT)。例: 1604676851.123456789
。
MetricFamily間に明示的な区切り文字があってはなりません(MUST NOT)。次のMetricFamilyは、メタデータまたは前のMetricFamilyの一部ではありえない新しいサンプルメトリック名で示されなければなりません(MUST)。
MetricFamilyはインターリーブされてはなりません(MUST NOT)。
メタデータは4つの要素から構成されます: MetricFamily名、TYPE、UNIT、HELP。「foo」というカウンターメトリックのメタデータの例は次のとおりです。
# TYPE foo counter
TYPEが公開されていない場合、MetricFamilyはUnknownタイプでなければなりません(MUST)。
単位が指定されている場合、UNITメタデータ行で提供されなければなりません(MUST)。加えて、アンダースコアと単位はMetricFamily名のサフィックスでなければなりません(MUST)。
単位が「seconds」であるfoo_secondsメトリックの有効な例
# TYPE foo_seconds counter
# UNIT foo_seconds seconds
単位が名前のサフィックスではない無効な例
# TYPE foo counter
# UNIT foo seconds
以下も有効です。
# TYPE foo_seconds counter
単位が分かっている場合、提供されるべきです(SHOULD)。
UNITまたはHELP行の値は空であってもよいです(MAY)。これは、MetricFamilyのメタデータ行が存在しなかったかのように扱われなければなりません(MUST)。
# TYPE foo_seconds counter
# UNIT foo_seconds seconds
# HELP foo_seconds Some text and \n some \" escaping
MetricFamilyごとに、各タイプのメタデータ行が複数存在してはなりません(MUST NOT)。順序はTYPE、UNIT、HELPであるべきです(SHOULD)。
このメタデータとメッセージの末尾にあるEOF行を除いて、#で始まる行を公開してはなりません(MUST NOT)。
メトリックはインターリーブされてはなりません(MUST NOT)。
「テキストフォーマット -> MetricPoint」の例を参照してください。ラベルがないサンプル、またはタイムスタンプがなく値が0のサンプルは、以下のようにレンダリングされなければなりません(MUST)。
bar_seconds_count 0
または以下のように。
bar_seconds_count{} 0
ラベル値は任意の有効なUTF-8値であってもよいので(MAY)、ABNFに従ってエスケープが適用されなければなりません(MUST)。2つのラベルを持つ有効な例
bar_seconds_count{a="x",b="escaping\" example \n "} 0
MetricPointの値のレンダリングには、追加のラベル(例:ヒストグラムタイプの「le」ラベル)を含めることができます。これらはメトリック自身のLabelSetと同じ方法でレンダリングされなければなりません(MUST)。
MetricPointはインターリーブされてはなりません(MUST NOT)。
MetricFamily内に複数のMetricPointとサンプルがあった正しい例は次のとおりです。
# TYPE foo_seconds summary
# UNIT foo_seconds seconds
foo_seconds_count{a="bb"} 0 123
foo_seconds_sum{a="bb"} 0 123
foo_seconds_count{a="bb"} 0 456
foo_seconds_sum{a="bb"} 0 456
foo_seconds_count{a="ccc"} 0 123
foo_seconds_sum{a="ccc"} 0 123
foo_seconds_count{a="ccc"} 0 456
foo_seconds_sum{a="ccc"} 0 456
メトリックがインターリーブされている誤った例
# TYPE foo_seconds summary
# UNIT foo_seconds seconds
foo_seconds_count{a="bb"} 0 123
foo_seconds_count{a="ccc"} 0 123
foo_seconds_count{a="bb"} 0 456
foo_seconds_count{a="ccc"} 0 456
MetricPointがインターリーブされている誤った例
# TYPE foo_seconds summary
# UNIT foo_seconds seconds
foo_seconds_count{a="bb"} 0 123
foo_seconds_count{a="bb"} 0 456
foo_seconds_sum{a="bb"} 0 123
foo_seconds_sum{a="bb"} 0 456
ゲージタイプのMetricFamilyのMetricPointの値に対するサンプルメトリック名は、サフィックスを持ってはなりません(MUST NOT)。
ラベルなしのメトリックとタイムスタンプなしのMetricPointを持つMetricFamilyの例
# TYPE foo gauge
foo 17.0
ラベル付きの2つのメトリックとタイムスタンプなしのMetricPointを持つMetricFamilyの例
# TYPE foo gauge
foo{a="bb"} 17.0
foo{a="ccc"} 17.0
メトリックを持たないMetricFamilyの例
# TYPE foo gauge
ラベル付きのメトリックとタイムスタンプ付きのMetricPointを持つ例
# TYPE foo gauge
foo{a="b"} 17.0 1520879607.789
ラベルなしのメトリックとタイムスタンプ付きのMetricPointを持つ例
# TYPE foo gauge
foo 17.0 1520879607.789
ラベルなしのメトリックとタイムスタンプ付きの2つのMetricPointを持つ例
# TYPE foo gauge
foo 17.0 123
foo 18.0 456
MetricPointのTotal値のサンプルメトリック名は、サフィックス_total
を持たなければなりません(MUST)。存在する場合、MetricPointのCreated値のサンプルメトリック名は、サフィックス_created
を持たなければなりません(MUST)。
ラベルなしのメトリック、タイムスタンプなし、作成時間なしのMetricPointを持つ例
# TYPE foo counter
foo_total 17.0
ラベルなしのメトリック、タイムスタンプあり、作成時間なしのMetricPointを持つ例
# TYPE foo counter
foo_total 17.0 1520879607.789
ラベルなしのメトリック、タイムスタンプなし、作成時間ありのMetricPointを持つ例
# TYPE foo counter
foo_total 17.0
foo_created 1520430000.123
ラベルなしのメトリック、タイムスタンプあり、作成時間ありのMetricPointを持つ例
# TYPE foo counter
foo_total 17.0 1520879607.789
foo_created 1520430000.123 1520879607.789
エグゼンプラはMetricPointのTotalサンプルに添付されてもよいです(MAY)。
StateSetタイプのMetricFamilyのMetricPointの値に対するサンプルメトリック名は、サフィックスを持ってはなりません(MUST NOT)。
StateSetは、MetricPoint内の状態ごとに1つのサンプルを持たなければなりません(MUST)。各状態のサンプルは、MetricFamily名をラベル名とし、状態名をラベル値とするラベルを持たなければなりません(MUST)。状態サンプルの値は、状態が真であれば1でなければならず(MUST)、状態が偽であれば0でなければなりません(MUST)。
「a」、「bb」、「ccc」の状態を持ち、bbの値のみが有効で、メトリック名がfooである例
# TYPE foo stateset
foo{foo="a"} 0
foo{foo="bb"} 1
foo{foo="ccc"} 0
メトリック上の「entity」ラベルの例
# TYPE foo stateset
foo{entity="controller",foo="a"} 1.0
foo{entity="controller",foo="bb"} 0.0
foo{entity="controller",foo="ccc"} 0.0
foo{entity="replica",foo="a"} 1.0
foo{entity="replica",foo="bb"} 0.0
foo{entity="replica",foo="ccc"} 1.0
InfoタイプのMetricFamilyのMetricPointの値に対するサンプルメトリック名は、サフィックス_info
を持たなければなりません(MUST)。サンプル値は常に1でなければなりません(MUST)。
ラベルなしのメトリックと、「name」および「version」ラベルを持つ1つのMetricPoint値の例
# TYPE foo info
foo_info{name="pretty name",version="8.2.7"} 1
「entity」ラベルを持つメトリックと、「name」および「version」ラベルを持つ1つのMetricPoint値の例
# TYPE foo info
foo_info{entity="controller",name="pretty name",version="8.2.7"} 1.0
foo_info{entity="replica",name="prettier name",version="8.1.9"} 1.0
メトリックラベルとMetricPoint値ラベルは任意の順序であってもよいです(MAY)。
存在する場合、MetricPointのSum値のサンプルメトリック名はサフィックス_sum
を持たなければなりません(MUST)。存在する場合、MetricPointのCount値のサンプルメトリック名はサフィックス_count
を持たなければなりません(MUST)。存在する場合、MetricPointのCreated値のサンプルメトリック名はサフィックス_created
を持たなければなりません(MUST)。存在する場合、MetricPointのクオンタイル値は、「quantile」というラベル名と、測定されたクオンタイルのラベル値を持つラベルを使用して、測定されたクオンタイルを指定しなければなりません(MUST)。
ラベルなしのメトリックと、Sum、Count、Created値を持つMetricPointの例
# TYPE foo summary
foo_count 17.0
foo_sum 324789.3
foo_created 1520430000.123
ラベルなしのメトリックと、2つのクオンタイルを持つMetricPointの例
# TYPE foo summary
foo{quantile="0.95"} 123.7
foo{quantile="0.99"} 150.0
クオンタイルは任意の順序であってもよいです(MAY)。
MetricPointのバケット値のサンプルメトリック名は、サフィックス_bucket
を持たなければなりません(MUST)。存在する場合、MetricPointのSum値のサンプルメトリック名は、サフィックス_sum
を持たなければなりません(MUST)。存在する場合、MetricPointのCreated値のサンプルメトリック名は、サフィックス_created
を持たなければなりません(MUST)。MetricPointにSum値が存在する場合に限り、MetricPointの+Infバケット値も、サフィックス「_count」を持つメトリック名を持つサンプルに表示されなければなりません(MUST)。
バケットは、「le」の数値増加順にソートされなければならず(MUST)、「le」ラベルの値は標準的な数値のルールに従わなければなりません(MUST)。
ラベルなしのメトリックと、Sum、Count、Created値、および12個のバケットを持つMetricPointの例。「le」値の広範で非典型的だが有効な多様性が意図的に示されています。
# TYPE foo histogram
foo_bucket{le="0.0"} 0
foo_bucket{le="1e-05"} 0
foo_bucket{le="0.0001"} 5
foo_bucket{le="0.1"} 8
foo_bucket{le="1.0"} 10
foo_bucket{le="10.0"} 11
foo_bucket{le="100000.0"} 11
foo_bucket{le="1e+06"} 15
foo_bucket{le="1e+23"} 16
foo_bucket{le="1.1e+23"} 17
foo_bucket{le="+Inf"} 17
foo_count 17
foo_sum 324789.3
foo_created 1520430000.123
ラベルなしのエグゼンプラは、空のLabelSetを{}として表現しなければなりません(MUST)。
複数の有効なケースを示すエグゼンプラの例: 「0.01」バケットにはエグゼンプラがありません。0.1バケットにはラベルなしのエグゼンプラがあります。1バケットには1つのラベルを持つエグゼンプラがあります。10バケットにはラベルとタイムスタンプを持つエグゼンプラがあります。実際には、すべてのバケットは同じ形式のエグゼンプラを持つべきです(SHOULD)。
# TYPE foo histogram
foo_bucket{le="0.01"} 0
foo_bucket{le="0.1"} 8 # {} 0.054
foo_bucket{le="1"} 11 # {trace_id="KOO5S4vxi0o"} 0.67
foo_bucket{le="10"} 17 # {trace_id="oHg5SJYRHA0"} 9.8 1520879607.789
foo_bucket{le="+Inf"} 17
foo_count 17
foo_sum 324789.3
foo_created 1520430000.123
MetricPointのバケット値のサンプルメトリック名は、サフィックス_bucket
を持たなければなりません(MUST)。存在する場合、MetricPointのSum値のサンプルメトリック名は、サフィックス_gsum
を持たなければなりません(MUST)。MetricPointにSum値が存在する場合に限り、MetricPointの+Infバケット値も、サフィックス_gcount
を持つメトリック名を持つサンプルに表示されなければなりません(MUST)。
バケットは、「le」の数値増加順にソートされなければならず(MUST)、「le」ラベルの値は標準的な数値のルールに従わなければなりません(MUST)。
ラベルなしのメトリックと、バケットにエグゼンプラがないエグゼンプラなしの1つのMetricPoint値の例
# TYPE foo gaugehistogram
foo_bucket{le="0.01"} 20.0
foo_bucket{le="0.1"} 25.0
foo_bucket{le="1"} 34.0
foo_bucket{le="10"} 34.0
foo_bucket{le="+Inf"} 42.0
foo_gcount 42.0
foo_gsum 3289.3
不明タイプのMetricFamilyのMetricPointの値に対するサンプルメトリック名は、サフィックスを持ってはなりません(MUST NOT)。
ラベルなしのメトリックとタイムスタンプなしのMetricPointを持つ例
# TYPE foo unknown
foo 42.23
Protobufメッセージはバイナリでエンコードされなければならず(MUST)、コンテンツタイプとしてapplication/openmetrics-protobuf; version=1.0.0
を持たなければなりません(MUST)。
すべてのペイロードは、OpenMetrics Protobufスキーマで定義されている通り、単一のバイナリエンコードされたMetricSetメッセージでなければなりません(MUST)。
Protobufフォーマットは、プロトコルバッファ言語のproto3バージョンに従わなければなりません(MUST)。
すべての文字列フィールドはUTF-8でエンコードされなければなりません(MUST)。
OpenMetrics Protobufスキーマにおけるタイムスタンプ表現は、公開されているgoogle.protobuf.Timestamp [timestamp]メッセージに従わなければなりません(MUST)。タイムスタンプメッセージは、int64としてのUnixエポック秒と、秒のタイムスタンプコンポーネントから前方にカウントされるナノ秒分解能の非負の秒の分数としてint32でなければなりません(MUST)。0から999,999,999まで(両端を含む)でなければなりません(MUST)。
Protobufスキーマは現在、こちらで入手可能です。
OpenMetricsは、オンラインシステム向けのテレメトリを提供することを目的としています。これは、ハードまたはソフトなリアルタイム保証を提供しないプロトコル上で動作するため、それ自体でリアルタイム保証を行うことはできません。OpenMetricsのレイテンシーおよびジッター特性は、基盤となるネットワーク、オペレーティングシステム、CPUなどと同様に不正確です。これは、集計が意思決定の基礎として使用されるのに十分な精度がありますが、個々のイベントを反映するためではありません。
1時間に数件のリクエストを受信するアプリケーションから、400Gbネットワークポートの帯域幅使用量を監視するアプリケーションまで、あらゆる規模のシステムがサポートされるべきです。送信されたテレメトリの集計と分析は、任意の期間にわたって可能であるべきです。
これは、定期的な周期でデータ送信時の状態のスナップショットを転送することを意図しています。
インジェスターがどのエクスポーターが存在するかを発見する方法、およびその逆は、この標準のスコープ外であり、したがって定義されていません。
OpenMetricsのこの最初のバージョンは、確立されたデファクト標準であるPrometheusテキストフォーマット0.0.4に基づいており、意図的に大きな構文的または意味的な拡張や最適化を追加していません。例えば、ヒストグラムバケットのテキスト表現をよりコンパクトにする試みは行われておらず、その繰り返し性を処理するために基盤となるスタックの圧縮に依存しています。
これは意図的な選択であり、標準が既存のユーザーベースの採用と勢いを活用できるようにするためです。これにより、Prometheusテキストフォーマット0.0.4からの比較的容易な移行が保証されます。
また、実装が容易な基本標準が存在することも保証します。これは、将来の標準バージョンで構築できます。将来の標準バージョンでは、構文的にも意味的にもこの1.0バージョンのサポートが常に要求されることを意図しています。
監視システムがOpenMetricsの公開から過度の負担なく利用可能な情報を取得できるようにしたいと考えています。もしすべてのメタデータと構造を取り除き、OpenMetricsの公開を順序付けされていないサンプルのセットとして見た場合でも、それ自体で利用可能であるべきです。そのため、スケッチやt-ダイジェストのような不透明なバイナリ型はありません。これらはカスタムの解析と処理を必要とするため、ゲージとカウンターの組み合わせとして表現することはできません。
この原則は、標準全体で一貫して適用されています。例えば、MetricFamilyの単位は名前に重複して記述されており、単位メタデータを理解しないシステムでも単位を利用できるようにしています。「le」ラベルは、独自の特別な構文を持つのではなく、通常のラベル値であるため、インジェスターはそれらを取り込むために特別なヒストグラム処理コードを追加する必要がありません。さらに例を挙げると、複合データ型はありません。例えば、緯度/経度の地理位置情報型はありません。これは個別のゲージメトリックで実現できるためです。
システム間の一貫性と混乱を避けるため、単位は主にSI基本単位に基づいています。基本単位には、秒、バイト、ジュール、グラム、メートル、比率、ボルト、アンペア、セルシウス度が含まれます。単位は適用可能な場合に提供されるべきです。
例えば、すべての期間メトリックを秒単位で持つことで、特定のメトリックがナノ秒、マイクロ秒、ミリ秒、秒、分、時間、日、週のいずれであるかを推測したり、混合単位を扱う必要がなくなります。接頭辞なしの単位を選択することで、キロミリ秒が複雑なシステムの創発的な挙動の結果であったような状況を避けることができます。
値は浮動小数点数であるため、基本単位以下の精度が標準に組み込まれています。
同様に、ビットとバイトを混同すると混乱を招くため、バイトが基本として選択されます。理論的にはケルビンの方が良い基本単位ですが、実際には既存のほとんどのハードウェアはセルシウス度を公開しています。キログラムはSI基本単位ですが、キロ接頭辞は問題があるため、グラムが基本単位として選択されます。
基本単位は可能な限りすべての場合で使用すべきですが(SHOULD)、ケルビンは確立された単位であり、色や黒体温度など、セルシウス度とケルビンのメトリック間の比較が行われる可能性が低いユースケースでは、セルシウス度の代わりにケルビンを使用してもよいです(MAY)。
比率は基本単位であり、パーセンテージではありません。可能であれば、与えられた分子と分母に対するゲージまたはカウンターの形式で生データを公開すべきです。これにより、インジェスターでの分析と集計においてより良い数学的特性が得られます。
デシベルは基本単位ではありません。第一に、デシはSI接頭辞であり、第二に、ベルは対数であるためです。信号/エネルギー/電力比を公開するには、比率を直接公開する方が良いでしょう。可能であれば、生電力/エネルギーを公開するのがさらに良いです。浮動小数点指数は、極端な科学的用途でも十分カバーできます。電子ボルト(約1e-19 J)から超新星が放出するエネルギー(約1e44 J)までで63桁の差があり、64ビット浮動小数点数は2000桁以上の範囲をカバーできます。
基本単位ではない単位を避けられず、変換も実現できない場合でも、明確さのために実際の単位をメトリック名に含めるべきです。例えば、ワットはジュール単位のカウンターとして表現できるため、ジュールはエネルギーと電力の両方の基本単位です。実際には、特定のサードパーティシステムはワットのみを公開する場合があり、その場合、ワットで表現されたゲージが唯一現実的な選択肢となります。
すべてのMetricFamilyが単位を持つわけではありません。例えば、HTTPリクエストの数には単位がありません。技術的には単位はHTTPリクエストですが、その意味ではMetricFamily名全体が単位です。そこまで極端にすると有用ではありません。下流システムで人間が利用するためのグラフに適切な軸を設定できる可能性は常に念頭に置かれるべきです。
OpenMetricsで定義されているワイヤーフォーマットは、公開間でステートレスです。以前に公開された情報が、将来の公開に影響を与えてはなりません(MUST)。各公開は、エクスポーターの現在の状態の自己完結型スナップショットです。
既存および新規のインジェスターには、同じ自己完結型の公開が提供されなければなりません(MUST)。
中心的な設計上の選択は、エクスポーターは、最近変更や観測がなかったという理由だけでメトリックを除外してはならない(MUST NOT)という点です。エクスポーターは、インジェスターがどれくらいの頻度で公開を消費するかについて、いかなる仮定もしてはなりません。
メトリックは、時間経過に伴うその進化を分析できる場合に最も有用であるため、公開も時間とともに意味をなすものでなければなりません。したがって、単一の公開だけでは有用かつ有効であるとは言えません。メトリックのセマンティクスに対する一部の変更は、下流のユーザーを壊す可能性もあります。
パーサーは、以前の結果をキャッシュすることで一般的に最適化を行います。したがって、公開間でラベルが公開される順序を変更することは、技術的に破壊的ではないとはいえ、避けるべきです(SHOULD)。これはまた、公開に対する単体テストの作成を容易にする傾向があります。
メトリックとサンプルは、公開から公開へと現れたり消えたりすべきではありません(SHOULD NOT)。例えば、カウンターは履歴がある場合にのみ有用です。原則として、特定のメトリックは、プロセスが開始されてから終了するまで公開に存在すべきです。特定のプロセスのライフタイム中にMetricFamilyがどのようなメトリックを持つかを事前に知ることはしばしば不可能です(例:レイテンシーヒストグラムのラベル値はHTTPパスであり、これはエンドユーザーが実行時に提供します)が、カウンターのようなメトリックが一度公開されたら、プロセスが終了するまで公開され続けるべきです。カウンターが増加しなくても、現在の値を持っているという事実は無効になりません。特定のメトリックの公開を停止することが理にかなっている場合もあります。欠損データのセクションを参照してください。
一般的に、MetricFamilyのタイプを変更したり、そのメトリックからラベルを追加または削除したりすると、インジェスターにとって破壊的となります。
注目すべき例外は、情報MetricPointの値にラベルを追加しても破壊的ではないことです。これは、追加のラベル値を持つ全く新しい情報メトリックを作成することを強制されるのではなく、既存の情報MetricFamilyに意味のある追加情報を追加できるようにするためです。インジェスターシステムは、そのような追加に対して堅牢であることを確認すべきです。
MetricFamilyのヘルプを変更しても破壊的ではありません。可能な値の場合、浮動小数点数と整数間の切り替えは破壊的ではありません。ステートセットに新しい状態を追加しても破壊的ではありません。メトリック名を変更しない単位メタデータを追加しても破壊的ではありません。
ヒストグラムバケットは、公開から公開へと変更すべきではありません(SHOULD NOT)。これはパフォーマンスの問題を引き起こし、インジェスターを破壊する可能性が高いからです。同様に、アプリケーションの整合性のあるバイナリおよび環境からのすべての公開は、特定のヒストグラムMetricFamilyに対して同じバケットを持つべきであり(SHOULD)、これにより、インジェスターが異質なバケットに対するヒストグラムマージロジックを実装することなく、すべてのインジェスターによって集約されることができます。例外として、破壊的とみなされるバケットへの偶発的な手動変更がありますが、新しいソフトウェアリリースによってパフォーマンス特性が変化する場合、これは有効なトレードオフとなる可能性があります。
変更が技術的に破壊的でなくても、コストはかかります。例えば、頻繁な変更はインジェスターのパフォーマンス問題を引き起こす可能性があります。公開ごとに異なるHelp文字列は、各Help値が保存される原因となる可能性があります。整数値と浮動小数点値の頻繁な切り替えは、効率的な圧縮を妨げる可能性があります。
NaNはOpenMetricsにおける他の数値と同様に、通常、最近観測がなかった場合のサマリークオンタイルに対するゼロ除算などによって生じます。NaNはOpenMetricsにおいて特別な意味を持たず、特に欠損データやその他の不良データのマーカーとして使用してはなりません(MUST NOT)。
データが存在しなくなる有効なケースがあります。例えば、ファイルシステムがアンマウントされ、それによって空きディスク容量のゲージメトリックがもはや存在しなくなる場合です。この状況に対する特別なマーカーや信号はありません。その後の公開には、このメトリックは単に含まれません。
メトリックは、合理的な時間枠で収集できる場合にのみ有用です。公開に数分かかるメトリックは有用とはみなされません。
経験則として、公開は1秒以内であるべきです(SHOULD)。
OpenMetricsを介してシリアル化されたレガシーシステムからのメトリックは、時間がかかる場合があります。このため、厳密なパフォーマンスの仮定はできません。
公開は最新の状態であるべきです(SHOULD)。例えば、公開リクエストを処理するスレッドは、そのようなキャッシングをバイパスできる限り、キャッシュされた値に依存すべきではありません(SHOULD NOT)。
高可用性とアドホックアクセスには、複数のインジェスターを持つのが一般的なアプローチです。これをサポートするため、並行公開がサポートされなければなりません(MUST)。並行システムに関するすべてのBCP(ベストコモンプラクティス)に従うべきであり(SHOULD)、一般的な落とし穴にはデッドロック、競合状態、並行公開の進行を妨げる過度に粗い粒度のロックが含まれます。
メトリックとラベル名の命名において、理解しやすさ、衝突の回避、簡潔さのバランスを目指しています。名前はアンダースコアで区切られ、メトリック名は「snake_case」になります。
例として「http_request_seconds」は簡潔ですが、多数のアプリケーション間で衝突する可能性があり、このメトリックが正確に何を測定しているのかも不明確です。例えば、複雑なシステムでは認証ミドルウェアの前または後かもしれません。
メトリック名は、どのコードから来ているかを示すべきです。例えば、「A Company Manufacturing Everything」という会社は、そのコード内のすべてのメトリックに「acme_」という接頭辞を付けるかもしれません。もしHTTPルーターライブラリでレイテンシーを測定している場合、それは全体のレイテンシーであることを示すヘルプ文字列を持つ「acme_http_router_request_seconds」のようなメトリックを持つかもしれません。
すべてのアプリケーション間での潜在的な衝突をすべて防ぐことは目的ではありません。それは、メトリックネームスペースのグローバルレジストリやDNSに基づいた非常に長いネームスペースのような強硬な解決策を必要とするでしょう。むしろ目的は、軽量で非公式なアプローチを維持し、特定のアプリケーションにおいてその構成ライブラリ間で衝突が発生する可能性が非常に低いようにすることです。
監視システム全体の特定のデプロイメントにおいて、同じメトリック名が異なる意味を持つ衝突が稀であるようにすることが目的です。例えば、「A Company Manufacturing Everything」が開発した数百もの異なるアプリケーションに「acme_http_router_request_seconds」が含まれることは正常です。「Another Corporation Making Entities」もそのHTTPルーターで「acme_http_router_request_seconds」というメトリック名を使用した場合でも問題ありません。両社のアプリケーションが同じ監視システムによって監視されている場合、衝突は望ましくありませんが、どちらのアプリケーションも両方の名前を公開しようとしておらず、どのターゲットも(誤って)同じメトリック名を2回公開しようとしていないため、許容範囲です。もしあるアプリケーションが「My Example Company」と「Mega Exciting Company」の両方のHTTPルーターライブラリを含めたい場合、それは問題となり、いずれかのメトリック名を何らかの方法で変更する必要があるでしょう。
結果として、ライブラリが公開されているほど、そのようなシナリオが発生するリスクを減らすために、そのメトリック名はより適切にネームスペース化されるべきです。「acme_」は社内使用には悪い選択ではありませんが、これらの企業は、例えば社外で共有されるコードに対して「acmeverything_」や「acorpme_」といった接頭辞を選択するかもしれません。
企業または組織によるネームスペース化の後、必要に応じてライブラリ/サブシステム/アプリケーションごとにフラクタルにネームスペース化と命名を続けるべきです。上記のhttp_routerライブラリがその例です。目標は、コードベースの全体構造に精通していれば、与えられたメトリック名から、そのメトリックの計測がどこにあるかをうまく推測できることです。
一般的で非常によく知られた既存のソフトウェアの場合、ソフトウェア自体の名前で十分に区別できるかもしれません。例えば、DNSソフトウェアの場合、bind_で十分でしょう。isc_bind_の方がより一般的な命名ですが。
scrape_で始まるメトリック名は、個々の公開に関連する情報を添付するためにインジェスターによって使用されるため、アプリケーションによって直接公開されるべきではありません。既に汎用監視システムを介して消費され、通過したメトリックは、その後の公開でそのようなメトリック名を含む場合があります。エクスポーターが個々の公開に関する情報を提供したい場合、myexposer_scrape_のようなメトリック接頭辞を使用してもよいです。一般的な例としては、エクスポーターの視点からその公開に要した時間を示すゲージmyexposer_scrape_duration_secondsがあります。
Prometheusエコシステム内では、すべての実装で一貫性のある一連のプロセスごとのメトリックが、process_の接頭辞を付けて登場しています。例えば、オープンファイルのulimitの場合、MetricFamilyのprocess_open_fdsおよびprocess_max_fdsゲージは、現在値と最大値の両方を提供します。(これらの名前はレガシーであり、今日定義されるとしたらprocess_fds_openおよびprocess_fds_limitと命名される可能性が高いでしょう)。一般に、このように同一のセマンティクスを持つ名前を取得することは非常に困難であるため、異なる計測では異なる名前を使用すべきです。
メトリック名における冗長性を避けてください。「metric」、「timer」、「stats」、「counter」、「total」、「float64」などの部分文字列は避けてください。OpenMetricsを介して公開される特定のタイプ(およびおそらく単位)のメトリックであるという性質上、このような情報はすでに暗示されているため、明示的に含めるべきではありません。同じ理由で、メトリックのラベル名をメトリック名に含めるべきではありません。さらに、監視システムによるメトリックのその後の集計によって、そのような情報が不正確になる可能性があります。
計測に含まれるメトリック名に、監視システムの他のレイヤーからの実装の詳細を含めないでください。例えば、MetricFamily名に単に現在OpenMetricsを介して公開されているからといって「openmetrics」という文字列を含めたり、現在の監視システムがPrometheusだからといって「prometheus」という文字列を含めたりすべきではありません。
ラベル名については、企業やライブラリによる明示的なネームスペース化は推奨されません。ラベル名の長さの増加を考慮すると、メトリック名からのネームスペース化で十分です。しかし、一般的な衝突を避けるための最小限の注意は推奨されます。
region、zone、cluster、availability_zone、az、datacenter、dc、owner、customer、stage、service、team、job、instance、environment、envなどのラベル名は、汎用監視システムが追加するターゲットを識別するために使用されるラベルと衝突する可能性が非常に高いです。これらを避けるように努め、これらのケースでは最小限のネームスペースを追加することが適切かもしれません。
ラベル名「type」は非常に一般的であり、避けるべきです。例えば、HTTP関連のメトリックの場合、GET、POST、PUTリクエストを区別しているのであれば、「method」の方がより良いラベル名となるでしょう。
HELP、TYPE、UNITといったメトリック名に関するメタデータはありますが、ラベル名に関するメタデータはありません。これは、わずかなメリットのためにフォーマットを肥大化させることになるためです。帯域外のドキュメントは、エクスポーターがインジェスターにこれを提示する1つの方法です。
MetricFamily内で複数のメトリックを使用する場合と、複数のMetricFamilyを使用する場合の両方が意味をなすように思える状況があります。MetricFamilyの合計または平均は、常に有用でなくても意味を持つべきです。例えば、電圧とファン速度を混ぜるのは意味がありません。
念のためですが、OpenMetricsは、インジェスターがデータを処理し、集計を実行できるという前提で構築されています。
他のメトリックと一緒に合計値を公開するのは間違っています。これは、下流のインジェスターでの集計時に二重カウントを引き起こすためです。
wrong_metric{label="a"} 1
wrong_metric{label="b"} 6
wrong_metric{label="total"} 7
メトリックのラベルは、一意性を確保するために必要な最小限にすべきです。追加のラベルはすべて、ユーザーが下流で作業する際に考慮しなければならないラベルが1つ増えることになります。多くのMetricFamilyに適用できるラベルは、データベースの{{正規化}}と同様に_infoメトリックに移動する候補です。メトリックの事実上すべてのユーザーが追加のラベルを望むと予想される場合、それをすべてのMetricFamilyに追加する方が良いトレードオフとなるかもしれません。例えば、完全なSQLステートメントのハッシュを含むラベルによって一意性が提供される異なるSQLステートメントに関連するMetricFamilyがある場合、人間が読みやすいようにSQLステートメントの最初の500文字を含む別のラベルを持つことは問題ありません。
経験上、下流のインジェスターは、1つのMetricFamily内で{result="success"}と{result="failure"}のラベルを使用するよりも、個別の合計および失敗MetricFamilyを扱う方が容易であることが示されています。また、全二重システムが一般的であり、下流のインジェスターはそれらの値を集計するよりも個別に気にすることが多いため、個別の読み書きおよび送受信MetricFamilyを公開する方が通常は良いです。
これらすべては、聞こえるほど簡単ではありません。公開と公開されるシステムの両方におけるドメイン固有の専門家による経験とエンジニアリング上のトレードオフが必要とされる分野であり、適切なバランスを見つける必要があります。メトリックとラベル名の文字
OpenMetricsは、既存の広く採用されているPrometheusテキスト公開フォーマットと、その周りに形成されたエコシステムに基づいています。後方互換性は中心的な設計目標です。Prometheusテキストフォーマットがサポートする文字セットを拡張または縮小することは、その目標に反するでしょう。後方互換性を破壊することは、ワイヤーフォーマットだけでなく、より広範な影響をもたらすでしょう。特に、Prometheusエコシステム内で送信されたデータを扱うために作成または採用されたクエリ言語は、これらの正確な文字セットに依存しています。ラベル値は完全なUTF-8をサポートしているため、このフォーマットは多言語メトリックを表現できます。
メタデータは様々なソースから取得できます。長年にわたり、主に2つのソースが浮上しました。これらは機能的には同じであることが多いですが、概念的な違いについて話すことは理解を助けます。
「ターゲットメタデータ」は、一般的にエクスポーターの外部にあるメタデータです。一般的な例としては、データセンターの地域情報、サービスが特定のデプロイメントの一部であるかどうか、本番環境かテスト環境かなど、サービスディスカバリ、CMDBなどから得られるデータがあります。これは、エクスポーターまたはインジェスターが、このメタデータをキャプチャするすべてのメトリックにラベルを追加することで実現できます。インジェスターを介してこれを行う方が、より柔軟でオーバーヘッドが少ないため推奨されます。柔軟性に関しては、ハードウェア保守チームはマシンのサーバラックの場所を気にするかもしれませんが、同じマシンを使用するデータベースチームは、それが本番データベースのレプリカ2を含むことを気にするかもしれません。オーバーヘッドに関しては、この情報をハードコードまたは設定するには追加の配信パスが必要です。
「エクスポーターメタデータ」は、エクスポーターの内部から提供されるメタデータです。一般的な例としては、ソフトウェアバージョン、コンパイラバージョン、GitコミットSHAなどがあります。
プッシュベースの消費では、エクスポーターが関連するターゲットメタデータをインジェスターに提供するのが一般的です。プルベースの消費では、プッシュベースのアプローチもとれますが、より一般的には、インジェスターは機械データベースやサービスディスカバリシステムなどからターゲットのメタデータを事前に知っており、公開を消費する際にそれをメトリックと関連付けます。
OpenMetricsはステートレスであり、すべてのインジェスターに同じ公開を提供します。これはプッシュスタイルのアプローチと矛盾します。さらに、プッシュスタイルのアプローチでは、不要なメタデータが公開されるため、プルスタイルのインジェスターを破壊するでしょう。
1つのアプローチとして、プッシュスタイルのインジェスターが、オペレーターの設定に基づいて帯域外でターゲットメタデータを提供すること、例えばHTTPヘッダーとして提供することが考えられます。これはプッシュスタイルのインジェスターにターゲットメタデータを転送することになり、この標準によって排除されるものではありませんが、プルスタイルのインジェスターが独自のターゲットメタデータを使用すべきであるにもかかわらず、エクスポーター自身が認識しているメタデータにアクセスできることが依然として有用であるという欠点があります。
推奨される解決策は、このターゲットメタデータをエクスポジションの一部として提供することですが、エクスポジション全体に影響を与えない方法で行うことです。Info MetricFamilyは、この目的のために設計されています。エクスポーザーは、メタデータを持つラベルなしの単一のメトリックを含む「target」というInfo MetricFamilyを含めることができます。テキスト形式の例は以下のようになります。
# TYPE target info
# HELP target Target metadata
target_info{env="prod",hostname="myhost",datacenter="sdc",region="europe",owner="frontend"} 1
エクスポーザーがこの目的のためにこのメトリックを提供する場合、それはエクスポジションの最初に置かれるべきです(SHOULD)。これは効率のためであり、ターゲットメタデータのためにそれに依存するインジェスターが、その内容に基づいてビジネスロジックを適用する前に、エクスポジションの残りをバッファリングする必要がないようにするためです。
エクスポーザーは、特定のインジェスター向けに明示的に構成されていない限り、エクスポジション内のすべてのメトリックにターゲットメタデータラベルを追加してはなりません(MUST NOT)。エクスポーザーは、ターゲットメタデータに基づいてMetricFamily名にプレフィックスを付けたり、MetricFamily名を変更したりしてはなりません(MUST NOT)。一般的に、同じラベルがエクスポジションのすべてのメトリックに表示されるべきではありませんが、偶発的な動作の結果としてこれが発生する稀なケースがあります。同様に、非常に小さなエクスポジションでは、エクスポーザーからのすべてのMetricFamily名がたまたま同じプレフィックスを共有することがあります。例えば、「A Company Manufacturing Everything」がGo言語で書いたアプリケーションは、acme_、go_、process_、および使用されているサードパーティライブラリからのメトリックプレフィックスを含むメトリックを持つ可能性が高いでしょう。
エクスポーザーは、エクスポーザーのメタデータをInfo MetricFamiliesとして公開できます。
上記の議論は個々のエクスポーザーの文脈におけるものです。汎用監視システムからのエクスポジションは、多くの個々のターゲットからのメトリックを含むことができ、したがって複数のターゲット情報メトリックを公開する可能性があります。メトリックには、インジェストの一部として既にラベルとしてターゲットメタデータが追加されている場合があります。メトリック名は、ターゲットメタデータに基づいて変更されてはなりません(MUST NOT)。例えば、すべてのメトリックがステージング環境のターゲットから発生したとしても、それらすべてがstaging_というプレフィックスで終わるのは誤りです)。
エクスポーザーは、あらゆる計算をインジェスターに任せるべきです。特筆すべき例外は、残念ながら後方互換性のために必要とされるSummaryのquantileです。エクスポジションは、任意の期間にわたって有用な生の値であるべきです。
例として、過去5分間のカウンタの増加率の平均値をゲージとして公開すべきではありません。インジェスターがエクスポジションを横断して消費したデータポイントに基づいて増加量を計算させる方が、数学的に優れた特性を持ち、スクレイプの失敗に対してより耐性があります。
別の例は、ヒストグラム/サマリーの平均イベントサイズです。アプリケーションが開始されてから、またはメトリックが作成されてからのカウンタの増加率の平均値を公開すると、以前の例と同じ問題が発生し、さらに集計を妨げます。
標準偏差もこのカテゴリに属します。二乗和をカウンタとして公開するのが正しいアプローチでしょう。64ビット浮動小数点精度では実用的に機能しないため、ヒストグラム値としてはこの標準には含まれていませんでした。二乗するため、精度という点では53ビット仮数の半分しか利用できません。例として、毎秒1万イベントを観測するヒストグラムは、2時間以内に精度を失います。64ビット整数を使用しても、浮動小数点がないため、改善されません。ナノ秒解像度の整数で通常1秒間のイベントを追跡する場合、19回の観測でオーバーフローするでしょう。この設計上の決定は、128ビット浮動小数点数が一般的になったときに再検討される可能性があります。
もう1つの例は、リクエストの失敗率を公開するのを避け、代わりに失敗したリクエストと合計リクエストの別々のカウンタを公開することです。
毎秒100万回インクリメントされるカウンタの場合、float64は53ビットの仮数を持っているため、精度が失われ始めるまでに1世紀以上かかるでしょう。しかし、100Gbpsのネットワークインターフェースのオクテットスループット精度は、float64では約20時間以内に失われ始める可能性があります。100Gbpsのネットワークインターフェースで数年間にわたって1KBの精度が失われることは実際には問題にならない可能性が高いですが、そのような高スループットの整数データにはint64が選択肢となります。
Summaryのquantileはfloat64でなければなりません。これらは推定値であり、根本的に不正確だからです。
OpenMetricsの主要な前提の1つは、エクスポーザーが公開するものの最新のスナップショットを公開することです。
公開されたデータにタイムスタンプを付加するユースケースは限られており、これらは非常に稀です。以前にタイムスタンプが付加されていたデータ、特に汎用監視システムにインジェストされたデータはタイムスタンプを持つことがあります。ライブデータまたは生データはタイムスタンプを持つべきではありません。同じメトリックのMetricPoint値を、エクスポジション間で同じタイムスタンプで公開することは有効ですが、基となるメトリックが現在存在しない場合は無効です。
時刻同期は難しい問題であり、データは各システム内で内部的に一貫しているべきです。そのため、インジェスターはエクスポーザーデバイスのシステム時間に基づかず、自身の視点から現在のタイムスタンプをデータに付加できるべきです。
タイムスタンプ付きのメトリックでは、エクスポジション間でメトリックがいつ消失したかを一般的に検出することはできません。しかし、タイムスタンプなしのメトリックでは、インジェスターはメトリックがもはや存在しないエクスポジションから自身のタイムスタンプを使用できます。
これらすべてが意味するのは、一般的にMetricPointのタイムスタンプは公開すべきではないということです。なぜなら、インジェスターがインジェストするサンプルに自身のタイムスタンプを適用するのはインジェスターの責任であるべきだからです。
カウンタmy_counterが初期化され、その後時刻123で1だけインクリメントされたと仮定します。テキスト形式でこれを公開する正しい方法は次のとおりです。
# HELP my_counter Good increment example
# TYPE my_counter counter
my_counter_total 1
親セクションの通り、インジェスターは自由に自身のタイムスタンプを付加できるべきなので、これは正しくありません。
# HELP my_counter Bad increment example
# TYPE my_counter counter
my_counter_total 1 123
カウンタの最終変更時刻が重要である場合、これが正しい方法です。
# HELP my_counter Good increment example
# TYPE my_counter counter
my_counter_total 1
# HELP my_counter_last_increment_timestamp_seconds When my_counter was last incremented
# TYPE my_counter_last_increment_timestamp_seconds gauge
# UNIT my_counter_last_increment_timestamp_seconds seconds
my_counter_last_increment_timestamp_seconds 123
最終変更のタイムスタンプを独自のゲージ値として配置することで、インジェスターは両方のメトリックに自身のタイムスタンプを自由に付加できます。
経験上、絶対タイムスタンプ(ここではエポックが絶対とみなされる)を公開する方が、経過時間やからの秒数などよりも堅牢であることが示されています。どちらの場合も、それらはゲージとなります。例えば
# TYPE my_boot_time_seconds gauge
# HELP my_boot_time_seconds Boot time of the machine
# UNIT my_boot_time_seconds seconds
my_boot_time_seconds 1256060124
より優れています
# TYPE my_time_since_boot_seconds gauge
# HELP my_time_since_boot_seconds Time elapsed since machine booted
# UNIT my_time_since_boot_seconds seconds
my_time_since_boot_seconds 123
逆に、エクセンプラーのタイムスタンプにはベストプラクティス上の制約はありません。競合状態やデバイス間で時間が完全に同期されていないため、エクセンプラーのタイムスタンプが、インジェスターのシステムクロックや同じエクスポジションからの他のメトリックと比較して、わずかに未来に見える可能性があることに留意してください。同様に、同じMetricPointの"_created"が、そのMetricPointのエクセンプラーまたはサンプルタイムスタンプよりもわずかに後に表示される可能性もあります。
ナノ秒から秒までの解像度をサポートする監視システムが一般的に使用されていることに留意してください。そのため、秒単位の解像度に切り詰めたときに同じタイムスタンプを持つ2つのMetricPointが存在すると、インジェスターで重複が発生する可能性があります。この場合、最も早いタイムスタンプを持つMetricPointが使用されなければなりません(MUST)。
システムの望ましい範囲を公開することは理にかなっていますが、適切な注意が必要です。普遍的に真である値については、そのようなしきい値に対してゲージメトリックを発行することは理にかなっています。例えば、データセンターのHVACシステムは、現在の測定値、設定値、アラート設定値を知っています。それは、望ましいシステム状態のグローバルに有効で正確なビューを持っています。反対の例として、一部のしきい値は、スケール、デプロイメントモデル、または時間とともに変化する可能性があります。ある量のCPU使用率は、ある設定では許容できても、別の設定では望ましくない場合があります。値の集計は、さらに許容値を変更する可能性があります。このようなシステムでは、範囲を公開することは逆効果になる可能性があります。
例えば、キューの最大サイズは、現在キューにあるアイテム数とともに公開される場合があります。
# HELP acme_notifications_queue_capacity The capacity of the notifications queue.
# TYPE acme_notifications_queue_capacity gauge
acme_notifications_queue_capacity 10000
# HELP acme_notifications_queue_length The number of notifications in the queue.
# TYPE acme_notifications_queue_length gauge
acme_notifications_queue_length 42
この標準は、単一のエクスポジションによって公開されるサンプルの数、存在する可能性のあるラベルの数、statesetが持つ可能性のある状態の数、情報値内のラベルの数、またはメトリック名/ラベル名/ラベル値/ヘルプ文字の制限について、特定の制限を規定していません。
具体的な制限は、合理的なユースケースを妨げるリスクがあります。例えば、あるエクスポジションが汎用監視システムを通過した後、適切な数のラベルを持っていたとしても、いくつかのターゲットラベルが追加されて制限を超えてしまう可能性があります。このような数値に対する具体的な制限は、汎用監視システムにとっての本当のコストがどこにあるのかを捉えることもできません。したがって、これらのガイドラインは、エクスポーザーとインジェスターが何が合理的であるかを理解するのに役立ちます。
一方、ある次元で大きすぎるエクスポジションは、公開されるメトリックの利点と比較して、深刻なパフォーマンス問題を引き起こす可能性があります。したがって、単一のエクスポジションのサイズに関するいくつかのガイドラインが有用でしょう。
インジェスターは、特に攻撃や停止を防ぐために、自ら制限を課すことを選択できます。それでも、インジェスターは合理的なユースケースを考慮し、それらに不均衡な影響を与えないように努める必要があります。いずれかの単一の値/メトリック/エクスポジションがそのような制限を超えた場合、エクスポジション全体が拒否されなければなりません。
一般的に、汎用監視システムの時系列データ取り込みのパフォーマンスに影響を与える3つの要素があります。それは、ユニークな時系列の数、それらの時系列における時間経過に伴うサンプルの数、そしてメトリック名、ラベル名、ラベル値、HELPのようなユニークな文字列の数です。インジェスターは取り込み頻度を制御できるため、その側面はこれ以上考慮する必要はありません。
ユニークな時系列の数は、テキスト形式の非コメント行数とほぼ同等です。2020年現在、合計1000万の時系列は大量と見なされ、単一インスタンスのインジェスターの上限の桁数となるのが一般的です。単一のエクスポジションは、十分な検討なしに1万時系列を超えるべきではありません。一般的な考慮事項の1つは水平スケーリングです。インスタンス数を1〜2桁増やすとどうなりますか?30年前には、単一のデプロイメントで千台のトップオブラック(ToR)スイッチを持つことは想像しがたかったでしょう。ターゲットがシングルトン(例えば、クラスター全体に関連するメトリックを公開するなど)であれば、数十万の時系列が合理的かもしれません。重要なのは、ユニークなMetricFamilyの数や個々のラベル/バケット/statesetのカーディナリティではなく、時系列の合計の桁数です。それぞれ1つのメトリックを持つ1,000個のゲージは、1,000個のメトリックを持つ単一のゲージと同じくらいコストがかかります。
特定のタイプのすべてのターゲットが同じ時系列セットを公開している場合、追加の各ターゲットの文字列は、ほとんどの合理的に近代的な監視システムにとって増分コストをもたらしません。しかし、各ターゲットがユニークな文字列を持つ場合、そのようなコストが発生します。極端な例として、多くのターゲットで使用される単一の10k文字のメトリック名は、それ自体は実際には問題になる可能性は非常に低いです。これとは対照的に、それぞれユニークな36文字のUUIDを公開する千のターゲットは、現代的なアプローチを前提とすると、格納される文字列の観点から、その単一の10k文字のメトリック名の3倍以上のコストがかかります。さらに、これらの文字列が時間とともに変化する場合、古い文字列も少なくともしばらくの間は格納する必要があり、追加のコストが発生します。前の段落の1000万時系列を仮定すると、1時間あたり100MBのユニークな文字列は、ユースケースがメトリック時系列ではなくイベントロギングに近いことを示唆するかもしれません。
トレーシングスパンデータやその他のイベントロギングにこの機能が悪用されるのを防ぐため、エクセンプラーの長さには厳格な128UTF-8文字の制限があります。
実装者は、認証、認可、およびアカウンティングを提供することを選択してもよい(MAY)。もしそれらを選択するならば、これはOpenMetricsの外部で処理されるべきです(SHOULD)。
すべてのエクスポーザー実装は、TLS 1.2以降でHTTPトラフィックを保護できるべきです(SHOULD)。エクスポーザー実装が暗号化をサポートしない場合、オペレーターは可能な限りリバースプロキシ、ファイアウォール、および/またはACLを使用すべきです(SHOULD)。
メトリックのエクスポジションは、エンドユーザーに公開される本番サービスとは独立しているべきです。そのため、OpenMetricsを使用する公開サービスの場合、TCP/80、TCP/443、TCP/8080、TCP/8443などのポートで/metricsエンドポイントを持つことは一般的に推奨されません。
現在、Prometheusエクスポジション形式のほとんどの実装は、{{PrometheusPorts}}にある非公式レジストリからのIANA未登録ポートを使用していますが、OpenMetricsは明確に定義されたポートで見つけることができます。
IANAによってデータ公開クライアントに割り当てられたポートは、<歴史的整合性のために要求された9099>です。
複数のメトリックエンドポイントが共通のIPアドレスとポートで到達可能である必要がある場合、オペレーターはlocalhostアドレスを介してエクスポーザーと通信するリバースプロキシの使用を検討するかもしれません。多重化を容易にするため、エンドポイントはパスに自身の名前を含むべきです(SHOULD)。例えば、/node_exporter/metrics
。エクスポジションは、”プッシュベースとプルベースの両方のシステムにおけるターゲットメタデータのサポート”で説明されている理由、および単一障害点なしに独立した取り込みを可能にするために、1つのエクスポジションに結合されるべきではありません(SHOULD NOT)。
OpenMetricsは、application/openmetrics-text
とapplication/openmetrics-proto
の2つのMIMEタイプを登録したいと考えています。
このドキュメントはオープンソースです。問題提起やプルリクエストを通じて、改善にご協力ください。