From fb1063ce89543b87a0d35be2e97f3f0a1a83dc8b Mon Sep 17 00:00:00 2001 From: Leighton Chen Date: Fri, 14 Jan 2022 16:40:44 -0800 Subject: [PATCH] Handle duplicate meters (#2373) --- .../opentelemetry/sdk/_metrics/__init__.py | 14 +++++++---- .../tests/metrics/test_metrics.py | 24 +++++++++++++++++++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/__init__.py index 6693bc5e258..56b0ad704f5 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/__init__.py @@ -154,6 +154,7 @@ def __init__( shutdown_on_exit: bool = True, ): self._lock = Lock() + self._meter_lock = Lock() self._atexit_handler = None self._measurement_consumer = SynchronousMeasurementConsumer() @@ -161,6 +162,7 @@ def __init__( if shutdown_on_exit: self._atexit_handler = register(self.shutdown) + self._meters = {} self._metric_readers = metric_readers for metric_reader in self._metric_readers: @@ -221,7 +223,11 @@ def get_meter( ) return _DefaultMeter(name, version=version, schema_url=schema_url) - return Meter( - InstrumentationInfo(name, version, schema_url), - self._measurement_consumer, - ) + info = InstrumentationInfo(name, version, schema_url) + with self._meter_lock: + if not self._meters.get(info): + self._meters[info] = Meter( + info, + self._measurement_consumer, + ) + return self._meters[info] diff --git a/opentelemetry-sdk/tests/metrics/test_metrics.py b/opentelemetry-sdk/tests/metrics/test_metrics.py index d9a6dc9cafd..20714167023 100644 --- a/opentelemetry-sdk/tests/metrics/test_metrics.py +++ b/opentelemetry-sdk/tests/metrics/test_metrics.py @@ -64,6 +64,30 @@ def test_get_meter(self): self.assertEqual(meter._instrumentation_info.version, "version") self.assertEqual(meter._instrumentation_info.schema_url, "schema_url") + def test_get_meter_duplicate(self): + """ + Subsequent calls to `MeterProvider.get_meter` with the same arguments + should return the same `Meter` instance. + """ + mp = MeterProvider() + meter1 = mp.get_meter( + "name", + version="version", + schema_url="schema_url", + ) + meter2 = mp.get_meter( + "name", + version="version", + schema_url="schema_url", + ) + meter3 = mp.get_meter( + "name2", + version="version", + schema_url="schema_url", + ) + self.assertIs(meter1, meter2) + self.assertIsNot(meter1, meter3) + def test_shutdown_subsequent_calls(self): """ No subsequent attempts to get a `Meter` are allowed after calling