Skip to content

Commit 1b7d55b

Browse files
jpbemdneto
andauthored
support prefix for prometheus exporter (open-telemetry#4895)
* support prefix for prometheus exporter * update changelog * fix parameter order * precommit * ci --------- Co-authored-by: Emídio Neto <9735060+emdneto@users.noreply.github.com>
1 parent 0f47f66 commit 1b7d55b

File tree

4 files changed

+43
-8
lines changed

4 files changed

+43
-8
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2222
([#4935](https://github.com/open-telemetry/opentelemetry-python/pull/4935))
2323
- `opentelemetry-sdk`: upgrade vendored OTel configuration schema from v1.0.0-rc.3 to v1.0.0
2424
([#4965](https://github.com/open-telemetry/opentelemetry-python/pull/4965))
25+
- `opentelemetry-exporter-prometheus`: Fix metric name prefix
26+
([#4895](https://github.com/open-telemetry/opentelemetry-python/pull/4895))
2527

2628
## Version 1.40.0/0.61b0 (2026-03-04)
2729

docs/examples/metrics/prometheus-grafana/prometheus-monitor.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
start_http_server(port=8000, addr="localhost")
1212
# Exporter to export metrics to Prometheus
1313
prefix = "MyAppPrefix"
14-
reader = PrometheusMetricReader(prefix)
14+
reader = PrometheusMetricReader(prefix=prefix)
1515
# Meter is responsible for creating and recording metrics
1616
set_meter_provider(MeterProvider(metric_readers=[reader]))
1717
meter = get_meter_provider().get_meter("view-name-change", "0.1.2")

exporter/opentelemetry-exporter-prometheus/src/opentelemetry/exporter/prometheus/__init__.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
3939
# Exporter to export metrics to Prometheus
4040
prefix = "MyAppPrefix"
41-
reader = PrometheusMetricReader(prefix)
41+
reader = PrometheusMetricReader(prefix=prefix)
4242
4343
# Meter is responsible for creating and recording metrics
4444
set_meter_provider(MeterProvider(metric_readers=[reader]))
@@ -131,7 +131,9 @@ def _convert_buckets(
131131
class PrometheusMetricReader(MetricReader):
132132
"""Prometheus metric exporter for OpenTelemetry."""
133133

134-
def __init__(self, disable_target_info: bool = False) -> None:
134+
def __init__(
135+
self, disable_target_info: bool = False, prefix: str = ""
136+
) -> None:
135137
super().__init__(
136138
preferred_temporality={
137139
Counter: AggregationTemporality.CUMULATIVE,
@@ -142,9 +144,12 @@ def __init__(self, disable_target_info: bool = False) -> None:
142144
ObservableGauge: AggregationTemporality.CUMULATIVE,
143145
}
144146
)
145-
self._collector = _CustomCollector(disable_target_info)
147+
self._collector = _CustomCollector(
148+
disable_target_info=disable_target_info, prefix=prefix
149+
)
146150
REGISTRY.register(self._collector)
147151
self._collector._callback = self.collect
152+
self._prefix = prefix
148153

149154
def _receive_metrics(
150155
self,
@@ -167,11 +172,12 @@ class _CustomCollector:
167172
https://github.com/prometheus/client_python#custom-collectors
168173
"""
169174

170-
def __init__(self, disable_target_info: bool = False):
175+
def __init__(self, disable_target_info: bool = False, prefix: str = ""):
171176
self._callback = None
172177
self._metrics_datas: Deque[MetricsData] = deque()
173178
self._disable_target_info = disable_target_info
174179
self._target_info = None
180+
self._prefix = prefix
175181

176182
def add_metrics_data(self, metrics_data: MetricsData) -> None:
177183
"""Add metrics to Prometheus data"""
@@ -227,7 +233,10 @@ def _translate_to_prometheus(
227233
label_values_data_points = []
228234
values = []
229235

230-
metric_name = sanitize_full_name(metric.name)
236+
metric_name = metric.name
237+
if self._prefix:
238+
metric_name = self._prefix + "_" + metric_name
239+
metric_name = sanitize_full_name(metric_name)
231240
metric_description = metric.description or ""
232241
metric_unit = map_unit(metric.unit)
233242

exporter/opentelemetry-exporter-prometheus/tests/test_prometheus_exporter.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def setUp(self):
5555
)
5656

5757
def verify_text_format(
58-
self, metric: Metric, expect_prometheus_text: str
58+
self, metric: Metric, expect_prometheus_text: str, prefix: str = ""
5959
) -> None:
6060
metrics_data = MetricsData(
6161
resource_metrics=[
@@ -73,7 +73,7 @@ def verify_text_format(
7373
]
7474
)
7575

76-
collector = _CustomCollector(disable_target_info=True)
76+
collector = _CustomCollector(disable_target_info=True, prefix=prefix)
7777
collector.add_metrics_data(metrics_data)
7878
result_bytes = generate_latest(collector)
7979
result = result_bytes.decode("utf-8")
@@ -463,6 +463,30 @@ def test_metric_name(self):
463463
"""
464464
),
465465
)
466+
self.verify_text_format(
467+
_generate_sum(name="test_counter_w_prefix", value=1, unit=""),
468+
dedent(
469+
"""\
470+
# HELP foo_test_counter_w_prefix_total foo
471+
# TYPE foo_test_counter_w_prefix_total counter
472+
foo_test_counter_w_prefix_total{a="1",b="true"} 1.0
473+
"""
474+
),
475+
prefix="foo",
476+
)
477+
self.verify_text_format(
478+
_generate_sum(
479+
name="test_counter_w_invalid_chars_prefix", value=1, unit=""
480+
),
481+
dedent(
482+
"""\
483+
# HELP _foo_test_counter_w_invalid_chars_prefix_total foo
484+
# TYPE _foo_test_counter_w_invalid_chars_prefix_total counter
485+
_foo_test_counter_w_invalid_chars_prefix_total{a="1",b="true"} 1.0
486+
"""
487+
),
488+
prefix="#foo",
489+
)
466490
self.verify_text_format(
467491
_generate_sum(name="1leading_digit", value=1, unit=""),
468492
dedent(

0 commit comments

Comments
 (0)