Skip to content

Commit b68d744

Browse files
committed
Add check for duplicate instrument names
Fixes open-telemetry#2142
1 parent cd4c5e7 commit b68d744

File tree

4 files changed

+106
-9
lines changed

4 files changed

+106
-9
lines changed

opentelemetry-api/src/opentelemetry/_metrics/__init__.py

+11-6
Original file line numberDiff line numberDiff line change
@@ -129,17 +129,21 @@ def version(self):
129129
def schema_url(self):
130130
return self._schema_url
131131

132-
# FIXME check that the instrument name has not been used already
132+
def _check_instrument_name(self, name):
133+
if name in self._instrument_names:
134+
raise Exception(f"Instrument name {name} has been used already")
135+
136+
self._instrument_names.add(name)
133137

134138
@abstractmethod
135139
def create_counter(self, name, unit="", description="") -> Counter:
136-
pass
140+
self._check_instrument_name(name)
137141

138142
@abstractmethod
139143
def create_up_down_counter(
140144
self, name, unit="", description=""
141145
) -> UpDownCounter:
142-
pass
146+
self._check_instrument_name(name)
143147

144148
@abstractmethod
145149
def create_observable_counter(
@@ -223,22 +227,23 @@ def cpu_time_callback(states_to_include: set[str]) -> Iterable[Iterable[Measurem
223227
example, ``By`` for bytes. UCUM units are recommended.
224228
description: A description for this instrument and what it measures.
225229
"""
230+
self._check_instrument_name(name)
226231

227232
@abstractmethod
228233
def create_histogram(self, name, unit="", description="") -> Histogram:
229-
pass
234+
self._check_instrument_name(name)
230235

231236
@abstractmethod
232237
def create_observable_gauge(
233238
self, name, callback, unit="", description=""
234239
) -> ObservableGauge:
235-
pass
240+
self._check_instrument_name(name)
236241

237242
@abstractmethod
238243
def create_observable_up_down_counter(
239244
self, name, callback, unit="", description=""
240245
) -> ObservableUpDownCounter:
241-
pass
246+
self._check_instrument_name(name)
242247

243248

244249
class _ProxyMeter(Meter):

opentelemetry-api/tests/metrics/test_meter.py

+78
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,17 @@
1414
# type: ignore
1515

1616
from unittest import TestCase
17+
from unittest.mock import Mock
1718

1819
from opentelemetry._metrics import Meter
20+
from opentelemetry._metrics.instrument import (
21+
Counter,
22+
Histogram,
23+
ObservableCounter,
24+
ObservableGauge,
25+
ObservableUpDownCounter,
26+
UpDownCounter,
27+
)
1928

2029
# FIXME Test that the meter methods can be called concurrently safely.
2130

@@ -53,6 +62,75 @@ def create_observable_up_down_counter(
5362

5463

5564
class TestMeter(TestCase):
65+
def test_repeated_instrument_names(self):
66+
class TestMeter(Meter):
67+
def create_counter(self, name, unit="", description="") -> Counter:
68+
super().create_counter(
69+
name, unit=unit, description=description
70+
)
71+
72+
def create_up_down_counter(
73+
self, name, unit="", description=""
74+
) -> UpDownCounter:
75+
super().create_up_down_counter(
76+
name, unit=unit, description=description
77+
)
78+
79+
def create_observable_counter(
80+
self, name, callback, unit="", description=""
81+
) -> ObservableCounter:
82+
super().create_observable_up_down_counter(
83+
name, callback, unit=unit, description=description
84+
)
85+
86+
def create_histogram(
87+
self, name, unit="", description=""
88+
) -> Histogram:
89+
super().create_histogram(
90+
name, unit=unit, description=description
91+
)
92+
93+
def create_observable_gauge(
94+
self, name, callback, unit="", description=""
95+
) -> ObservableGauge:
96+
super().create_observable_gauge(
97+
name, callback, unit=unit, description=description
98+
)
99+
100+
def create_observable_up_down_counter(
101+
self, name, callback, unit="", description=""
102+
) -> ObservableUpDownCounter:
103+
super().create_observable_up_down_counter(
104+
name, callback, unit=unit, description=description
105+
)
106+
107+
try:
108+
test_meter = TestMeter("name")
109+
110+
test_meter.create_counter("counter")
111+
test_meter.create_up_down_counter("up_down_counter")
112+
test_meter.create_observable_counter("observable_counter", Mock())
113+
test_meter.create_histogram("histogram")
114+
test_meter.create_observable_gauge("observable_gauge", Mock())
115+
test_meter.create_observable_up_down_counter(
116+
"observable_up_down_counter", Mock()
117+
)
118+
except Exception as error:
119+
self.fail(f"Unexpected exception raised {error}")
120+
121+
for instrument_name in [
122+
"counter",
123+
"up_down_counter",
124+
"observable_counter",
125+
"histogram",
126+
"observable_gauge",
127+
"observable_up_down_counter",
128+
]:
129+
with self.assertRaises(Exception):
130+
getattr(test_meter, f"create_{instrument_name}")(
131+
instrument_name
132+
)
133+
56134
def test_create_counter(self):
57135
"""
58136
Test that the meter provides a function to create a new Counter

opentelemetry-sdk/src/opentelemetry/sdk/_metrics/__init__.py

+14
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ def __init__(
6464
self._measurement_consumer = measurement_consumer
6565

6666
def create_counter(self, name, unit=None, description=None) -> APICounter:
67+
super().create_counter(name, unit=unit, description=description)
6768
return Counter(
6869
name,
6970
self._instrumentation_info,
@@ -75,6 +76,9 @@ def create_counter(self, name, unit=None, description=None) -> APICounter:
7576
def create_up_down_counter(
7677
self, name, unit=None, description=None
7778
) -> APIUpDownCounter:
79+
super().create_up_down_counter(
80+
name, unit=unit, description=description
81+
)
7882
return UpDownCounter(
7983
name,
8084
self._instrumentation_info,
@@ -86,6 +90,9 @@ def create_up_down_counter(
8690
def create_observable_counter(
8791
self, name, callback, unit=None, description=None
8892
) -> APIObservableCounter:
93+
super().create_observable_counter(
94+
name, callback, unit=unit, description=description
95+
)
8996

9097
instrument = ObservableCounter(
9198
name,
@@ -103,6 +110,7 @@ def create_observable_counter(
103110
def create_histogram(
104111
self, name, unit=None, description=None
105112
) -> APIHistogram:
113+
super().create_histogram(name, unit=unit, description=description)
106114
return Histogram(
107115
name,
108116
self._instrumentation_info,
@@ -114,6 +122,9 @@ def create_histogram(
114122
def create_observable_gauge(
115123
self, name, callback, unit=None, description=None
116124
) -> APIObservableGauge:
125+
super().create_observable_gauge(
126+
name, callback, unit=unit, description=description
127+
)
117128

118129
instrument = ObservableGauge(
119130
name,
@@ -131,6 +142,9 @@ def create_observable_gauge(
131142
def create_observable_up_down_counter(
132143
self, name, callback, unit=None, description=None
133144
) -> APIObservableUpDownCounter:
145+
super().create_observable_up_down_counter(
146+
name, callback, unit=unit, description=description
147+
)
134148

135149
instrument = ObservableUpDownCounter(
136150
name,

opentelemetry-sdk/tests/metrics/test_metrics.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -217,17 +217,17 @@ def test_register_asynchronous_instrument(
217217

218218
meter_provider._measurement_consumer.register_asynchronous_instrument.assert_called_with(
219219
meter_provider.get_meter("name").create_observable_counter(
220-
"name", Mock()
220+
"name0", Mock()
221221
)
222222
)
223223
meter_provider._measurement_consumer.register_asynchronous_instrument.assert_called_with(
224224
meter_provider.get_meter("name").create_observable_up_down_counter(
225-
"name", Mock()
225+
"name1", Mock()
226226
)
227227
)
228228
meter_provider._measurement_consumer.register_asynchronous_instrument.assert_called_with(
229229
meter_provider.get_meter("name").create_observable_gauge(
230-
"name", Mock()
230+
"name2", Mock()
231231
)
232232
)
233233

0 commit comments

Comments
 (0)