From e48f3443b48a97794b303215910e124338f7645a Mon Sep 17 00:00:00 2001 From: manvi Date: Tue, 7 Apr 2026 21:09:02 +0530 Subject: [PATCH 1/7] Add registry keyword argument to PrometheusMetricReader --- .../src/opentelemetry/exporter/prometheus/__init__.py | 7 ++++--- .../tests/test_prometheus_exporter.py | 8 ++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/exporter/opentelemetry-exporter-prometheus/src/opentelemetry/exporter/prometheus/__init__.py b/exporter/opentelemetry-exporter-prometheus/src/opentelemetry/exporter/prometheus/__init__.py index 608d8f6d30..9f94a385a0 100644 --- a/exporter/opentelemetry-exporter-prometheus/src/opentelemetry/exporter/prometheus/__init__.py +++ b/exporter/opentelemetry-exporter-prometheus/src/opentelemetry/exporter/prometheus/__init__.py @@ -135,7 +135,7 @@ class PrometheusMetricReader(MetricReader): """Prometheus metric exporter for OpenTelemetry.""" def __init__( - self, disable_target_info: bool = False, prefix: str = "" + self, disable_target_info: bool = False, prefix: str = "", registry=REGISTRY ) -> None: super().__init__( preferred_temporality={ @@ -151,7 +151,8 @@ def __init__( self._collector = _CustomCollector( disable_target_info=disable_target_info, prefix=prefix ) - REGISTRY.register(self._collector) + self._registry = registry + self._registry.register(self._collector) self._collector._callback = self.collect self._prefix = prefix @@ -166,7 +167,7 @@ def _receive_metrics( self._collector.add_metrics_data(metrics_data) def shutdown(self, timeout_millis: float = 30_000, **kwargs) -> None: - REGISTRY.unregister(self._collector) + self._registry.unregister(self._collector) class _CustomCollector: diff --git a/exporter/opentelemetry-exporter-prometheus/tests/test_prometheus_exporter.py b/exporter/opentelemetry-exporter-prometheus/tests/test_prometheus_exporter.py index 26770c9e1f..43d3dbc849 100644 --- a/exporter/opentelemetry-exporter-prometheus/tests/test_prometheus_exporter.py +++ b/exporter/opentelemetry-exporter-prometheus/tests/test_prometheus_exporter.py @@ -55,6 +55,14 @@ def setUp(self): side_effect=self._mock_registry_register, ) + def test_custom_registry(self): + from prometheus_client import CollectorRegistry + custom_registry = CollectorRegistry() + reader = PrometheusMetricReader(registry=custom_registry) + # global REGISTRY should NOT be used + self._mock_registry_register.assert_not_called() + reader.shutdown() + def verify_text_format( self, metric: Metric, expect_prometheus_text: str, prefix: str = "" ) -> None: From e46cd6aa0b5e36dc2e6480dc3bd1828f41b88fd5 Mon Sep 17 00:00:00 2001 From: manvi Date: Wed, 8 Apr 2026 19:05:48 +0530 Subject: [PATCH 2/7] Fix lint, formatting, and changelog for PrometheusMetricReader registry kwarg --- CHANGELOG.md | 3 +++ .../src/opentelemetry/exporter/prometheus/__init__.py | 5 ++++- .../tests/test_prometheus_exporter.py | 3 +-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87a6fd6d38..25ac467d43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +- Add `registry` keyword argument to `PrometheusMetricReader` to allow passing a custom Prometheus registry + ([#5055](https://github.com/open-telemetry/opentelemetry-python/pull/5055)) + - Enabled the flake8-tidy-import plugins rules for the ruff linter. These rules throw warnings for relative imports in the modules. ([#5019](https://github.com/open-telemetry/opentelemetry-python/pull/5019)) - `opentelemetry-sdk`: Fix `AttributeError` in `ExplicitBucketHistogramAggregation` when applied to non-Histogram instruments without explicit boundaries diff --git a/exporter/opentelemetry-exporter-prometheus/src/opentelemetry/exporter/prometheus/__init__.py b/exporter/opentelemetry-exporter-prometheus/src/opentelemetry/exporter/prometheus/__init__.py index 9f94a385a0..9d9bc992a1 100644 --- a/exporter/opentelemetry-exporter-prometheus/src/opentelemetry/exporter/prometheus/__init__.py +++ b/exporter/opentelemetry-exporter-prometheus/src/opentelemetry/exporter/prometheus/__init__.py @@ -135,7 +135,10 @@ class PrometheusMetricReader(MetricReader): """Prometheus metric exporter for OpenTelemetry.""" def __init__( - self, disable_target_info: bool = False, prefix: str = "", registry=REGISTRY + self, + disable_target_info: bool = False, + prefix: str = "", + registry=REGISTRY, ) -> None: super().__init__( preferred_temporality={ diff --git a/exporter/opentelemetry-exporter-prometheus/tests/test_prometheus_exporter.py b/exporter/opentelemetry-exporter-prometheus/tests/test_prometheus_exporter.py index 43d3dbc849..3371b9a5a1 100644 --- a/exporter/opentelemetry-exporter-prometheus/tests/test_prometheus_exporter.py +++ b/exporter/opentelemetry-exporter-prometheus/tests/test_prometheus_exporter.py @@ -16,7 +16,7 @@ from unittest import TestCase from unittest.mock import Mock, patch -from prometheus_client import generate_latest +from prometheus_client import CollectorRegistry, generate_latest from prometheus_client.core import ( CounterMetricFamily, GaugeMetricFamily, @@ -56,7 +56,6 @@ def setUp(self): ) def test_custom_registry(self): - from prometheus_client import CollectorRegistry custom_registry = CollectorRegistry() reader = PrometheusMetricReader(registry=custom_registry) # global REGISTRY should NOT be used From 22e6d424760b84dfd0b47819e889f9035451e1d6 Mon Sep 17 00:00:00 2001 From: Manvi <155549774+Manvi2402@users.noreply.github.com> Date: Mon, 13 Apr 2026 20:44:59 +0530 Subject: [PATCH 3/7] Apply suggestions from code review Co-authored-by: Mike Goldsmith --- CHANGELOG.md | 1 - .../src/opentelemetry/exporter/prometheus/__init__.py | 2 +- .../tests/test_prometheus_exporter.py | 2 ++ 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25ac467d43..a319a557fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add `registry` keyword argument to `PrometheusMetricReader` to allow passing a custom Prometheus registry ([#5055](https://github.com/open-telemetry/opentelemetry-python/pull/5055)) - - Enabled the flake8-tidy-import plugins rules for the ruff linter. These rules throw warnings for relative imports in the modules. ([#5019](https://github.com/open-telemetry/opentelemetry-python/pull/5019)) - `opentelemetry-sdk`: Fix `AttributeError` in `ExplicitBucketHistogramAggregation` when applied to non-Histogram instruments without explicit boundaries diff --git a/exporter/opentelemetry-exporter-prometheus/src/opentelemetry/exporter/prometheus/__init__.py b/exporter/opentelemetry-exporter-prometheus/src/opentelemetry/exporter/prometheus/__init__.py index 9d9bc992a1..afe3e7ef9b 100644 --- a/exporter/opentelemetry-exporter-prometheus/src/opentelemetry/exporter/prometheus/__init__.py +++ b/exporter/opentelemetry-exporter-prometheus/src/opentelemetry/exporter/prometheus/__init__.py @@ -138,7 +138,7 @@ def __init__( self, disable_target_info: bool = False, prefix: str = "", - registry=REGISTRY, + registry: CollectorRegistry = REGISTRY, ) -> None: super().__init__( preferred_temporality={ diff --git a/exporter/opentelemetry-exporter-prometheus/tests/test_prometheus_exporter.py b/exporter/opentelemetry-exporter-prometheus/tests/test_prometheus_exporter.py index 3371b9a5a1..dfe48a48c1 100644 --- a/exporter/opentelemetry-exporter-prometheus/tests/test_prometheus_exporter.py +++ b/exporter/opentelemetry-exporter-prometheus/tests/test_prometheus_exporter.py @@ -60,6 +60,8 @@ def test_custom_registry(self): reader = PrometheusMetricReader(registry=custom_registry) # global REGISTRY should NOT be used self._mock_registry_register.assert_not_called() + # check custom_registry was registered + self.assertIn(reader._collector, custom_registry._names_to_collectors.values()) reader.shutdown() def verify_text_format( From 4a014e380afdd789c2b6b16eb034d46978b97460 Mon Sep 17 00:00:00 2001 From: manvi Date: Tue, 14 Apr 2026 07:45:11 +0530 Subject: [PATCH 4/7] Fix CollectorRegistry import and test assertion --- .../exporter/prometheus/__init__.py | 2 +- .../tests/test_prometheus_exporter.py | 17 ++++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/exporter/opentelemetry-exporter-prometheus/src/opentelemetry/exporter/prometheus/__init__.py b/exporter/opentelemetry-exporter-prometheus/src/opentelemetry/exporter/prometheus/__init__.py index afe3e7ef9b..005c0d0c27 100644 --- a/exporter/opentelemetry-exporter-prometheus/src/opentelemetry/exporter/prometheus/__init__.py +++ b/exporter/opentelemetry-exporter-prometheus/src/opentelemetry/exporter/prometheus/__init__.py @@ -69,7 +69,7 @@ from os import environ from typing import Deque, Dict, Iterable, Sequence, Tuple, Union -from prometheus_client import start_http_server +from prometheus_client import CollectorRegistry, start_http_server from prometheus_client.core import ( REGISTRY, CounterMetricFamily, diff --git a/exporter/opentelemetry-exporter-prometheus/tests/test_prometheus_exporter.py b/exporter/opentelemetry-exporter-prometheus/tests/test_prometheus_exporter.py index dfe48a48c1..a8b6bf5a34 100644 --- a/exporter/opentelemetry-exporter-prometheus/tests/test_prometheus_exporter.py +++ b/exporter/opentelemetry-exporter-prometheus/tests/test_prometheus_exporter.py @@ -56,13 +56,16 @@ def setUp(self): ) def test_custom_registry(self): - custom_registry = CollectorRegistry() - reader = PrometheusMetricReader(registry=custom_registry) - # global REGISTRY should NOT be used - self._mock_registry_register.assert_not_called() - # check custom_registry was registered - self.assertIn(reader._collector, custom_registry._names_to_collectors.values()) - reader.shutdown() + with self._registry_register_patch: + custom_registry = CollectorRegistry() + reader = PrometheusMetricReader(registry=custom_registry) + # global REGISTRY should NOT be used + self._mock_registry_register.assert_not_called() + # check custom_registry was registered + self.assertIn(reader._collector, custom_registry._collector_to_names) + reader.shutdown() + + def verify_text_format( self, metric: Metric, expect_prometheus_text: str, prefix: str = "" From 018235ec58165f4ff90803f51ee3d28297813a93 Mon Sep 17 00:00:00 2001 From: manvi Date: Tue, 14 Apr 2026 07:55:50 +0530 Subject: [PATCH 5/7] Fix ruff formatting --- .../tests/test_prometheus_exporter.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/exporter/opentelemetry-exporter-prometheus/tests/test_prometheus_exporter.py b/exporter/opentelemetry-exporter-prometheus/tests/test_prometheus_exporter.py index a8b6bf5a34..59cb1dc465 100644 --- a/exporter/opentelemetry-exporter-prometheus/tests/test_prometheus_exporter.py +++ b/exporter/opentelemetry-exporter-prometheus/tests/test_prometheus_exporter.py @@ -62,11 +62,11 @@ def test_custom_registry(self): # global REGISTRY should NOT be used self._mock_registry_register.assert_not_called() # check custom_registry was registered - self.assertIn(reader._collector, custom_registry._collector_to_names) + self.assertIn( + reader._collector, custom_registry._collector_to_names + ) reader.shutdown() - - def verify_text_format( self, metric: Metric, expect_prometheus_text: str, prefix: str = "" ) -> None: From cbff44102545ae25f165d1fdddb9b52a6ae5fbf7 Mon Sep 17 00:00:00 2001 From: manvi Date: Thu, 16 Apr 2026 16:45:19 +0530 Subject: [PATCH 6/7] fix: convert CRLF to LF in test file --- .../tests/test_prometheus_exporter.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/exporter/opentelemetry-exporter-prometheus/tests/test_prometheus_exporter.py b/exporter/opentelemetry-exporter-prometheus/tests/test_prometheus_exporter.py index 59cb1dc465..bee85335ad 100644 --- a/exporter/opentelemetry-exporter-prometheus/tests/test_prometheus_exporter.py +++ b/exporter/opentelemetry-exporter-prometheus/tests/test_prometheus_exporter.py @@ -47,7 +47,7 @@ ) -class TestPrometheusMetricReader(TestCase): +class TestPrometheusMetricReader(TestCase): # pylint: disable=too-many-public-methods def setUp(self): self._mock_registry_register = Mock() self._registry_register_patch = patch( @@ -63,7 +63,8 @@ def test_custom_registry(self): self._mock_registry_register.assert_not_called() # check custom_registry was registered self.assertIn( - reader._collector, custom_registry._collector_to_names + reader._collector, # pylint: disable=protected-access + custom_registry._collector_to_names, # pylint: disable=protected-access ) reader.shutdown() From bd2c051b6cda673d0e015d1829ea164557a89955 Mon Sep 17 00:00:00 2001 From: manvi Date: Thu, 23 Apr 2026 09:49:03 +0530 Subject: [PATCH 7/7] Fix ruff formatting --- .../tests/test_prometheus_exporter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exporter/opentelemetry-exporter-prometheus/tests/test_prometheus_exporter.py b/exporter/opentelemetry-exporter-prometheus/tests/test_prometheus_exporter.py index bee85335ad..bd5087b6bf 100644 --- a/exporter/opentelemetry-exporter-prometheus/tests/test_prometheus_exporter.py +++ b/exporter/opentelemetry-exporter-prometheus/tests/test_prometheus_exporter.py @@ -63,8 +63,8 @@ def test_custom_registry(self): self._mock_registry_register.assert_not_called() # check custom_registry was registered self.assertIn( - reader._collector, # pylint: disable=protected-access - custom_registry._collector_to_names, # pylint: disable=protected-access + reader._collector, # pylint: disable=protected-access + custom_registry._collector_to_names, # pylint: disable=protected-access ) reader.shutdown()