Skip to content

Commit 1cf32f0

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

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
@@ -63,6 +63,7 @@ def __init__(
6363
self._measurement_consumer = measurement_consumer
6464

6565
def create_counter(self, name, unit=None, description=None) -> APICounter:
66+
super().create_counter(name, unit=unit, description=description)
6667
return Counter(
6768
name,
6869
self._instrumentation_info,
@@ -74,6 +75,9 @@ def create_counter(self, name, unit=None, description=None) -> APICounter:
7475
def create_up_down_counter(
7576
self, name, unit=None, description=None
7677
) -> APIUpDownCounter:
78+
super().create_up_down_counter(
79+
name, unit=unit, description=description
80+
)
7781
return UpDownCounter(
7882
name,
7983
self._instrumentation_info,
@@ -85,6 +89,9 @@ def create_up_down_counter(
8589
def create_observable_counter(
8690
self, name, callback, unit=None, description=None
8791
) -> APIObservableCounter:
92+
super().create_observable_counter(
93+
name, callback, unit=unit, description=description
94+
)
8895

8996
instrument = ObservableCounter(
9097
name,
@@ -102,6 +109,7 @@ def create_observable_counter(
102109
def create_histogram(
103110
self, name, unit=None, description=None
104111
) -> APIHistogram:
112+
super().create_histogram(name, unit=unit, description=description)
105113
return Histogram(
106114
name,
107115
self._instrumentation_info,
@@ -113,6 +121,9 @@ def create_histogram(
113121
def create_observable_gauge(
114122
self, name, callback, unit=None, description=None
115123
) -> APIObservableGauge:
124+
super().create_observable_gauge(
125+
name, callback, unit=unit, description=description
126+
)
116127

117128
instrument = ObservableGauge(
118129
name,
@@ -130,6 +141,9 @@ def create_observable_gauge(
130141
def create_observable_up_down_counter(
131142
self, name, callback, unit=None, description=None
132143
) -> APIObservableUpDownCounter:
144+
super().create_observable_up_down_counter(
145+
name, callback, unit=unit, description=description
146+
)
133147

134148
instrument = ObservableUpDownCounter(
135149
name,

opentelemetry-sdk/tests/metrics/test_metrics.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -145,17 +145,17 @@ def test_register_asynchronous_instrument(
145145

146146
meter_provider._measurement_consumer.register_asynchronous_instrument.assert_called_with(
147147
meter_provider.get_meter("name").create_observable_counter(
148-
"name", Mock()
148+
"name0", Mock()
149149
)
150150
)
151151
meter_provider._measurement_consumer.register_asynchronous_instrument.assert_called_with(
152152
meter_provider.get_meter("name").create_observable_up_down_counter(
153-
"name", Mock()
153+
"name1", Mock()
154154
)
155155
)
156156
meter_provider._measurement_consumer.register_asynchronous_instrument.assert_called_with(
157157
meter_provider.get_meter("name").create_observable_gauge(
158-
"name", Mock()
158+
"name2", Mock()
159159
)
160160
)
161161

0 commit comments

Comments
 (0)