We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Allow use of "/" in Metrics Instrument Names, and with a 255 char limit
As per the recent specs change :
 
* Increase max instrument name length from 63 to 255: https://github.com/open-telemetry/opentelemetry-specification/pull/3648
* Instrument names can have "/" character: https://github.com/open-telemetry/opentelemetry-specification/pull/3684

Then update spec compliance matrix https://github.com/open-telemetry/opentelemetry-specification/blob/main/spec-compliance-matrix.md

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `opentelemetry-api/src/opentelemetry/metrics/_internal/instrument.py`
Content:
```
1 # Copyright The OpenTelemetry Authors
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #     http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 
15 # pylint: disable=too-many-ancestors
16 
17 
18 from abc import ABC, abstractmethod
19 from dataclasses import dataclass
20 from logging import getLogger
21 from re import compile as re_compile
22 from typing import (
23     Callable,
24     Dict,
25     Generator,
26     Generic,
27     Iterable,
28     Optional,
29     Sequence,
30     TypeVar,
31     Union,
32 )
33 
34 # pylint: disable=unused-import; needed for typing and sphinx
35 from opentelemetry import metrics
36 from opentelemetry.metrics._internal.observation import Observation
37 from opentelemetry.util.types import Attributes
38 
39 _logger = getLogger(__name__)
40 
41 _name_regex = re_compile(r"[a-zA-Z][-_.a-zA-Z0-9]{0,62}")
42 _unit_regex = re_compile(r"[\x00-\x7F]{0,63}")
43 
44 
45 @dataclass(frozen=True)
46 class CallbackOptions:
47     """Options for the callback
48 
49     Args:
50         timeout_millis: Timeout for the callback's execution. If the callback does asynchronous
51             work (e.g. HTTP requests), it should respect this timeout.
52     """
53 
54     timeout_millis: float = 10_000
55 
56 
57 InstrumentT = TypeVar("InstrumentT", bound="Instrument")
58 CallbackT = Union[
59     Callable[[CallbackOptions], Iterable[Observation]],
60     Generator[Iterable[Observation], CallbackOptions, None],
61 ]
62 
63 
64 class Instrument(ABC):
65     """Abstract class that serves as base for all instruments."""
66 
67     @abstractmethod
68     def __init__(
69         self,
70         name: str,
71         unit: str = "",
72         description: str = "",
73     ) -> None:
74         pass
75 
76     @staticmethod
77     def _check_name_unit_description(
78         name: str, unit: str, description: str
79     ) -> Dict[str, Optional[str]]:
80         """
81         Checks the following instrument name, unit and description for
82         compliance with the spec.
83 
84         Returns a dict with keys "name", "unit" and "description", the
85         corresponding values will be the checked strings or `None` if the value
86         is invalid. If valid, the checked strings should be used instead of the
87         original values.
88         """
89 
90         result: Dict[str, Optional[str]] = {}
91 
92         if _name_regex.fullmatch(name) is not None:
93             result["name"] = name
94         else:
95             result["name"] = None
96 
97         if unit is None:
98             unit = ""
99         if _unit_regex.fullmatch(unit) is not None:
100             result["unit"] = unit
101         else:
102             result["unit"] = None
103 
104         if description is None:
105             result["description"] = ""
106         else:
107             result["description"] = description
108 
109         return result
110 
111 
112 class _ProxyInstrument(ABC, Generic[InstrumentT]):
113     def __init__(
114         self,
115         name: str,
116         unit: str = "",
117         description: str = "",
118     ) -> None:
119         self._name = name
120         self._unit = unit
121         self._description = description
122         self._real_instrument: Optional[InstrumentT] = None
123 
124     def on_meter_set(self, meter: "metrics.Meter") -> None:
125         """Called when a real meter is set on the creating _ProxyMeter"""
126 
127         # We don't need any locking on proxy instruments because it's OK if some
128         # measurements get dropped while a real backing instrument is being
129         # created.
130         self._real_instrument = self._create_real_instrument(meter)
131 
132     @abstractmethod
133     def _create_real_instrument(self, meter: "metrics.Meter") -> InstrumentT:
134         """Create an instance of the real instrument. Implement this."""
135 
136 
137 class _ProxyAsynchronousInstrument(_ProxyInstrument[InstrumentT]):
138     def __init__(
139         self,
140         name: str,
141         callbacks: Optional[Sequence[CallbackT]] = None,
142         unit: str = "",
143         description: str = "",
144     ) -> None:
145         super().__init__(name, unit, description)
146         self._callbacks = callbacks
147 
148 
149 class Synchronous(Instrument):
150     """Base class for all synchronous instruments"""
151 
152 
153 class Asynchronous(Instrument):
154     """Base class for all asynchronous instruments"""
155 
156     @abstractmethod
157     def __init__(
158         self,
159         name: str,
160         callbacks: Optional[Sequence[CallbackT]] = None,
161         unit: str = "",
162         description: str = "",
163     ) -> None:
164         super().__init__(name, unit=unit, description=description)
165 
166 
167 class Counter(Synchronous):
168     """A Counter is a synchronous `Instrument` which supports non-negative increments."""
169 
170     @abstractmethod
171     def add(
172         self,
173         amount: Union[int, float],
174         attributes: Optional[Attributes] = None,
175     ) -> None:
176         pass
177 
178 
179 class NoOpCounter(Counter):
180     """No-op implementation of `Counter`."""
181 
182     def __init__(
183         self,
184         name: str,
185         unit: str = "",
186         description: str = "",
187     ) -> None:
188         super().__init__(name, unit=unit, description=description)
189 
190     def add(
191         self,
192         amount: Union[int, float],
193         attributes: Optional[Attributes] = None,
194     ) -> None:
195         return super().add(amount, attributes=attributes)
196 
197 
198 class _ProxyCounter(_ProxyInstrument[Counter], Counter):
199     def add(
200         self,
201         amount: Union[int, float],
202         attributes: Optional[Attributes] = None,
203     ) -> None:
204         if self._real_instrument:
205             self._real_instrument.add(amount, attributes)
206 
207     def _create_real_instrument(self, meter: "metrics.Meter") -> Counter:
208         return meter.create_counter(self._name, self._unit, self._description)
209 
210 
211 class UpDownCounter(Synchronous):
212     """An UpDownCounter is a synchronous `Instrument` which supports increments and decrements."""
213 
214     @abstractmethod
215     def add(
216         self,
217         amount: Union[int, float],
218         attributes: Optional[Attributes] = None,
219     ) -> None:
220         pass
221 
222 
223 class NoOpUpDownCounter(UpDownCounter):
224     """No-op implementation of `UpDownCounter`."""
225 
226     def __init__(
227         self,
228         name: str,
229         unit: str = "",
230         description: str = "",
231     ) -> None:
232         super().__init__(name, unit=unit, description=description)
233 
234     def add(
235         self,
236         amount: Union[int, float],
237         attributes: Optional[Attributes] = None,
238     ) -> None:
239         return super().add(amount, attributes=attributes)
240 
241 
242 class _ProxyUpDownCounter(_ProxyInstrument[UpDownCounter], UpDownCounter):
243     def add(
244         self,
245         amount: Union[int, float],
246         attributes: Optional[Attributes] = None,
247     ) -> None:
248         if self._real_instrument:
249             self._real_instrument.add(amount, attributes)
250 
251     def _create_real_instrument(self, meter: "metrics.Meter") -> UpDownCounter:
252         return meter.create_up_down_counter(
253             self._name, self._unit, self._description
254         )
255 
256 
257 class ObservableCounter(Asynchronous):
258     """An ObservableCounter is an asynchronous `Instrument` which reports monotonically
259     increasing value(s) when the instrument is being observed.
260     """
261 
262 
263 class NoOpObservableCounter(ObservableCounter):
264     """No-op implementation of `ObservableCounter`."""
265 
266     def __init__(
267         self,
268         name: str,
269         callbacks: Optional[Sequence[CallbackT]] = None,
270         unit: str = "",
271         description: str = "",
272     ) -> None:
273         super().__init__(name, callbacks, unit=unit, description=description)
274 
275 
276 class _ProxyObservableCounter(
277     _ProxyAsynchronousInstrument[ObservableCounter], ObservableCounter
278 ):
279     def _create_real_instrument(
280         self, meter: "metrics.Meter"
281     ) -> ObservableCounter:
282         return meter.create_observable_counter(
283             self._name, self._callbacks, self._unit, self._description
284         )
285 
286 
287 class ObservableUpDownCounter(Asynchronous):
288     """An ObservableUpDownCounter is an asynchronous `Instrument` which reports additive value(s) (e.g.
289     the process heap size - it makes sense to report the heap size from multiple processes and sum them
290     up, so we get the total heap usage) when the instrument is being observed.
291     """
292 
293 
294 class NoOpObservableUpDownCounter(ObservableUpDownCounter):
295     """No-op implementation of `ObservableUpDownCounter`."""
296 
297     def __init__(
298         self,
299         name: str,
300         callbacks: Optional[Sequence[CallbackT]] = None,
301         unit: str = "",
302         description: str = "",
303     ) -> None:
304         super().__init__(name, callbacks, unit=unit, description=description)
305 
306 
307 class _ProxyObservableUpDownCounter(
308     _ProxyAsynchronousInstrument[ObservableUpDownCounter],
309     ObservableUpDownCounter,
310 ):
311     def _create_real_instrument(
312         self, meter: "metrics.Meter"
313     ) -> ObservableUpDownCounter:
314         return meter.create_observable_up_down_counter(
315             self._name, self._callbacks, self._unit, self._description
316         )
317 
318 
319 class Histogram(Synchronous):
320     """Histogram is a synchronous `Instrument` which can be used to report arbitrary values
321     that are likely to be statistically meaningful. It is intended for statistics such as
322     histograms, summaries, and percentile.
323     """
324 
325     @abstractmethod
326     def record(
327         self,
328         amount: Union[int, float],
329         attributes: Optional[Attributes] = None,
330     ) -> None:
331         pass
332 
333 
334 class NoOpHistogram(Histogram):
335     """No-op implementation of `Histogram`."""
336 
337     def __init__(
338         self,
339         name: str,
340         unit: str = "",
341         description: str = "",
342     ) -> None:
343         super().__init__(name, unit=unit, description=description)
344 
345     def record(
346         self,
347         amount: Union[int, float],
348         attributes: Optional[Attributes] = None,
349     ) -> None:
350         return super().record(amount, attributes=attributes)
351 
352 
353 class _ProxyHistogram(_ProxyInstrument[Histogram], Histogram):
354     def record(
355         self,
356         amount: Union[int, float],
357         attributes: Optional[Attributes] = None,
358     ) -> None:
359         if self._real_instrument:
360             self._real_instrument.record(amount, attributes)
361 
362     def _create_real_instrument(self, meter: "metrics.Meter") -> Histogram:
363         return meter.create_histogram(
364             self._name, self._unit, self._description
365         )
366 
367 
368 class ObservableGauge(Asynchronous):
369     """Asynchronous Gauge is an asynchronous `Instrument` which reports non-additive value(s) (e.g.
370     the room temperature - it makes no sense to report the temperature value from multiple rooms
371     and sum them up) when the instrument is being observed.
372     """
373 
374 
375 class NoOpObservableGauge(ObservableGauge):
376     """No-op implementation of `ObservableGauge`."""
377 
378     def __init__(
379         self,
380         name: str,
381         callbacks: Optional[Sequence[CallbackT]] = None,
382         unit: str = "",
383         description: str = "",
384     ) -> None:
385         super().__init__(name, callbacks, unit=unit, description=description)
386 
387 
388 class _ProxyObservableGauge(
389     _ProxyAsynchronousInstrument[ObservableGauge],
390     ObservableGauge,
391 ):
392     def _create_real_instrument(
393         self, meter: "metrics.Meter"
394     ) -> ObservableGauge:
395         return meter.create_observable_gauge(
396             self._name, self._callbacks, self._unit, self._description
397         )
398
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/opentelemetry-api/src/opentelemetry/metrics/_internal/instrument.py b/opentelemetry-api/src/opentelemetry/metrics/_internal/instrument.py
--- a/opentelemetry-api/src/opentelemetry/metrics/_internal/instrument.py
+++ b/opentelemetry-api/src/opentelemetry/metrics/_internal/instrument.py
@@ -38,7 +38,7 @@
 
 _logger = getLogger(__name__)
 
-_name_regex = re_compile(r"[a-zA-Z][-_.a-zA-Z0-9]{0,62}")
+_name_regex = re_compile(r"[a-zA-Z][-_./a-zA-Z0-9]{0,254}")
 _unit_regex = re_compile(r"[\x00-\x7F]{0,63}")

{"golden_diff": "diff --git a/opentelemetry-api/src/opentelemetry/metrics/_internal/instrument.py b/opentelemetry-api/src/opentelemetry/metrics/_internal/instrument.py\n--- a/opentelemetry-api/src/opentelemetry/metrics/_internal/instrument.py\n+++ b/opentelemetry-api/src/opentelemetry/metrics/_internal/instrument.py\n@@ -38,7 +38,7 @@\n \n _logger = getLogger(__name__)\n \n-_name_regex = re_compile(r\"[a-zA-Z][-_.a-zA-Z0-9]{0,62}\")\n+_name_regex = re_compile(r\"[a-zA-Z][-_./a-zA-Z0-9]{0,254}\")\n _unit_regex = re_compile(r\"[\\x00-\\x7F]{0,63}\")\n", "issue": "Allow use of \"/\" in Metrics Instrument Names, and with a 255 char limit\nAs per the recent specs change :\r\n \r\n* Increase max instrument name length from 63 to 255: https://github.com/open-telemetry/opentelemetry-specification/pull/3648\r\n* Instrument names can have \"/\" character: https://github.com/open-telemetry/opentelemetry-specification/pull/3684\r\n\r\nThen update spec compliance matrix https://github.com/open-telemetry/opentelemetry-specification/blob/main/spec-compliance-matrix.md\n", "before_files": [{"content": "# Copyright The OpenTelemetry Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# pylint: disable=too-many-ancestors\n\n\nfrom abc import ABC, abstractmethod\nfrom dataclasses import dataclass\nfrom logging import getLogger\nfrom re import compile as re_compile\nfrom typing import (\n    Callable,\n    Dict,\n    Generator,\n    Generic,\n    Iterable,\n    Optional,\n    Sequence,\n    TypeVar,\n    Union,\n)\n\n# pylint: disable=unused-import; needed for typing and sphinx\nfrom opentelemetry import metrics\nfrom opentelemetry.metrics._internal.observation import Observation\nfrom opentelemetry.util.types import Attributes\n\n_logger = getLogger(__name__)\n\n_name_regex = re_compile(r\"[a-zA-Z][-_.a-zA-Z0-9]{0,62}\")\n_unit_regex = re_compile(r\"[\\x00-\\x7F]{0,63}\")\n\n\n@dataclass(frozen=True)\nclass CallbackOptions:\n    \"\"\"Options for the callback\n\n    Args:\n        timeout_millis: Timeout for the callback's execution. If the callback does asynchronous\n            work (e.g. HTTP requests), it should respect this timeout.\n    \"\"\"\n\n    timeout_millis: float = 10_000\n\n\nInstrumentT = TypeVar(\"InstrumentT\", bound=\"Instrument\")\nCallbackT = Union[\n    Callable[[CallbackOptions], Iterable[Observation]],\n    Generator[Iterable[Observation], CallbackOptions, None],\n]\n\n\nclass Instrument(ABC):\n    \"\"\"Abstract class that serves as base for all instruments.\"\"\"\n\n    @abstractmethod\n    def __init__(\n        self,\n        name: str,\n        unit: str = \"\",\n        description: str = \"\",\n    ) -> None:\n        pass\n\n    @staticmethod\n    def _check_name_unit_description(\n        name: str, unit: str, description: str\n    ) -> Dict[str, Optional[str]]:\n        \"\"\"\n        Checks the following instrument name, unit and description for\n        compliance with the spec.\n\n        Returns a dict with keys \"name\", \"unit\" and \"description\", the\n        corresponding values will be the checked strings or `None` if the value\n        is invalid. If valid, the checked strings should be used instead of the\n        original values.\n        \"\"\"\n\n        result: Dict[str, Optional[str]] = {}\n\n        if _name_regex.fullmatch(name) is not None:\n            result[\"name\"] = name\n        else:\n            result[\"name\"] = None\n\n        if unit is None:\n            unit = \"\"\n        if _unit_regex.fullmatch(unit) is not None:\n            result[\"unit\"] = unit\n        else:\n            result[\"unit\"] = None\n\n        if description is None:\n            result[\"description\"] = \"\"\n        else:\n            result[\"description\"] = description\n\n        return result\n\n\nclass _ProxyInstrument(ABC, Generic[InstrumentT]):\n    def __init__(\n        self,\n        name: str,\n        unit: str = \"\",\n        description: str = \"\",\n    ) -> None:\n        self._name = name\n        self._unit = unit\n        self._description = description\n        self._real_instrument: Optional[InstrumentT] = None\n\n    def on_meter_set(self, meter: \"metrics.Meter\") -> None:\n        \"\"\"Called when a real meter is set on the creating _ProxyMeter\"\"\"\n\n        # We don't need any locking on proxy instruments because it's OK if some\n        # measurements get dropped while a real backing instrument is being\n        # created.\n        self._real_instrument = self._create_real_instrument(meter)\n\n    @abstractmethod\n    def _create_real_instrument(self, meter: \"metrics.Meter\") -> InstrumentT:\n        \"\"\"Create an instance of the real instrument. Implement this.\"\"\"\n\n\nclass _ProxyAsynchronousInstrument(_ProxyInstrument[InstrumentT]):\n    def __init__(\n        self,\n        name: str,\n        callbacks: Optional[Sequence[CallbackT]] = None,\n        unit: str = \"\",\n        description: str = \"\",\n    ) -> None:\n        super().__init__(name, unit, description)\n        self._callbacks = callbacks\n\n\nclass Synchronous(Instrument):\n    \"\"\"Base class for all synchronous instruments\"\"\"\n\n\nclass Asynchronous(Instrument):\n    \"\"\"Base class for all asynchronous instruments\"\"\"\n\n    @abstractmethod\n    def __init__(\n        self,\n        name: str,\n        callbacks: Optional[Sequence[CallbackT]] = None,\n        unit: str = \"\",\n        description: str = \"\",\n    ) -> None:\n        super().__init__(name, unit=unit, description=description)\n\n\nclass Counter(Synchronous):\n    \"\"\"A Counter is a synchronous `Instrument` which supports non-negative increments.\"\"\"\n\n    @abstractmethod\n    def add(\n        self,\n        amount: Union[int, float],\n        attributes: Optional[Attributes] = None,\n    ) -> None:\n        pass\n\n\nclass NoOpCounter(Counter):\n    \"\"\"No-op implementation of `Counter`.\"\"\"\n\n    def __init__(\n        self,\n        name: str,\n        unit: str = \"\",\n        description: str = \"\",\n    ) -> None:\n        super().__init__(name, unit=unit, description=description)\n\n    def add(\n        self,\n        amount: Union[int, float],\n        attributes: Optional[Attributes] = None,\n    ) -> None:\n        return super().add(amount, attributes=attributes)\n\n\nclass _ProxyCounter(_ProxyInstrument[Counter], Counter):\n    def add(\n        self,\n        amount: Union[int, float],\n        attributes: Optional[Attributes] = None,\n    ) -> None:\n        if self._real_instrument:\n            self._real_instrument.add(amount, attributes)\n\n    def _create_real_instrument(self, meter: \"metrics.Meter\") -> Counter:\n        return meter.create_counter(self._name, self._unit, self._description)\n\n\nclass UpDownCounter(Synchronous):\n    \"\"\"An UpDownCounter is a synchronous `Instrument` which supports increments and decrements.\"\"\"\n\n    @abstractmethod\n    def add(\n        self,\n        amount: Union[int, float],\n        attributes: Optional[Attributes] = None,\n    ) -> None:\n        pass\n\n\nclass NoOpUpDownCounter(UpDownCounter):\n    \"\"\"No-op implementation of `UpDownCounter`.\"\"\"\n\n    def __init__(\n        self,\n        name: str,\n        unit: str = \"\",\n        description: str = \"\",\n    ) -> None:\n        super().__init__(name, unit=unit, description=description)\n\n    def add(\n        self,\n        amount: Union[int, float],\n        attributes: Optional[Attributes] = None,\n    ) -> None:\n        return super().add(amount, attributes=attributes)\n\n\nclass _ProxyUpDownCounter(_ProxyInstrument[UpDownCounter], UpDownCounter):\n    def add(\n        self,\n        amount: Union[int, float],\n        attributes: Optional[Attributes] = None,\n    ) -> None:\n        if self._real_instrument:\n            self._real_instrument.add(amount, attributes)\n\n    def _create_real_instrument(self, meter: \"metrics.Meter\") -> UpDownCounter:\n        return meter.create_up_down_counter(\n            self._name, self._unit, self._description\n        )\n\n\nclass ObservableCounter(Asynchronous):\n    \"\"\"An ObservableCounter is an asynchronous `Instrument` which reports monotonically\n    increasing value(s) when the instrument is being observed.\n    \"\"\"\n\n\nclass NoOpObservableCounter(ObservableCounter):\n    \"\"\"No-op implementation of `ObservableCounter`.\"\"\"\n\n    def __init__(\n        self,\n        name: str,\n        callbacks: Optional[Sequence[CallbackT]] = None,\n        unit: str = \"\",\n        description: str = \"\",\n    ) -> None:\n        super().__init__(name, callbacks, unit=unit, description=description)\n\n\nclass _ProxyObservableCounter(\n    _ProxyAsynchronousInstrument[ObservableCounter], ObservableCounter\n):\n    def _create_real_instrument(\n        self, meter: \"metrics.Meter\"\n    ) -> ObservableCounter:\n        return meter.create_observable_counter(\n            self._name, self._callbacks, self._unit, self._description\n        )\n\n\nclass ObservableUpDownCounter(Asynchronous):\n    \"\"\"An ObservableUpDownCounter is an asynchronous `Instrument` which reports additive value(s) (e.g.\n    the process heap size - it makes sense to report the heap size from multiple processes and sum them\n    up, so we get the total heap usage) when the instrument is being observed.\n    \"\"\"\n\n\nclass NoOpObservableUpDownCounter(ObservableUpDownCounter):\n    \"\"\"No-op implementation of `ObservableUpDownCounter`.\"\"\"\n\n    def __init__(\n        self,\n        name: str,\n        callbacks: Optional[Sequence[CallbackT]] = None,\n        unit: str = \"\",\n        description: str = \"\",\n    ) -> None:\n        super().__init__(name, callbacks, unit=unit, description=description)\n\n\nclass _ProxyObservableUpDownCounter(\n    _ProxyAsynchronousInstrument[ObservableUpDownCounter],\n    ObservableUpDownCounter,\n):\n    def _create_real_instrument(\n        self, meter: \"metrics.Meter\"\n    ) -> ObservableUpDownCounter:\n        return meter.create_observable_up_down_counter(\n            self._name, self._callbacks, self._unit, self._description\n        )\n\n\nclass Histogram(Synchronous):\n    \"\"\"Histogram is a synchronous `Instrument` which can be used to report arbitrary values\n    that are likely to be statistically meaningful. It is intended for statistics such as\n    histograms, summaries, and percentile.\n    \"\"\"\n\n    @abstractmethod\n    def record(\n        self,\n        amount: Union[int, float],\n        attributes: Optional[Attributes] = None,\n    ) -> None:\n        pass\n\n\nclass NoOpHistogram(Histogram):\n    \"\"\"No-op implementation of `Histogram`.\"\"\"\n\n    def __init__(\n        self,\n        name: str,\n        unit: str = \"\",\n        description: str = \"\",\n    ) -> None:\n        super().__init__(name, unit=unit, description=description)\n\n    def record(\n        self,\n        amount: Union[int, float],\n        attributes: Optional[Attributes] = None,\n    ) -> None:\n        return super().record(amount, attributes=attributes)\n\n\nclass _ProxyHistogram(_ProxyInstrument[Histogram], Histogram):\n    def record(\n        self,\n        amount: Union[int, float],\n        attributes: Optional[Attributes] = None,\n    ) -> None:\n        if self._real_instrument:\n            self._real_instrument.record(amount, attributes)\n\n    def _create_real_instrument(self, meter: \"metrics.Meter\") -> Histogram:\n        return meter.create_histogram(\n            self._name, self._unit, self._description\n        )\n\n\nclass ObservableGauge(Asynchronous):\n    \"\"\"Asynchronous Gauge is an asynchronous `Instrument` which reports non-additive value(s) (e.g.\n    the room temperature - it makes no sense to report the temperature value from multiple rooms\n    and sum them up) when the instrument is being observed.\n    \"\"\"\n\n\nclass NoOpObservableGauge(ObservableGauge):\n    \"\"\"No-op implementation of `ObservableGauge`.\"\"\"\n\n    def __init__(\n        self,\n        name: str,\n        callbacks: Optional[Sequence[CallbackT]] = None,\n        unit: str = \"\",\n        description: str = \"\",\n    ) -> None:\n        super().__init__(name, callbacks, unit=unit, description=description)\n\n\nclass _ProxyObservableGauge(\n    _ProxyAsynchronousInstrument[ObservableGauge],\n    ObservableGauge,\n):\n    def _create_real_instrument(\n        self, meter: \"metrics.Meter\"\n    ) -> ObservableGauge:\n        return meter.create_observable_gauge(\n            self._name, self._callbacks, self._unit, self._description\n        )\n", "path": "opentelemetry-api/src/opentelemetry/metrics/_internal/instrument.py"}], "after_files": [{"content": "# Copyright The OpenTelemetry Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# pylint: disable=too-many-ancestors\n\n\nfrom abc import ABC, abstractmethod\nfrom dataclasses import dataclass\nfrom logging import getLogger\nfrom re import compile as re_compile\nfrom typing import (\n    Callable,\n    Dict,\n    Generator,\n    Generic,\n    Iterable,\n    Optional,\n    Sequence,\n    TypeVar,\n    Union,\n)\n\n# pylint: disable=unused-import; needed for typing and sphinx\nfrom opentelemetry import metrics\nfrom opentelemetry.metrics._internal.observation import Observation\nfrom opentelemetry.util.types import Attributes\n\n_logger = getLogger(__name__)\n\n_name_regex = re_compile(r\"[a-zA-Z][-_./a-zA-Z0-9]{0,254}\")\n_unit_regex = re_compile(r\"[\\x00-\\x7F]{0,63}\")\n\n\n@dataclass(frozen=True)\nclass CallbackOptions:\n    \"\"\"Options for the callback\n\n    Args:\n        timeout_millis: Timeout for the callback's execution. If the callback does asynchronous\n            work (e.g. HTTP requests), it should respect this timeout.\n    \"\"\"\n\n    timeout_millis: float = 10_000\n\n\nInstrumentT = TypeVar(\"InstrumentT\", bound=\"Instrument\")\nCallbackT = Union[\n    Callable[[CallbackOptions], Iterable[Observation]],\n    Generator[Iterable[Observation], CallbackOptions, None],\n]\n\n\nclass Instrument(ABC):\n    \"\"\"Abstract class that serves as base for all instruments.\"\"\"\n\n    @abstractmethod\n    def __init__(\n        self,\n        name: str,\n        unit: str = \"\",\n        description: str = \"\",\n    ) -> None:\n        pass\n\n    @staticmethod\n    def _check_name_unit_description(\n        name: str, unit: str, description: str\n    ) -> Dict[str, Optional[str]]:\n        \"\"\"\n        Checks the following instrument name, unit and description for\n        compliance with the spec.\n\n        Returns a dict with keys \"name\", \"unit\" and \"description\", the\n        corresponding values will be the checked strings or `None` if the value\n        is invalid. If valid, the checked strings should be used instead of the\n        original values.\n        \"\"\"\n\n        result: Dict[str, Optional[str]] = {}\n\n        if _name_regex.fullmatch(name) is not None:\n            result[\"name\"] = name\n        else:\n            result[\"name\"] = None\n\n        if unit is None:\n            unit = \"\"\n        if _unit_regex.fullmatch(unit) is not None:\n            result[\"unit\"] = unit\n        else:\n            result[\"unit\"] = None\n\n        if description is None:\n            result[\"description\"] = \"\"\n        else:\n            result[\"description\"] = description\n\n        return result\n\n\nclass _ProxyInstrument(ABC, Generic[InstrumentT]):\n    def __init__(\n        self,\n        name: str,\n        unit: str = \"\",\n        description: str = \"\",\n    ) -> None:\n        self._name = name\n        self._unit = unit\n        self._description = description\n        self._real_instrument: Optional[InstrumentT] = None\n\n    def on_meter_set(self, meter: \"metrics.Meter\") -> None:\n        \"\"\"Called when a real meter is set on the creating _ProxyMeter\"\"\"\n\n        # We don't need any locking on proxy instruments because it's OK if some\n        # measurements get dropped while a real backing instrument is being\n        # created.\n        self._real_instrument = self._create_real_instrument(meter)\n\n    @abstractmethod\n    def _create_real_instrument(self, meter: \"metrics.Meter\") -> InstrumentT:\n        \"\"\"Create an instance of the real instrument. Implement this.\"\"\"\n\n\nclass _ProxyAsynchronousInstrument(_ProxyInstrument[InstrumentT]):\n    def __init__(\n        self,\n        name: str,\n        callbacks: Optional[Sequence[CallbackT]] = None,\n        unit: str = \"\",\n        description: str = \"\",\n    ) -> None:\n        super().__init__(name, unit, description)\n        self._callbacks = callbacks\n\n\nclass Synchronous(Instrument):\n    \"\"\"Base class for all synchronous instruments\"\"\"\n\n\nclass Asynchronous(Instrument):\n    \"\"\"Base class for all asynchronous instruments\"\"\"\n\n    @abstractmethod\n    def __init__(\n        self,\n        name: str,\n        callbacks: Optional[Sequence[CallbackT]] = None,\n        unit: str = \"\",\n        description: str = \"\",\n    ) -> None:\n        super().__init__(name, unit=unit, description=description)\n\n\nclass Counter(Synchronous):\n    \"\"\"A Counter is a synchronous `Instrument` which supports non-negative increments.\"\"\"\n\n    @abstractmethod\n    def add(\n        self,\n        amount: Union[int, float],\n        attributes: Optional[Attributes] = None,\n    ) -> None:\n        pass\n\n\nclass NoOpCounter(Counter):\n    \"\"\"No-op implementation of `Counter`.\"\"\"\n\n    def __init__(\n        self,\n        name: str,\n        unit: str = \"\",\n        description: str = \"\",\n    ) -> None:\n        super().__init__(name, unit=unit, description=description)\n\n    def add(\n        self,\n        amount: Union[int, float],\n        attributes: Optional[Attributes] = None,\n    ) -> None:\n        return super().add(amount, attributes=attributes)\n\n\nclass _ProxyCounter(_ProxyInstrument[Counter], Counter):\n    def add(\n        self,\n        amount: Union[int, float],\n        attributes: Optional[Attributes] = None,\n    ) -> None:\n        if self._real_instrument:\n            self._real_instrument.add(amount, attributes)\n\n    def _create_real_instrument(self, meter: \"metrics.Meter\") -> Counter:\n        return meter.create_counter(self._name, self._unit, self._description)\n\n\nclass UpDownCounter(Synchronous):\n    \"\"\"An UpDownCounter is a synchronous `Instrument` which supports increments and decrements.\"\"\"\n\n    @abstractmethod\n    def add(\n        self,\n        amount: Union[int, float],\n        attributes: Optional[Attributes] = None,\n    ) -> None:\n        pass\n\n\nclass NoOpUpDownCounter(UpDownCounter):\n    \"\"\"No-op implementation of `UpDownCounter`.\"\"\"\n\n    def __init__(\n        self,\n        name: str,\n        unit: str = \"\",\n        description: str = \"\",\n    ) -> None:\n        super().__init__(name, unit=unit, description=description)\n\n    def add(\n        self,\n        amount: Union[int, float],\n        attributes: Optional[Attributes] = None,\n    ) -> None:\n        return super().add(amount, attributes=attributes)\n\n\nclass _ProxyUpDownCounter(_ProxyInstrument[UpDownCounter], UpDownCounter):\n    def add(\n        self,\n        amount: Union[int, float],\n        attributes: Optional[Attributes] = None,\n    ) -> None:\n        if self._real_instrument:\n            self._real_instrument.add(amount, attributes)\n\n    def _create_real_instrument(self, meter: \"metrics.Meter\") -> UpDownCounter:\n        return meter.create_up_down_counter(\n            self._name, self._unit, self._description\n        )\n\n\nclass ObservableCounter(Asynchronous):\n    \"\"\"An ObservableCounter is an asynchronous `Instrument` which reports monotonically\n    increasing value(s) when the instrument is being observed.\n    \"\"\"\n\n\nclass NoOpObservableCounter(ObservableCounter):\n    \"\"\"No-op implementation of `ObservableCounter`.\"\"\"\n\n    def __init__(\n        self,\n        name: str,\n        callbacks: Optional[Sequence[CallbackT]] = None,\n        unit: str = \"\",\n        description: str = \"\",\n    ) -> None:\n        super().__init__(name, callbacks, unit=unit, description=description)\n\n\nclass _ProxyObservableCounter(\n    _ProxyAsynchronousInstrument[ObservableCounter], ObservableCounter\n):\n    def _create_real_instrument(\n        self, meter: \"metrics.Meter\"\n    ) -> ObservableCounter:\n        return meter.create_observable_counter(\n            self._name, self._callbacks, self._unit, self._description\n        )\n\n\nclass ObservableUpDownCounter(Asynchronous):\n    \"\"\"An ObservableUpDownCounter is an asynchronous `Instrument` which reports additive value(s) (e.g.\n    the process heap size - it makes sense to report the heap size from multiple processes and sum them\n    up, so we get the total heap usage) when the instrument is being observed.\n    \"\"\"\n\n\nclass NoOpObservableUpDownCounter(ObservableUpDownCounter):\n    \"\"\"No-op implementation of `ObservableUpDownCounter`.\"\"\"\n\n    def __init__(\n        self,\n        name: str,\n        callbacks: Optional[Sequence[CallbackT]] = None,\n        unit: str = \"\",\n        description: str = \"\",\n    ) -> None:\n        super().__init__(name, callbacks, unit=unit, description=description)\n\n\nclass _ProxyObservableUpDownCounter(\n    _ProxyAsynchronousInstrument[ObservableUpDownCounter],\n    ObservableUpDownCounter,\n):\n    def _create_real_instrument(\n        self, meter: \"metrics.Meter\"\n    ) -> ObservableUpDownCounter:\n        return meter.create_observable_up_down_counter(\n            self._name, self._callbacks, self._unit, self._description\n        )\n\n\nclass Histogram(Synchronous):\n    \"\"\"Histogram is a synchronous `Instrument` which can be used to report arbitrary values\n    that are likely to be statistically meaningful. It is intended for statistics such as\n    histograms, summaries, and percentile.\n    \"\"\"\n\n    @abstractmethod\n    def record(\n        self,\n        amount: Union[int, float],\n        attributes: Optional[Attributes] = None,\n    ) -> None:\n        pass\n\n\nclass NoOpHistogram(Histogram):\n    \"\"\"No-op implementation of `Histogram`.\"\"\"\n\n    def __init__(\n        self,\n        name: str,\n        unit: str = \"\",\n        description: str = \"\",\n    ) -> None:\n        super().__init__(name, unit=unit, description=description)\n\n    def record(\n        self,\n        amount: Union[int, float],\n        attributes: Optional[Attributes] = None,\n    ) -> None:\n        return super().record(amount, attributes=attributes)\n\n\nclass _ProxyHistogram(_ProxyInstrument[Histogram], Histogram):\n    def record(\n        self,\n        amount: Union[int, float],\n        attributes: Optional[Attributes] = None,\n    ) -> None:\n        if self._real_instrument:\n            self._real_instrument.record(amount, attributes)\n\n    def _create_real_instrument(self, meter: \"metrics.Meter\") -> Histogram:\n        return meter.create_histogram(\n            self._name, self._unit, self._description\n        )\n\n\nclass ObservableGauge(Asynchronous):\n    \"\"\"Asynchronous Gauge is an asynchronous `Instrument` which reports non-additive value(s) (e.g.\n    the room temperature - it makes no sense to report the temperature value from multiple rooms\n    and sum them up) when the instrument is being observed.\n    \"\"\"\n\n\nclass NoOpObservableGauge(ObservableGauge):\n    \"\"\"No-op implementation of `ObservableGauge`.\"\"\"\n\n    def __init__(\n        self,\n        name: str,\n        callbacks: Optional[Sequence[CallbackT]] = None,\n        unit: str = \"\",\n        description: str = \"\",\n    ) -> None:\n        super().__init__(name, callbacks, unit=unit, description=description)\n\n\nclass _ProxyObservableGauge(\n    _ProxyAsynchronousInstrument[ObservableGauge],\n    ObservableGauge,\n):\n    def _create_real_instrument(\n        self, meter: \"metrics.Meter\"\n    ) -> ObservableGauge:\n        return meter.create_observable_gauge(\n            self._name, self._callbacks, self._unit, self._description\n        )\n", "path": "opentelemetry-api/src/opentelemetry/metrics/_internal/instrument.py"}]}