> Source: https://www.ymotongpoo.com/works/otel-specs-ja/spec/compatibility/prometheus_and_openmetrics/


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

## Differences between Prometheus formats

この文書は、以下を含む、さまざまなPrometheus関連の形式とのOpenTelemetryの互換性を扱います。

メトリクスのスクレイピング（プル）に使われる形式:

* [Prometheusテキスト表現形式](https://github.com/prometheus/docs/blob/main/docs/instrumenting/exposition_formats.md)
* [Prometheus protobuf形式](https://github.com/prometheus/client_model/blob/01ca24cafc7877ed5ce091083068cde086b7c3dc/io/prometheus/client/metrics.proto)
* [OpenMetricsテキスト形式](https://github.com/prometheus/OpenMetrics/blob/1386544931307dff279688f332890c31b6c5de36/specification/OpenMetrics.md#text-format)
* （Prometheusではまだサポートされていない）[OpenMetrics protobuf形式](https://github.com/prometheus/OpenMetrics/blob/1386544931307dff279688f332890c31b6c5de36/specification/OpenMetrics.md#protobuf-format)

メトリクスのプッシュに使われる形式:

* [Prometheus Remote Write形式](https://github.com/prometheus/prometheus/blob/main/prompb/remote.proto)

以下の文書では、特定の機能が個々の形式でサポートされていない場合もありますが、これらすべての形式の総称として「Prometheus」を使います。形式ごとに仕様を重複して記述することを避けるため、この文書には、すべてのPrometheus形式で実装可能とは限らない要求事項が含まれます。執筆時点で、以下の機能は一貫してサポートされていません。

* エグゼンプラーは、現在Prometheusテキスト表現形式ではサポートされていません。
  * サポートされていない場合、エグゼンプラーは破棄されなければなりません（MUST）。
* Info型とStateSet型のメトリクスは、現在Prometheusテキスト表現形式またはPrometheus protobuf形式ではサポートされていません。
  * 以下の仕様がPrometheusのInfo型メトリクスの生成を要求している場合、Info型メトリクスがサポートされていなければ、`_info`という追加のサフィックスを持つPrometheusのGaugeを生成しなければなりません（MUST）。
  * 以下の仕様がPrometheusのStateSet型メトリクスの生成を要求している場合、StateSet型メトリクスがサポートされていなければ、代わりにPrometheusのGaugeを生成しなければなりません（MUST）。
* 指数（Native）Histogramは、現在Prometheusテキスト表現形式、またはOpenMetricsのテキスト形式・proto形式ではサポートされていません。
  * サポートされていない場合、指数（Native）Histogramは破棄すべき（SHOULD）であり、固定バケットのHistogramへ変換してもかまいません（MAY）。

## Prometheus Metric points to OTLP

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

### Metric Metadata

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

[Prometheusのメトリクス名](https://prometheus.io/docs/instrumenting/exposition_formats/#comments-help-text-and-type-information)は、OTLPメトリクスの名前として追加されなければなりません（MUST）。名前は変更すべきではありません（SHOULD NOT）。

[PrometheusのUNITメタデータ](https://github.com/prometheus/OpenMetrics/blob/v1.0.0/specification/OpenMetrics.md#metricfamily)が存在する場合、それはOTLPメトリクスの単位に変換されなければなりません（MUST）。単位が以下のよく使われる単位の集合に含まれる場合、単語からUCUMの略記へ翻訳されなければなりません（MUST）。

| Prometheusの単位 | UCUMの略記 |
| :--- | :--- |
| `days` | `d` |
| `hours` | `h` |
| `minutes` | `min` |
| `seconds` | `s` |
| `milliseconds` | `ms` |
| `microseconds` | `us` |
| `nanoseconds` | `ns` |
| `bytes` | `By` |
| `kibibytes` | `KiBy` |
| `mebibytes` | `MiBy` |
| `gibibytes` | `GiBy` |
| `tebibytes` | `TiBy` |
| `kilobytes` | `kBy` |
| `megabytes` | `MBy` |
| `gigabytes` | `GBy` |
| `terabytes` | `TBy` |
| `meters` | `m` |
| `volts` | `V` |
| `amperes` | `A` |
| `joules` | `J` |
| `watts` | `W` |
| `grams` | `g` |
| `celsius` | `Cel` |
| `hertz` | `Hz` |
| `percent` | `%` |

[PrometheusのHELPメタデータ](https://prometheus.io/docs/instrumenting/exposition_formats/#comments-help-text-and-type-information)が存在する場合、それはOTLPメトリクスの説明として追加されなければなりません（MUST）。

[PrometheusのTYPEメタデータ](https://prometheus.io/docs/instrumenting/exposition_formats/#comments-help-text-and-type-information)が存在する場合、それはOTLPのデータ型を決定するために使わなければならず（MUST）、以下に列挙する型固有の変換規則を左右します。TYPEメタデータを持たないメトリクスファミリーは、以下の[unknown-typed](#unknown-typed)メトリクスの規則に従います。TYPEメタデータは、OTLPの[metric.metadata][metricMetadata]内の`prometheus.type`キー（例えば`prometheus.type="unknown"`）にも追加されなければなりません（MUST）。

### Timestamps

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

Prometheusのメトリクスサンプルの開始タイムスタンプ（Createdタイムスタンプとも呼ばれます）が存在する場合、それはOTLPデータポイントの開始タイムスタンプへ変換されなければなりません（MUST）。開始タイムスタンプが存在しない場合、OTLPデータポイントの開始時刻は未設定のままにすべきです（SHOULD）。

Prometheusのメトリクスサンプルのタイムスタンプが存在する場合、それはOTLPデータポイントのタイムスタンプへ変換されなければなりません（MUST）。明示的なタイムスタンプなしでPrometheusエンドポイントからスクレイピングされたメトリクスについては、OTLPデータポイントのタイムスタンプはスクレイピングを行った時刻に設定されなければなりません（MUST）。

### Counters

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

[Prometheus Counter](https://prometheus.io/docs/instrumenting/exposition_formats/#basic-info)は、`is_monotonic`が`true`のOTLP Sumへ変換されなければなりません（MUST）。

Prometheus Counterのサンプルにあるエグゼンプラーは、[Exemplars](#exemplars)の規則に従って、OpenTelemetry SumデータポイントのOpenTelemetryエグゼンプラーへ変換されなければなりません（MUST）。

### Gauges

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

[Prometheus Gauge](https://prometheus.io/docs/instrumenting/exposition_formats/#basic-info)は、OTLP Gaugeへ変換されなければなりません（MUST）。

### Info

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

[Prometheus Info](https://github.com/prometheus/OpenMetrics/blob/v1.0.0/specification/OpenMetrics.md#info)メトリクスは、[リソース属性](#resource-attributes)を構成するために使われる`target`のInfoメトリクスである場合を除き、OTLPの非モノトニックなSumへ変換されなければなりません（MUST）。Prometheus Infoメトリクスは、値が1で、そのラベルがプロセスの生存期間中おおむね変わらない、Prometheus Gaugeメトリクスの特殊なケースと考えることができます。OTLP Gaugeではなく非モノトニックなOTLP Sumへ変換されるのは、値の1がカウントとして見なされることを意図しており、ラベルを集約する際にはそれらを合算すべきだからです。

### StateSet

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

[Prometheus StateSet](https://github.com/prometheus/OpenMetrics/blob/v1.0.0/specification/OpenMetrics.md#stateset)メトリクスは、OTLPの非モノトニックなSumへ変換されなければなりません（MUST）。Prometheus StateSetメトリクスは、値が0または1で、可能な状態それぞれについて1つのメトリクスポイントを持つ、Prometheus Gaugeの特殊なケースと考えることができます。OTLP Gaugeではなく非モノトニックなOTLP Sumへ変換されるのは、値の1がカウントとして見なされることを意図しており、ラベルを集約する際にはそれらを合算すべきだからです。

### Unknown-typed

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

[Prometheus Unknown](https://prometheus.io/docs/instrumenting/exposition_formats/#basic-info)は、OTLP Gaugeへ変換されなければなりません（MUST）。

### Histograms

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

[Prometheus Histogram](https://github.com/prometheus/OpenMetrics/blob/v1.0.0/specification/OpenMetrics.md#histogram)は、[OTLP Histogram](/works/otel-specs-ja/spec/metrics/data-model/#histogram)へ変換されなければなりません（MUST）。

Prometheusのバケット境界は、+Inf境界を除いてOTLPの明示的境界（explicit bounds）になります。Prometheusのバケット境界に関連付けられたサンプル値は、+Inf境界に関連付けられた値を含めて、OTLPのバケットカウントになります。Prometheus Histogramのカウントはそのままの形でOTLP Histogramのカウントになり、Prometheus HistogramのサムはOTLP Histogramのサムになります。

テキスト形式では、Prometheus Histogramのバケット、カウント、サムは別々のサンプルとして送出され、OTLP Histogramを構成する際にそれらをマージしなければなりません（MUST）。`_bucket`サフィックスを持つサンプルは、バケット境界を示す`le`ラベルを持ち、その値はバケット境界より小さい観測値の総カウントです。OpenTelemetryバケットのカウントは、そのバケットと（存在する場合は）次に小さいバケットとの差として計算されます。`_count`と`_sum`サフィックスを持つ行は、Histogramのカウントとサムを決定するために使われます。

* `_count`が存在しない場合、そのメトリクスは破棄されなければなりません（MUST）。
* `_sum`が存在しない場合、Histogramのサムは未設定にしなければなりません（MUST）。

Prometheus Histogramのサンプルにあるエグゼンプラーは、[Exemplars](#exemplars)の規則に従って、OpenTelemetry HistogramデータポイントのOpenTelemetryエグゼンプラーへ変換されなければなりません（MUST）。

### Native Histograms

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

標準的な（指数的な）スキーマ（すなわちスキーマ-4から8）を持ち、整数型かつCounterの[flavor](https://prometheus.io/docs/specs/native_histograms/#flavors)である[Prometheus Native Histogram](https://prometheus.io/docs/specs/native_histograms/)は、以下のようにOTLPのExponential Histogramへ変換されなければなりません（MUST）。

- Native Histogramの`ResetHint`（または`CounterResetHint`）がgauge型を示す場合、そのNative Histogramは破棄されます。それ以外の場合、このフィールドは無視されます。
- `Schema`はExponential Histogramの`Scale`へ変換されます。
- `Sum`が[Stale NaNの値](https://github.com/prometheus/prometheus/blob/main/model/value/value.go)と等しい場合、`NoRecordedValue`フラグは`true`に設定されます。そうでない場合、
  - `Count`は、以下を合計したすべての有効なバケットカウントの合計になります。
    - `ZeroCount`。
    - 以下で説明する疎（sparse）バケットレイアウトからのバケットカウント。オーバーフローバケットは除きます。
  - `Sum`はExponential Histogramの`Sum`へ変換されます。Native Histogramが値`NaN`、あるいは`-Inf`と`+Inf`の両方を観測した場合、`Sum`は`NaN`になることがあることに注意してください。`Sum`は`-Inf`または`+Inf`になることもあります。
- `Timestamp`は、ミリ秒をナノ秒に変換した上で、Exponential Histogramの`TimeUnixNano`へ変換されます。
- `ZeroCount`は、そのままExponential Histogramの`ZeroCount`へ変換されます。
- `ZeroThreshold`は、Exponential Histogramの`ZeroThreshold`へ変換されます。
- `PositiveSpans`と`PositiveDeltas`が表す[疎バケットレイアウト](https://prometheus.io/docs/specs/native_histograms/#buckets)は、`Positive`バケットカウントと`Offset`が表すExponential Histogramの密（dense）レイアウトへ変換されます。

  - `PositiveDeltas`は差分エンコードされたバケットカウントであり、最初の値は絶対的なバケットカウントで、以降の各値は直前の値との差分です。
  - Exponential Histogramの`Positive`の`Offset`は、スパンが存在する場合は最初の`PositiveSpan`の`Offset`から1を引いた値（`PositiveSpans[0].Offset-1`）に設定され、そうでなければ0のままにされます。1を引くのは、Prometheus Native Histogramのバケットが上限境界でインデックス付けされる一方、Exponential Histogramは下限境界でインデックス付けされるためです。
  - `PositiveSpans`は、`PositiveDeltas`内の各値について、`Positive`バケットカウントへのインデックスをエンコードします。インデックスは最初のスパンについては0から始まり、以降のスパンについては、そのスパンの`Offset`を直前のインデックスに加算します。スパンの`Length`は、使用する連続したインデックスの数を示します。
  - Native Histogramにはオーバーフローバケットが含まれることがあります。Exponential Histogramバケットへ変換する場合、オーバーフローバケットはIEEE浮動小数点数の範囲外の値へマッピングされることになります。オーバーフローバケットは破棄しなければならず（MUST）、全体の`Count`にも数えてはなりません（MUST NOT）。

- `NegativeSpans`と`NegativeDeltas`は、正のバケットと同じ方法で変換されます。
- `Min`と`Max`は設定されません。
- `StartTimeUnixNano`は、利用可能であれば`Start Timestamp`のタイムスタンプに設定されます。
- `AggregationTemporality`は`cumulative`に設定されます。

カスタムバケット付きのNative Histogram（NHCB）スキーマ（すなわちスキーマ-53）を持ち、整数型かつCounterの[flavor](https://prometheus.io/docs/specs/native_histograms/#flavors)であるものは、以下のようにOTLP Histogramへ変換されなければなりません（MUST）。

- Native Histogramの`ResetHint`（または`CounterResetHint`）がgauge型を示す場合、そのNative Histogramは破棄されます。それ以外の場合、このフィールドは無視されます。
- `Sum`が[Stale NaNの値](https://github.com/prometheus/prometheus/blob/main/model/value/value.go)と等しい場合、`NoRecordedValue`フラグは`true`に設定されます。そうでない場合、
  - `Count`はHistogramの`Count`へ変換されます。`Count`はすべてのバケットカウントの合計に等しいことに注意してください。
  - `Sum`はHistogramの`Sum`へ変換されます。Native Histogramが値`NaN`、あるいは`-Inf`と`+Inf`の両方を観測した場合、`Sum`は`NaN`になることがあることに注意してください。`Sum`は`-Inf`または`+Inf`になることもあります。
- `Timestamp`は、ミリ秒をナノ秒に変換した上で、Histogramの`TimeUnixNano`へ変換されます。
- `Min`と`Max`は設定されません。
- [`CustomValues`](https://prometheus.io/docs/specs/native_histograms/#custom-values)はバケット境界へ変換されます。`+Inf`バケットは暗黙的であるため、`N`個の`CustomValues`は`N+1`個のHistogramバケットカウントを表します。
- `PositiveSpans`と`PositiveDeltas`が表す[疎バケットレイアウト](https://prometheus.io/docs/specs/native_histograms/#buckets)は、Histogramのバケットカウントへ変換されます。

  - `PositiveDeltas`は差分エンコードされたバケットカウントであり、最初の値は絶対的なバケットカウントで、以降の各値は直前の値との差分です。
  - `PositiveSpans`は、`PositiveDeltas`内の各値について、バケットカウントへのインデックスをエンコードします。インデックスは最初のスパンの`Offset`から始まり、以降のスパンについては、そのスパンの`Offset`を直前のインデックスに加算します。スパンの`Length`は、使用する連続したインデックスの数を示します。

- `StartTimeUnixNano`は、利用可能であれば`Start Timestamp`に設定されます。
- `AggregationTemporality`は`cumulative`に設定されます。

floatまたはgaugeのflavorを持つNative Histogramは破棄されなければなりません（MUST）。

`Schema`が[-4, 8]の範囲外であり、かつ-53とも等しくないNative Histogramは破棄されなければなりません（MUST）。

Prometheus Native Histogramのサンプルにあるエグゼンプラーは、[Exemplars](#exemplars)の規則に従って、OpenTelemetry Exponential HistogramデータポイントのOpenTelemetryエグゼンプラーへ変換されなければなりません（MUST）。

### Summaries

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

[Prometheus Summary](https://prometheus.io/docs/instrumenting/exposition_formats/#basic-info)は、[OTLP Summary](/works/otel-specs-ja/spec/metrics/data-model/#summary-legacy)へ変換されなければなりません（MUST）。

Prometheus SummaryのQuantileはOTLP SummaryのQuantileになります。Prometheus Summaryのカウントは OTLP Summaryのカウントになり、Prometheus Summaryのサムは OTLP Summaryのサムになります。

テキスト形式では、サフィックスを持たないサンプルは、Prometheus Summaryの分位点を識別するための`quantile`ラベルを持ちます。同じメトリクス名を持つが`_count`と`_sum`のサフィックスを持つ追加のサンプルは、それぞれPrometheus Summaryのカウントとサムを識別するために使われます。

Prometheus Summaryが複数のサンプルで表現されるテキスト形式では、同じ[メトリクスファミリー](https://github.com/prometheus/OpenMetrics/blob/main/specification/OpenMetrics.md#metricfamily)名を持つサンプルは、単一のOTLP Summaryへマージされなければなりません（MUST）。

* `_count`が存在しない場合、そのメトリクスは破棄されなければなりません（MUST）。
* `_sum`が存在しない場合、Summaryのサムは[ゼロに設定されなければなりません](https://github.com/open-telemetry/opentelemetry-proto/blob/d8729d40f629dba12694b44c4c32c1eab109b00a/opentelemetry/proto/metrics/v1/metrics.proto#L601)（MUST）。

### Dropped Types

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

以下のPrometheusの型は破棄されなければなりません（MUST）。

* [Prometheus GaugeHistogram](https://github.com/prometheus/OpenMetrics/blob/v1.0.0/specification/OpenMetrics.md#gaugehistogram)
* [Prometheus Native GaugeHistogram](https://prometheus.io/docs/specs/native_histograms/#gauge-histograms-vs-counter-histograms)

### Exemplars

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

[Prometheusエグゼンプラー](https://github.com/prometheus/OpenMetrics/blob/v1.0.0/specification/OpenMetrics.md#exemplars)は、以下のようにOpenTelemetryエグゼンプラーへ変換されなければなりません（MUST）。

* タイムスタンプが存在する場合、それはOpenTelemetryエグゼンプラーのタイムスタンプとして使わなければなりません（MUST）。
* `trace_id`と`span_id`ラベルが存在し、その値が有効なTrace IDとSpan IDである場合、それぞれOpenTelemetryエグゼンプラーのTrace IDとSpan IDへ変換されなければなりません（MUST）。
* `trace_id`と`span_id`以外のすべてのラベルは、フィルタリングされた属性としてOpenTelemetryエグゼンプラーに追加されなければなりません（MUST）。

### Instrumentation Scope

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

`otel_scope_`という接頭辞を持つラベルは、すべてのメトリクスポイントから破棄されなければならず（MUST）、Instrumentation Scopeの名前（`otel_scope_name`）、バージョン（`otel_scope_version`）、Schema URL（`otel_scope_schema_url`）、属性（`otel_scope_[属性]`）として使われます。

```
# TYPE http_server_duration counter
http_server_duration{otel_scope_name="go.opentelemetry.io.contrib.instrumentation.net.http.otelhttp",otel_scope_schema_url="https://opentelemetry.io/schemas/1.31.0",otel_scope_version="v0.24.0",otel_scope_library_mascot="gopher"...} 1
```

は以下になります。

```yaml
# within a resource_metrics
scope_metrics:
  scope:
    name: go.opentelemetry.io.contrib.instrumentation.net.http.otelhttp
    version: v0.24.0
    attributes:
      library_mascot: gopher
  schema_url: https://opentelemetry.io/schemas/1.31.0 
  metrics:
  - name: http_server_duration
    data:
      sum:
        data_points:
        - value: 1
```

`otel_scope_`という接頭辞を持つラベルを一切持たないメトリクスには、Prometheusから OpenTelemetryへの変換を行うエンティティ（例えばCollectorのPrometheusレシーバー）を識別するInstrumentation Scopeが割り当てられなければなりません（MUST）。

### Resource Attributes

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

Prometheusエンドポイントをスクレイピングする際、他のPrometheusエンドポイントからのメトリクスと区別するために、リソース属性がスクレイピングされたメトリクスに追加されなければなりません（MUST）。特に、Prometheusエクスポーターが[`job`と`instance`ラベル](https://prometheus.io/docs/concepts/jobs_instances/)を使ってメトリクスを一意に区別できるようにするため、`service.name`と`service.instance.id`が必要です（[後述](#resource-attributes-1)のとおりです）。

以下の属性は、スクレイピングされたメトリクスにリソース属性として関連付けられなければならず（MUST）、メトリクス属性として追加してはなりません（MUST NOT）。

| OTLPリソース属性 | 説明 |
| ----------------------- | ----------- |
| `service.name` | 対象が属するサービスの設定済みの名前 |
| `service.instance.id` | 対象の一意な識別子。既定では、スクレイピングされたURLの`<host>:<port>`にすべきです |

以下の属性は、スクレイピングされたメトリクスにリソース属性として関連付けるべきであり（SHOULD）、メトリクス属性として追加してはなりません（MUST NOT）。

| OTLPリソース属性 | 説明 |
| ----------------------- | ----------- |
| `server.address` | スクレイピングされた対象のURLの`<host>`部分 |
| `server.port` | スクレイピングされた対象のURLの`<port>`部分 |
| `url.scheme` | `http`または`https` |

上記の属性に加えて、[target](https://github.com/prometheus/OpenMetrics/blob/v1.0.0/specification/OpenMetrics.md#supporting-target-metadata-in-both-push-based-and-pull-based-systems) Infoメトリクスは、追加のリソース属性を提供するために使われます。`target` Infoメトリクスが存在する場合、それはメトリクスのバッチから破棄されなければならず（MUST）、`target` Infoメトリクスのすべてのラベルは、そのスクレイプの一部である他のすべてのメトリクスに付随するリソース属性へ変換されなければなりません（MUST）。既定では、ラベルのキーと値は（キー内の`_`を`.`文字に置き換えるなどの）変更を加えられてはなりません（MUST NOT）。

## OTLP Metric points to Prometheus

### Metric Metadata

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

OpenTelemetryのメトリクスデータに対するPrometheus Pull用エクスポーターは、Prometheusエンドポイントの単一のスクレイプにおいて、同じメトリクス名について重複するUNIT、HELP、TYPEのコメントを返すことを許してはなりません（MUST NOT）。エクスポーターは、競合するTYPEコメントを避けるためメトリクス全体を破棄しなければなりません（MUST）が、競合するUNITやHELPコメントの結果としてメトリクスポイントを破棄すべきではありません（SHOULD NOT）。代わりに、競合するUNITとHELPコメント（メトリクスポイントは除く）のうち1つを除くすべてを破棄すべきです（SHOULD）。コメントやメトリクスポイントを破棄する場合、エクスポーターはエラーログを通じて利用者に警告すべきです（SHOULD）。なお、SDKは、同じ問題を示す[計装の重複登録について利用者へ警告することが要求されている](/works/otel-specs-ja/spec/metrics/sdk/#duplicate-instrument-registration)ことに注意してください。

OTLPメトリクスの名前は、[Prometheusのメトリクス名](https://prometheus.io/docs/instrumenting/exposition_formats/#comments-help-text-and-type-information)として追加されなければなりません（MUST）。Prometheusの命名規則は、メトリクス名が正規表現`[a-zA-Z_:]([a-zA-Z0-9_:])*`に一致することを推奨しています。Prometheusの規約との互換性を目指し、メトリクス名の中で推奨されない文字は、既定では`_`文字に置き換えるべきです（SHOULD）。連続する複数の`_`文字は、単一の`_`文字に置き換えるべきです（SHOULD）。

OTLPメトリクスポイントの単位は、[上記のMetric Metadata](#metric-metadata)にある表に含まれる場合、UCUMの単位からPrometheusにおける相当する単語へ変換されなければなりません（MUST）。

角括弧内の単位の部分（例えば{packet}）は破棄されなければなりません（MUST）。

時間に対する比率として定義された単位（例えば"m/s"）は、単語（例えば"meters_per_second"）へ変換されなければなりません（MUST）。

変換後の単位は、[UNITメタデータ](https://github.com/prometheus/OpenMetrics/blob/v1.0.0/specification/OpenMetrics.md#metricfamily)としてメトリクスに追加すべきです（SHOULD）。メトリクス名が（型固有のサフィックスの前で）既に単位で終わっていない限り、メトリクス名にサフィックスを追加すべきです（SHOULD）。単位のサフィックスは、型固有のサフィックスより前に置かれます。

OTLPメトリクスポイントの説明は、[HELPメタデータ](https://prometheus.io/docs/instrumenting/exposition_formats/#comments-help-text-and-type-information)として追加されなければなりません（MUST）。

OTLPメトリクスのデータポイントの型は、[TYPEメタデータ](https://prometheus.io/docs/instrumenting/exposition_formats/#comments-help-text-and-type-information)として追加されなければなりません（MUST）。これは、以下に列挙する型固有の変換規則も左右します。

### Instrumentation Scope

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

Prometheusエクスポーターは、元のデータポイントが入れ子になっていたScopeに基づき、既定でスコープ名を`otel_scope_name`ラベル、スコープバージョンを`otel_scope_version`ラベル、スコープのSchema URLを`otel_scope_schema_url`ラベルとして、すべてのメトリクスポイントに追加しなければならず（MUST）、スコープ属性は以下の[`Metric Attributes`](#metric-attributes)の節で説明する規則に従って`otel_scope_`という接頭辞を持つラベルとして追加しなければなりません（MUST）。`otel_scope_`接頭辞を追加し、[`Metric Attributes`](#metric-attributes)で説明されているラベル名の変換を適用した後に、`otel_scope_name`、`otel_scope_version`、`otel_scope_schema_url`と衝突することになるスコープ属性は、破棄されなければなりません（MUST）。

### Gauges

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

[OpenTelemetry Gauge](/works/otel-specs-ja/spec/metrics/data-model/#gauge)は、[metric.metadata][metricMetadata]内のヒントに従って変換されなければなりません（MUST）。
- `prometheus.type`キーが存在しない、またはその値が`gauge`と等しい場合、そのデータポイントはPrometheus Gaugeへ変換されなければなりません（MUST）。
- `prometheus.type`キーの値が`unkown`と等しい場合、そのデータポイントはPrometheus Unknownへ変換されなければなりません（MUST）。
- `prometheus.type`キーの値が`info`と等しい場合、そのデータポイントはPrometheus Infoへ変換すべきです（SHOULD）。
- `prometheus.type`キーの値が`stateset`と等しい場合、そのデータポイントはPrometheus Statesetへ変換すべきです（SHOULD）。

OpenTelemetry Gaugeにあるエグゼンプラーは破棄すべきです（SHOULD）。

### Sums

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

[OpenTelemetry Sum](/works/otel-specs-ja/spec/metrics/data-model/#sums)は、以下の規則に従って変換されなければなりません（MUST）。

- 集約時間的性質（aggregation temporality）がcumulativeであり、そのSumがモノトニックである場合、Prometheus Counterへ変換されなければなりません（MUST）。
- 集約時間的性質がcumulativeであり、そのSumが非モノトニックである場合、[OpenTelemetry Gauge](#gauges-1)について説明されているのと同じ規則に従うべきです（SHOULD）。
- 集約時間的性質がdeltaであり、そのSumがモノトニックである場合、cumulativeな時間的性質へ変換し、Prometheus Counterになってもかまいません（MAY）。以下の挙動が期待されます。
  - 新しいデータポイントの型は、蓄積されたデータポイントの型と同じでなければなりません（MUST）。
  - 新しいデータポイントの開始時刻は、蓄積されたデータポイントの時刻と一致しなければなりません（MUST）。一致しない場合は、[整合性の問題の検出](/works/otel-specs-ja/spec/metrics/data-model/#sums-detecting-alignment-issues)を参照してください。

モノトニックなSumメトリクスポイントのメトリクス名が`_total`というサフィックスで終わっていない場合、既定では`_total`というサフィックスを追加すべきです（SHOULD）。そうでない場合、名前は変更されないままでなければなりません（MUST）。

`StartTimeUnixNano`を持つモノトニックなSumメトリクスポイントは、各Prometheusプロトコルで使われる適切な形式に従って、`StartTimeUnixNano`をPrometheusの`StartTime`へ変換すべきです（SHOULD）。

SumがPrometheus Counterへ変換される場合、`Exemplars`は[Exemplar Conversion](#exemplar-conversion)の節で説明されているように変換されなければなりません（MUST）。そうでない場合、`Exemplars`は破棄すべきです（SHOULD）。Prometheusプロトコルが、Counterのサンプルについて単一のエグゼンプラーしかサポートしない場合、最新のエグゼンプラーを変換すべきです（SHOULD）。これは、Counter Instrumentについて最新のエグゼンプラーを保持するというPrometheusクライアントライブラリの挙動と一致します。

### Histograms

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

cumulativeな集約時間的性質を持つ[OpenTelemetry Histogram](/works/otel-specs-ja/spec/metrics/data-model/#histogram)は、既定でPrometheus Histogramへ変換されなければなりません（MUST）。

[Development](../../document-status/): Prometheusプロトコルが許可する場合、利用者はOpenTelemetry HistogramをPrometheus Protocolが許可する[カスタムバケット付きのPrometheus Native Histogram](#histograms-as-prometheus-nhcb)（NHCB）へ変換することをオプトインで選べます。

Deltaな集約時間的性質を持つOpenTelemetry Histogramは、Cumulativeな集約時間的性質へ集約して以下のロジックに従ってもよい（MAY）ものとし、そうでなければ破棄されなければなりません（MUST）。

#### Histograms as Prometheus Histograms

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

Prometheus Histogramへ変換する場合、OpenTelemetry Histogramは以下の規則に従って変換されなければなりません（MUST）。

- `Count`はHistogramの`Count`へ変換されます。
- `Sum`はHistogramの`Sum`へ変換されます。Histogram内のすべての観測値が正またはゼロである場合、そのサムは正でモノトニックになります。
- `ExplicitBounds`のバケット境界と暗黙の`+Inf`境界、および`BucketCounts`は、`ExplicitBounds`の値の昇順でHistogramの`Buckets`へ変換されます。各バケットについて、明示的な境界は上限境界へ変換され、現在のバケットまでのすべてのバケットカウントの合計が累積カウントへ変換されます。
- `StartTimeUnixNano`が設定されている場合、各Prometheusプロトコルで使われる適切な形式に従って、Prometheusの`StartTime`へ変換すべきです（SHOULD）。
- `Min`と`Max`は使われません。
- `Exemplars`は[Exemplar Conversion](#exemplar-conversion)の節で説明されているように変換されます。Prometheusプロトコルがバケットごとに単一のエグゼンプラーしかサポートしない場合、各バケットに該当する最新のエグゼンプラーを変換すべきです（SHOULD）。

#### Histograms as Prometheus NHCB

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

NHCBの出力は、現在[Prometheus Remote-Write 2.0以降](https://prometheus.io/docs/specs/prw/remote_write_spec_2_0/)のプロトコルでのみサポートされています。

Prometheus NHCBへ変換する場合、単一のNHCBメトリクスのみが作成されなければなりません（MUST）。

- NHCBの[flavor](https://prometheus.io/docs/specs/native_histograms/#flavors)は整数型のCounterでなければなりません（MUST）。
- NHCB内の`ResetHint`は`UNKNOWN`に設定されなければなりません（MUST）。OpenTelemetryは明示的なリセットフラグを持たないため、`UNKNOWN`によってPrometheusが値からリセットを自動検出でき、OpenTelemetryのリセットモデルとの意味的な相違も避けられます。
- NHCB内の`Schema`は-53に設定されなければなりません（MUST）。
- `TimeUnixNano`は、ナノ秒をミリ秒に変換した上でPrometheusの`Timestamp`へ変換されます。
- `StartTimeUnixNano`が設定されている場合、各Prometheusプロトコルで使われる適切な形式に従って、Prometheusの`StartTime`へ変換すべきです（SHOULD）。
- `ExplicitBounds`のバケット境界は、昇順でNHCBの`CustomValues`へ書き込まれます。暗黙の`+Inf`上限境界は`CustomValues`に書き込んではならず（MUST NOT）、インデックス`len(CustomValues)`のオーバーフローバケットによって表されます。
- ここで明示的に言及されていないNHCBのすべてのフィールドは、zero threshold、zero count、negative spans、negative deltasなど、そのゼロ値に設定されなければなりません（MUST）。
- `Min`と`Max`は使われません。
- `Exemplars`は、[Exemplar Conversion](#exemplar-conversion)の節で説明されているように、Native Histogramのフラットな`Exemplars`のリストへ変換されます。
- `NoRecordedValue`フラグが`true`に設定されている場合、NHCBは[stale](https://prometheus.io/docs/specs/native_histograms/#staleness-markers)としてマークされなければなりません（MUST）。
  - Native Histogramの`Sum`はStale NaNの値に設定されなければなりません（MUST）。
  - Native Histogramの`Count`はゼロに設定されなければなりません（MUST）。`PositiveSpans`と`PositiveDeltas`は空のままにしなければなりません（MUST）。
- `NoRecordedValue`フラグが`false`に設定されている場合、
  - `Count`はNative Histogramの`Count`へ変換されます。
  - `Sum`はNative Histogramの`Sum`へ変換されます。
  - 密な`BucketCounts`は、[疎バケットレイアウト](https://prometheus.io/docs/specs/native_histograms/#buckets)の`PositiveSpans`と`PositiveDeltas`へ変換されます（負の境界を持つバケットについても同様です）。
    - ゼロでないバケットカウントは`PositiveDeltas`へ変換されなければなりません（MUST）。ゼロカウントのバケットも、（スパンの間にギャップを作るのではなく）それを囲むスパンを拡張し、`PositiveSpans`の数を減らすために、`PositiveDeltas`に含めてもかまいません（MAY）。
    - 変換が必要なバケットカウントは、差分エンコードされた`PositiveDeltas`へ変換されます。最初に変換された値はそのまま書き込まれ、残りは直前に変換された値との差分として書き込まれます。[Prometheus Histogram](#histograms-as-prometheus-histograms)への変換とは異なり、バケットをまたいだ累積の合算は不要です。OpenTelemetryとNative Histogramのバケットカウントは、すでにバケットごとの値になっているためです。
    - `PositiveSpans`は、`PositiveDeltas`内の各値について、`CustomValues`へのインデックスをエンコードします。最初のスパンの`Offset`は、最初に変換されたバケットの上限境界のインデックス（`CustomValues`内の0始まり）です。以降のスパンについては、`Offset`は、直前のスパンの終わりから今回のスパンの開始までの間で変換されなかったバケットの数です。`Length`は、そのスパン内で連続して変換されたバケットの数です。
    - 例: バケット境界が`-2, -1, 0, 1, 2, +Inf`で、バケットカウントが`10, 0, 0, 20, 5, 2`の場合、`CustomValues`は`-2, -1, 0, 1, 2`になります。ゼロでないバケットカウント`10, 20, 5, 2`のみを変換する場合、`PositiveSpans`は`{Offset: 0, Length: 1}, {Offset: 2, Length: 3}`になり、`PositiveDeltas`は`10, 10, -15, -3`になります。

### Exponential Histograms

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

cumulativeな集約時間的性質を持つ[OpenTelemetry Exponential Histogram](/works/otel-specs-ja/spec/metrics/data-model/#exponentialhistogram)は、以下のようにPrometheus Native Histogramへ変換されなければなりません（MUST）。

- `Scale`はNative Histogramの`Schema`へ変換されます。現時点で、`schema`の[有効な値](https://github.com/prometheus/prometheus/commit/d9d51c565c622cdc7d626d3e7569652bc28abe15#diff-bdaf80ebc5fa26365f45db53435b960ce623ea6f86747fb8870ad1abc355f64fR76-R83)は-4 <= n <= 8です。`Scale`が8より大きい場合、Exponential Histogramのデータポイントは、Prometheusが受け付ける範囲（[-4,8]）へダウンスケールすべきです（SHOULD）。許容範囲へリスケールできないデータポイントは破棄しなければなりません（MUST）。
- `NoRecordedValue`フラグが`false`に設定されている場合、`Count`はNative Histogramの`Count`へ変換されます。そうでない場合、Native Histogramの`Count`はStale NaNの値に設定されます。
- `Sum`が設定されており、`NoRecordedValue`フラグが`false`に設定されている場合、`Sum`はNative Histogramの`Sum`へ変換されます。そうでない場合、Native Histogramの`Sum`はStale NaNの値に設定されます。
- `TimeUnixNano`は、ナノ秒をミリ秒に変換した上でNative Histogramの`Timestamp`へ変換されます。
- `ZeroCount`は、そのままNative Histogramの`ZeroCount`へ変換されます。
- `ZeroThreshold`が設定されている場合、Native Histogramの`ZeroThreshold`へ変換されます。そうでない場合、既定値の`1e-128`に設定されます。
- `Positive`バケットカウントと`Offset`が表す密なバケットレイアウトは、`PositiveSpans`と`PositiveDeltas`が表すNative Histogramの疎なレイアウトへ変換されます。`Negative`バケットカウントと`Offset`についても同様です。Prometheus Native Histogramのバケットは上限境界でインデックス付けされる一方、Exponential Histogramは下限境界でインデックス付けされるため、結果としてOffsetフィールドは1つずれることに注意してください。
- `Min`と`Max`は使われません。
- `StartTimeUnixNano`は使われません。
- `Exemplars`は[Exemplar Conversion](#exemplar-conversion)の節で説明されているように変換されます。

deltaな集約時間的性質を持つ[OpenTelemetry Exponential Histogram](/works/otel-specs-ja/spec/metrics/data-model/#exponentialhistogram)メトリクスは破棄されます。

### Summaries

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

[OpenTelemetry Summary](/works/otel-specs-ja/spec/metrics/data-model/#summary-legacy)は、以下のようにPrometheus Summaryへ変換されなければなりません（MUST）。

- 属性は[`Metric Attributes`](#metric-attributes)の節で説明されているように変換されます。
- カウントはSummaryのカウントへ変換されます。
- サムはSummaryのサムへ変換されます。
- QuantileはSummaryのQuantileへ変換されます。`quantile`ラベルの値は、最低から最高までの順に並んだ、すべて非負である各Quantile（0.0から1.0の間）の文字列化された浮動小数点数値でなければなりません（MUST）。各Quantileの値は、そのQuantile点の計算済みの値です。
- Prometheus Remote Writeのようなプッシュ型のプロトコルを使う場合、`time_unix_nano`はSummaryのタイムスタンプへ変換されます。Prometheusがスクレイプのタイムスタンプを割り当てる、Prometheusテキスト表現形式のようなプル型のプロトコルでは、明示的なタイムスタンプを使うべきではありません（SHOULD NOT）。
- `start_time_unix_nano`は、サポートされている場合、Summaryの開始タイムスタンプへ変換されます。

OpenTelemetry Summaryにあるエグゼンプラーは破棄すべきです（SHOULD）。

### Metric Attributes

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

OpenTelemetryのメトリクス属性は、[Prometheusのラベル](https://prometheus.io/docs/concepts/data_model/#metric-names-and-labels)へ変換されなければなりません（MUST）。文字列型の属性値はそのままメトリクス属性へ変換され、文字列型でない属性値は、[属性の仕様](/works/otel-specs-ja/spec/common/#anyvalue-representation-for-non-otlp-protocols)に従って文字列型の属性へ変換されなければなりません（MUST）。Prometheusの命名規則は、メトリクス名が以下の正規表現に一致することを推奨しています。`[a-zA-Z_]([a-zA-Z0-9_])*`。推奨されない文字は`_`文字に置き換えるべきです（SHOULD）。連続する複数の`_`文字は、単一の`_`文字に置き換えるべきです（SHOULD）。この変換や、本仕様書によって追加される他のラベル（例えば`otel_scope_name`）により、異なるOpenTelemetryのキーが同じPrometheusのキーへマッピングされることがあります。そのような場合、値は`;`で区切り、元のキーの字句順で連結されなければなりません（MUST）。

### Exemplar Conversion

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

上記のメトリクス型固有の節に従ってエグゼンプラーが変換される場合、使われているPrometheusの（プッシュまたはプル）プロトコルがサポートしていれば、[OpenTelemetryエグゼンプラー](/works/otel-specs-ja/spec/metrics/data-model/#exemplars)は以下のようにPrometheusエグゼンプラーへ変換されなければなりません（MUST）。

* OpenTelemetryエグゼンプラーのTrace IDとSpan IDが存在する場合、それぞれ`trace_id`と`span_id`キーを使ってエグゼンプラーラベルとして追加されなければなりません（MUST）。キーが競合する場合、これらのラベルは`filtered_attributes`由来のラベルより優先されなければなりません（MUST）。
* タイムスタンプは、Prometheusエグゼンプラーのタイムスタンプとして追加されなければなりません（MUST）。
* `filtered_attributes`は、Prometheusプロトコルのエグゼンプラーの上限を超えない限り、Prometheusエグゼンプラーのラベルとして追加されなければなりません（MUST）。例えば、OpenMetrics 1.0は[128文字の上限](https://github.com/prometheus/OpenMetrics/blob/v1.0.0/specification/OpenMetrics.md#exemplars)を課しています。

### Resource Attributes

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

Prometheusエクスポーターでは、OpenTelemetryのResourceが[空](/works/otel-specs-ja/spec/resource/sdk/#空のリソース)でない場合、それは[`target` Infoメトリクス](https://github.com/prometheus/OpenMetrics/blob/v1.0.0/specification/OpenMetrics.md#supporting-target-metadata-in-both-push-based-and-pull-based-systems)へ変換すべきです（SHOULD）。Resource属性は、エクスポーターの設定によって必要であれば、エクスポートされるメトリクスファミリーのラベルへコピーしてもよく（MAY）、そうでなければ破棄しなければなりません（MUST）。`target` Infoメトリクスは、そのラベルにResource属性を含まなければならず（MUST）、他のラベルを含んではならない（MUST NOT）、Info型のメトリクスでなければなりません（MUST）。

Collectorが提供するPrometheusエクスポーターでは、複数の対象からのメトリクスが一緒に送出されることがあるため、対象を互いに区別する必要があります。しかし、Prometheusの表現形式と[remote-write](https://github.com/Prometheus/Prometheus/blob/main/prompb/remote.proto)形式はResourceという概念を含んでおらず、スクレイピングされた対象を区別するためにメトリクスラベルを使うことを想定しています。慣習的に、[`job`と`instance`](https://prometheus.io/docs/concepts/jobs_instances/)ラベルは対象を区別するために使われ、Prometheus Pullエクスポーター（["federated"](https://prometheus.io/docs/prometheus/latest/federation/) Prometheusエンドポイント）で公開されるメトリクス、またPrometheus remote-write経由でプッシュされるメトリクスに存在することが期待されます。OpenTelemetryのセマンティック規約では、`service.name`、`service.namespace`、`service.instance.id`の三つ組が[一意であることが要求されており](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/README.md#service)、そのため`job`と`instance`を構成するために使う良い候補になります。CollectorのPrometheusエクスポーターでは、`service.name`と`service.namespace`属性は、`job`メトリクスラベルを構成するために`<service.namespace>/<service.name>`として（namespaceが空の場合は`<service.name>`として）結合されなければなりません（MUST）。`service.instance.id`属性は、存在する場合は`instance`ラベルへ変換されなければならず（MUST）、そうでない場合は`instance`を空の値で追加すべきです（SHOULD）。他のResource属性は[target](https://github.com/prometheus/OpenMetrics/blob/v1.0.0/specification/OpenMetrics.md#supporting-target-metadata-in-both-push-based-and-pull-based-systems) Infoメトリクスへ変換すべきであり（SHOULD）、そうでなければ破棄しなければなりません（MUST）。`target`メトリクスは、そのラベルにResource属性を含まなければならず（MUST）、`job`と`instance`以外の他のラベルを含んではならない（MUST NOT）、Info型のメトリクスです。一意な`job`と`instance`の組み合わせごとに、エクスポートされる`target` Infoメトリクスは最大1つでなければなりません（MUST）。

言語のPrometheusクライアントライブラリがInfo型のメトリクスファミリーをまだサポートしていない場合、代わりに値1の定数を持つ、`target_info`という名前のgauge型のメトリクスファミリーを使わなければなりません（MUST）。

OTLPのResource属性をPrometheusのラベルへ変換するには、文字列型の属性値はそのままラベルへ変換され、文字列型でない属性値は[属性の仕様](/works/otel-specs-ja/spec/common/#attribute)に従って文字列型の属性へ変換されなければなりません（MUST）。

[metricMetadata]: https://github.com/open-telemetry/opentelemetry-proto/blob/c451441d7b73f702d1647574c730daf7786f188c/opentelemetry/proto/metrics/v1/metrics.proto#L199

