diff --git a/dependencyManagement/build.gradle.kts b/dependencyManagement/build.gradle.kts index debe9f7f40f..3a78d666da1 100644 --- a/dependencyManagement/build.gradle.kts +++ b/dependencyManagement/build.gradle.kts @@ -15,7 +15,7 @@ val jmhVersion = "1.37" val mockitoVersion = "4.11.0" val slf4jVersion = "2.0.17" val opencensusVersion = "0.31.1" -val prometheusServerVersion = "1.3.10" +val prometheusServerVersion = "1.4.3" val armeriaVersion = "1.36.0" val junitVersion = "5.14.2" val okhttpVersion = "5.3.2" diff --git a/exporters/prometheus/src/main/java/io/opentelemetry/exporter/prometheus/Otel2PrometheusConverter.java b/exporters/prometheus/src/main/java/io/opentelemetry/exporter/prometheus/Otel2PrometheusConverter.java index f05abbce947..5f443dba0ab 100644 --- a/exporters/prometheus/src/main/java/io/opentelemetry/exporter/prometheus/Otel2PrometheusConverter.java +++ b/exporters/prometheus/src/main/java/io/opentelemetry/exporter/prometheus/Otel2PrometheusConverter.java @@ -5,6 +5,7 @@ package io.opentelemetry.exporter.prometheus; +import static io.prometheus.metrics.model.snapshots.PrometheusNaming.prometheusName; import static io.prometheus.metrics.model.snapshots.PrometheusNaming.sanitizeLabelName; import static io.prometheus.metrics.model.snapshots.PrometheusNaming.sanitizeMetricName; import static java.util.Objects.requireNonNull; @@ -474,7 +475,7 @@ private Labels convertAttributes( attributes.forEach( (key, value) -> labelNameToValue.put( - sanitizeLabelName(key.getKey()), toLabelValue(key.getType(), value))); + convertLabelName(key.getKey()), toLabelValue(key.getType(), value))); for (int i = 0; i < additionalAttributes.length; i += 2) { labelNameToValue.putIfAbsent( @@ -504,7 +505,7 @@ private Labels convertAttributes( Object attributeValue = resourceAttributes.get(attributeKey); if (attributeValue != null) { labelNameToValue.putIfAbsent( - sanitizeLabelName(attributeKey.getKey()), attributeValue.toString()); + convertLabelName(attributeKey.getKey()), attributeValue.toString()); } } } @@ -544,14 +545,24 @@ private List> filterAllowedResourceAttributeKeys(@Nullable Resou return allowedAttributeKeys; } + /** + * Convert an attribute key to a legacy Prometheus label name. {@code prometheusName} converts + * non-standard characters (dots, dashes, etc.) to underscores, and {@code sanitizeLabelName} + * strips invalid leading prefixes. + */ + private static String convertLabelName(String key) { + return sanitizeLabelName(prometheusName(key)); + } + private static MetricMetadata convertMetadata(MetricData metricData) { - String name = sanitizeMetricName(metricData.getName()); + String name = sanitizeMetricName(prometheusName(metricData.getName())); String help = metricData.getDescription(); Unit unit = PrometheusUnitsHelper.convertUnit(metricData.getUnit()); if (unit != null && !name.endsWith(unit.toString())) { name = name + "_" + unit; } - // Repeated __ are not allowed according to spec, although this is allowed in prometheus + // Repeated __ are discouraged according to spec, although this is allowed in prometheus, see + // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/compatibility/prometheus_and_openmetrics.md#metric-metadata-1 while (name.contains("__")) { name = name.replace("__", "_"); } diff --git a/exporters/prometheus/src/test/java/io/opentelemetry/exporter/prometheus/PrometheusHttpServerTest.java b/exporters/prometheus/src/test/java/io/opentelemetry/exporter/prometheus/PrometheusHttpServerTest.java index 16c39efc31b..c4cda1d6fad 100644 --- a/exporters/prometheus/src/test/java/io/opentelemetry/exporter/prometheus/PrometheusHttpServerTest.java +++ b/exporters/prometheus/src/test/java/io/opentelemetry/exporter/prometheus/PrometheusHttpServerTest.java @@ -46,7 +46,7 @@ import io.opentelemetry.sdk.resources.Resource; import io.prometheus.metrics.exporter.httpserver.HTTPServer; import io.prometheus.metrics.exporter.httpserver.MetricsHandler; -import io.prometheus.metrics.expositionformats.generated.com_google_protobuf_4_31_1.Metrics; +import io.prometheus.metrics.expositionformats.generated.com_google_protobuf_4_33_0.Metrics; import io.prometheus.metrics.model.registry.PrometheusRegistry; import java.io.ByteArrayInputStream; import java.io.IOException;