Skip to content
Open
Changes from 3 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
dcdb927
Prometheus: define more precisely the conversion of resource attributes
krajorama Oct 14, 2026
e89b7d4
add notes on the OTLP to Prometheus side
krajorama Oct 15, 2026
6709a74
Exclude __name__, le and quantile from data point attributes
krajorama Oct 19, 2026
933ed01
Move inline notes to PR review comments
krajorama Oct 19, 2026
80b9712
Fix K8s spelling
krajorama Oct 19, 2026
a119e89
Remove remaining inline notes
krajorama Oct 19, 2026
1cb54d4
Apply suggestion from @krajorama
krajorama Oct 19, 2026
2377f29
Add changelog entry
krajorama Oct 19, 2026
86ff3b9
Rename Prometheus to OTLP metric attributes section to Metric Labels
krajorama Oct 26, 2026
5c438ee
Apply suggestion from @krajorama
krajorama Oct 26, 2026
528d2d6
Simplify job and instance fallback rules for scraped metrics
krajorama Oct 27, 2026
264eda5
Clarify which metrics receive target info resource attributes
krajorama Oct 27, 2026
56b5c6e
Merge branch 'main' into krajo/clarify-otel-prom-comp
krajorama Oct 27, 2026
7cdfcf6
Apply suggestion from @aknuds1
krajorama Nov 2, 2026
713c587
Apply suggestion from @krajorama
krajorama Nov 2, 2026
7a9dadd
Split Prometheus to OTLP resource attributes into pull and push rules
krajorama Nov 2, 2026
3eed842
move the changelog entry
krajorama Nov 9, 2026
6c4c1ea
Merge remote-tracking branch 'upstream/main' into krajo/clarify-otel-…
krajorama Nov 9, 2026
eebb6a8
update the server.address, server.port, url.scheme mapping
krajorama Nov 9, 2026
401d5cc
clarify text around empty string keys
krajorama Nov 9, 2026
6c6e850
Update the changelog to include the change as well explicitly.
krajorama Nov 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 108 additions & 22 deletions specification/compatibility/prometheus_and_openmetrics.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
* [Dropped Types](#dropped-types)
* [Exemplars](#exemplars)
* [Instrumentation Scope](#instrumentation-scope)
* [Metric Attributes](#metric-attributes)
* [Resource Attributes](#resource-attributes)
- [OTLP Metric points to Prometheus](#otlp-metric-points-to-prometheus)
* [Metric Metadata](#metric-metadata-1)
Expand All @@ -40,7 +41,7 @@
+ [Histograms as Prometheus NHCB](#histograms-as-prometheus-nhcb)
* [Exponential Histograms](#exponential-histograms)
* [Summaries](#summaries-1)
* [Metric Attributes](#metric-attributes)
* [Metric Attributes](#metric-attributes-1)
Comment thread
krajorama marked this conversation as resolved.
Resolved
* [Exemplar Conversion](#exemplar-conversion)
* [Resource Attributes](#resource-attributes-1)

Expand Down Expand Up @@ -368,42 +369,118 @@
the translation from Prometheus to OpenTelemetry (e.g. the collector's
Prometheus receiver).

### Metric Attributes
Comment thread
krajorama marked this conversation as resolved.
Resolved

**Status**: [Development](../document-status.md)

Labels of metrics MUST be copied to data point attributes, except for the
following labels, which MUST NOT be copied:

- `__name__`,
Comment thread
dashpole marked this conversation as resolved.
Resolved
- `job` and `instance`,
Comment thread
dashpole marked this conversation as resolved.
Resolved
- the `le` label of classic Prometheus histogram buckets,
- the `quantile` label of Prometheus summaries,
- labels with the `otel_scope_` prefix, which are handled according to the
[Instrumentation Scope](#instrumentation-scope) rules.

Labels of the `target` info metric are implicitly excluded, as `target` info
metric samples are not turned into data points.

### Resource Attributes

**Status**: [Development](../document-status.md)

When scraping a Prometheus endpoint, resource attributes MUST be added to the
Comment thread
dashpole marked this conversation as resolved.
Resolved
Comment thread
dashpole marked this conversation as resolved.
Resolved
scraped metrics to distinguish them from metrics from other Prometheus
endpoints. In particular, `service.name` and `service.instance.id`, are needed
to ensure Prometheus exporters can disambiguate metrics using
[`job` and `instance` labels](https://prometheus.io/docs/concepts/jobs_instances/)
as [described below](#resource-attributes-1).
endpoints.

NOTE(krajo): this only talks about scraping, but similar rules apply to remote

Check warning on line 397 in specification/compatibility/prometheus_and_openmetrics.md

View workflow job for this annotation

GitHub Actions / misspell

Unknown word (krajo) Suggestions: (Karo, Karoo, Harjo, kayo, kraal)
write receiver which uses `target` info metric. There are some differences
though.

TODO(krajo): deal with the remote write receiver use case.

Check warning on line 401 in specification/compatibility/prometheus_and_openmetrics.md

View workflow job for this annotation

GitHub Actions / misspell

Unknown word (krajo) Suggestions: (Karo, Karoo, Harjo, kayo, kraal)

In Prometheus metrics the `job` and `instance` are considered identifying,
Comment thread
dashpole marked this conversation as resolved.
Resolved
Comment thread
krajorama marked this conversation as resolved.
Resolved
therefore a new resource MUST be created for each `job` and `instance` pair
encountered in the metrics labels, except for the `target` info metric.

NOTE(krajo): both the prometheusreceiver and prometheusremotewritereceiver

Check warning on line 407 in specification/compatibility/prometheus_and_openmetrics.md

View workflow job for this annotation

GitHub Actions / misspell

Unknown word (prometheusremotewritereceiver)

Check warning on line 407 in specification/compatibility/prometheus_and_openmetrics.md

View workflow job for this annotation

GitHub Actions / misspell

Unknown word (prometheusreceiver)

Check warning on line 407 in specification/compatibility/prometheus_and_openmetrics.md

View workflow job for this annotation

GitHub Actions / misspell

Unknown word (krajo) Suggestions: (Karo, Karoo, Harjo, kayo, kraal)
work this way, thus both scrape and remote write can carry multiple resources
with the `job` and `instance` being the join key between regular metrics and
the `target` info metric.

If there is no `job` label on a metric and the metrics are being scraped,
then the `job` label MUST be considered to be equal to the `job` label of the
Comment thread
dashpole marked this conversation as resolved.
Resolved
scrape target. During scrape, the `job` label of the target may be equal to the scrape
job name or customized by relabel rules.
Comment thread
krajorama marked this conversation as resolved.
Resolved

If there is no `job` label on a metric and there is no `job` label for the
scrape target, the scrape MUST fail. Note that this is different from the
Comment thread
dashpole marked this conversation as resolved.
Resolved
Prometheus behavior that still scrapes the metrics without `job`.

If there is no `instance` label and the metrics are being scraped, the
`instance` label MUST be considered to be equal to the `instance` label of the
scrape target. Note that the `instance` label of the target may be equal to the
`__address__` of the target or customized by relabel rules.
Comment thread
krajorama marked this conversation as resolved.
Resolved

Comment thread
dashpole marked this conversation as resolved.
Resolved
For each resource the `service.name` attribute MUST be set to the
Comment thread
dashpole marked this conversation as resolved.
Resolved
`service.name` label in `target` info metric, if that label exists in the
`target` info metric with the same `job` and `instance` key as the resource.
Otherwise `service.name` MUST be set to the value of the `job` label.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The prometheusremotewritereceiver implementation currently splits job by / to derive service.namespace and service.name. If we agree this shouldn't happen, we should treat it as an implementation bug to be fixed rather than codifying the split here in the spec. I have opened open-telemetry/opentelemetry-collector-contrib#52626 to fix this.


NOTE(krajo): when an SDK uses default translation, then `service.name` is

Check warning on line 431 in specification/compatibility/prometheus_and_openmetrics.md

View workflow job for this annotation

GitHub Actions / misspell

Unknown word (krajo) Suggestions: (Karo, Karoo, Harjo, kayo, kraal)
translated into `service_name`, thus the `job` is copied into `service.name`
and `service_name` is also kept as a resource attribute.
This doesn't happen if there is no translation.

For each resource the `service.instance.id` attribute MUST be set to the
Comment thread
dashpole marked this conversation as resolved.
Resolved
`service.instance.id` label in `target` info metric, if that label exists in the
`target` info metric with the same `job` and `instance` key as the resource.
Otherwise `service.instance.id` MUST be set to the value of the `instance`
label.

NOTE(krajo): when an SDK uses default translation, then `service.instance.id` is

Check warning on line 442 in specification/compatibility/prometheus_and_openmetrics.md

View workflow job for this annotation

GitHub Actions / misspell

Unknown word (krajo) Suggestions: (Karo, Karoo, Harjo, kayo, kraal)
translated into `service_instance_id`, thus the `instance` is copied into
`service.instance.id` and `service_instance_id` is also kept as a resource
attribute.
This doesn't happen if there is no translation.

The following attributes MUST be associated with scraped metrics as resource
attributes, and MUST NOT be added as metric attributes:
The following attributes SHOULD be associated with scraped metrics as resource
attributes, and MUST NOT be added as metric
attributes:

| OTLP Resource Attribute | Description |
Comment thread
krajorama marked this conversation as resolved.
Resolved
| ----------------------- | ----------- |
| `service.name` | The configured name of the service that the target belongs to |
| `service.instance.id` | A unique identifier of the target. By default, it should be the `<host>:<port>` of the scraped URL |
| `server.address` | The `<host>` portion of the `instance` unless it is localhost, a loopback address, or an unspecified address |
Comment thread
dashpole marked this conversation as resolved.
Resolved
Comment thread
krajorama marked this conversation as resolved.
Resolved
| `server.port` | The `<port>` portion of the `instance` |
Comment thread
dashpole marked this conversation as resolved.
Resolved

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should keep server.address and server.port defined in terms of the scraped target address rather than instance (and omit server.port when no port is present, with an integer value per semconv), and treat the receiver's instance parsing as a bug.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO open issue/PR

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the existing spec on main already defines server.address and server.port in terms of the target's URL that was scraped, could we keep the target's URL that was scraped here (rather than changing it to instance) and file an issue in opentelemetry-collector-contrib to fix prometheusreceiver?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds like a plan, let's discuss in the meeting and I can make the change back or whatever we decide to write here

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in the meeting: we don't want to do this in the remote write receiver, prefer to set at scrape time only as original data

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also found from my review that we should preserve server.address and server.port in terms of the scraped target address.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that open-telemetry/opentelemetry-collector-contrib#52570 is merged, we can update server.address, server.port, and url.scheme here to reference the scraped target's URL (or post-relabeling __address__ and __scheme__ labels) rather than instance and pre-relabeling __scheme__.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done in eebb6a8

| `url.scheme` | `http` or `https` from the `__scheme__` label on the target |
Comment thread
krajorama marked this conversation as resolved.
Resolved

The following attributes SHOULD be associated with scraped metrics as resource
attributes, and MUST NOT be added as metric attributes:
NOTE(krajo): the receiver sets empty string for `server.port` if it cannot be
deduced, but perheaps this is a bug?

Check failure on line 459 in specification/compatibility/prometheus_and_openmetrics.md

View workflow job for this annotation

GitHub Actions / textlint

TextLint [common-misspellings]

This is a commonly misspelled word. Correct it to perhaps | 459:14

| OTLP Resource Attribute | Description |
| ----------------------- | ----------- |
| `server.address` | The `<host>` portion of the target's URL that was scraped |
| `server.port` | The `<port>` portion of the target's URL that was scraped |
| `url.scheme` | `http` or `https` |
NOTE(krajo): there is a bug in the receiver whereby it ignores the relabelling
of the `__scheme__`, so `url.scheme` always reflects the pre-relabelling state.

Further attributes (such as from k8s service discovery metadata labels) MAY be

Check failure on line 464 in specification/compatibility/prometheus_and_openmetrics.md

View workflow job for this annotation

GitHub Actions / textlint

TextLint [terminology]

Incorrect term: “k8s”, use “K8s” instead | 464:34
added to the resource attributes. Labels from the `target` info metric take
precedence over all derived resource attributes.

To summarize, `service.name` and `service.instance.id`, are needed
Comment thread
dashpole marked this conversation as resolved.
Resolved
to ensure Prometheus exporters can disambiguate metrics using
[`job` and `instance` labels](https://prometheus.io/docs/concepts/jobs_instances/)
as [described below](#resource-attributes-1), therefore this specification
ensures that `service.name` and `service.instance.id` are always defined.

In addition to the attributes above, the
[target](https://github.com/prometheus/OpenMetrics/blob/v1.0.0/specification/OpenMetrics.md#supporting-target-metadata-in-both-push-based-and-pull-based-systems)
[`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 metric is used to supply additional resource attributes. If present,
the `target` info metric MUST be dropped from the batch of metrics, and all labels from
the `target` info metric MUST be converted to resource attributes
attached to all other metrics which are part of the scrape. By default, label
keys and values MUST NOT be altered (such as replacing `_` with `.` characters
in keys).
the `target` info metric MUST be dropped from the batch of metrics, and all labels
except `job`, `instance` and `__name__` from the `target` info metric MUST be
converted to resource attributes attached to all other metrics which are part of
the same resource identified by `job` and `instance`.
Comment thread
krajorama marked this conversation as resolved.
Resolved

By default, label keys and values of the `target` info metric MUST NOT be
altered (such as replacing `_` with `.` characters in keys).

## OTLP Metric points to Prometheus

Expand Down Expand Up @@ -774,6 +851,15 @@
`<service.name>` if namespace is empty, to form the `job` metric label. The
`service.instance.id` attribute, if present, MUST be converted to the
`instance` label; otherwise, `instance` should be added with an empty value.

Comment thread
krajorama marked this conversation as resolved.
Resolved
NOTE(krajo): implicitly: existing `job` data point attribute would be
overwritten, however it is kept if there is no `service.name`.
Comment thread
dashpole marked this conversation as resolved.
Resolved

NOTE(krajo): both prometheusremotewriteexporter and the Prometheus OTLP endpoint

Check warning on line 858 in specification/compatibility/prometheus_and_openmetrics.md

View workflow job for this annotation

GitHub Actions / misspell

Unknown word (prometheusremotewriteexporter)
keep track of existing `target` info metrics by the full label set, not just
`job` and `instance` , so theoretically you can end up with two `target` info
metric that have the same `job` and `instance`, but different attributes.
Comment thread
dashpole marked this conversation as resolved.
Resolved

Other resource attributes SHOULD be converted to a
[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 metric, or MUST be dropped. The `target` metric is an info-typed metric
Expand Down
Loading