diff --git a/CHANGELOG.md b/CHANGELOG.md index 4537ad3f8b..81298cf3ff 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. - `opentelemetry-sdk`: Add `create_logger_provider`/`configure_logger_provider` to declarative file configuration, enabling LoggerProvider instantiation from config files without reading env vars ([#4990](https://github.com/open-telemetry/opentelemetry-python/pull/4990)) - `opentelemetry-sdk`: Add `service` resource detector support to declarative file configuration via `detection_development.detectors[].service` 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..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, @@ -135,7 +135,10 @@ 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: CollectorRegistry = REGISTRY, ) -> None: super().__init__( preferred_temporality={ @@ -151,7 +154,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 +170,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..59cb1dc465 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, @@ -55,6 +55,18 @@ def setUp(self): side_effect=self._mock_registry_register, ) + def test_custom_registry(self): + 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 = "" ) -> None: