We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
MetricReaders must be registered in only one MeterProvider instance
From the [spec](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#metricreader):

> The SDK MUST NOT allow a MetricReader instance to be registered on more than one MeterProvider instance.

--- 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-sdk/src/opentelemetry/sdk/_metrics/__init__.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 from atexit import register, unregister
16 from logging import getLogger
17 from threading import Lock
18 from typing import Optional, Sequence
19 
20 from opentelemetry._metrics import Meter as APIMeter
21 from opentelemetry._metrics import MeterProvider as APIMeterProvider
22 from opentelemetry._metrics import NoOpMeter
23 from opentelemetry._metrics.instrument import Counter as APICounter
24 from opentelemetry._metrics.instrument import Histogram as APIHistogram
25 from opentelemetry._metrics.instrument import (
26     ObservableCounter as APIObservableCounter,
27 )
28 from opentelemetry._metrics.instrument import (
29     ObservableGauge as APIObservableGauge,
30 )
31 from opentelemetry._metrics.instrument import (
32     ObservableUpDownCounter as APIObservableUpDownCounter,
33 )
34 from opentelemetry._metrics.instrument import UpDownCounter as APIUpDownCounter
35 from opentelemetry.sdk._metrics.instrument import (
36     Counter,
37     Histogram,
38     ObservableCounter,
39     ObservableGauge,
40     ObservableUpDownCounter,
41     UpDownCounter,
42 )
43 from opentelemetry.sdk._metrics.measurement_consumer import (
44     MeasurementConsumer,
45     SynchronousMeasurementConsumer,
46 )
47 from opentelemetry.sdk._metrics.metric_reader import MetricReader
48 from opentelemetry.sdk._metrics.sdk_configuration import SdkConfiguration
49 from opentelemetry.sdk._metrics.view import View
50 from opentelemetry.sdk.resources import Resource
51 from opentelemetry.sdk.util.instrumentation import InstrumentationInfo
52 from opentelemetry.util._once import Once
53 
54 _logger = getLogger(__name__)
55 
56 
57 class Meter(APIMeter):
58     def __init__(
59         self,
60         instrumentation_info: InstrumentationInfo,
61         measurement_consumer: MeasurementConsumer,
62     ):
63         super().__init__(instrumentation_info)
64         self._instrumentation_info = instrumentation_info
65         self._measurement_consumer = measurement_consumer
66 
67     def create_counter(self, name, unit=None, description=None) -> APICounter:
68         return Counter(
69             name,
70             self._instrumentation_info,
71             self._measurement_consumer,
72             unit,
73             description,
74         )
75 
76     def create_up_down_counter(
77         self, name, unit=None, description=None
78     ) -> APIUpDownCounter:
79         return UpDownCounter(
80             name,
81             self._instrumentation_info,
82             self._measurement_consumer,
83             unit,
84             description,
85         )
86 
87     def create_observable_counter(
88         self, name, callback, unit=None, description=None
89     ) -> APIObservableCounter:
90 
91         instrument = ObservableCounter(
92             name,
93             self._instrumentation_info,
94             self._measurement_consumer,
95             callback,
96             unit,
97             description,
98         )
99 
100         self._measurement_consumer.register_asynchronous_instrument(instrument)
101 
102         return instrument
103 
104     def create_histogram(
105         self, name, unit=None, description=None
106     ) -> APIHistogram:
107         return Histogram(
108             name,
109             self._instrumentation_info,
110             self._measurement_consumer,
111             unit,
112             description,
113         )
114 
115     def create_observable_gauge(
116         self, name, callback, unit=None, description=None
117     ) -> APIObservableGauge:
118 
119         instrument = ObservableGauge(
120             name,
121             self._instrumentation_info,
122             self._measurement_consumer,
123             callback,
124             unit,
125             description,
126         )
127 
128         self._measurement_consumer.register_asynchronous_instrument(instrument)
129 
130         return instrument
131 
132     def create_observable_up_down_counter(
133         self, name, callback, unit=None, description=None
134     ) -> APIObservableUpDownCounter:
135 
136         instrument = ObservableUpDownCounter(
137             name,
138             self._instrumentation_info,
139             self._measurement_consumer,
140             callback,
141             unit,
142             description,
143         )
144 
145         self._measurement_consumer.register_asynchronous_instrument(instrument)
146 
147         return instrument
148 
149 
150 class MeterProvider(APIMeterProvider):
151     r"""See `opentelemetry._metrics.MeterProvider`.
152 
153     Args:
154         metric_readers: Register metric readers to collect metrics from the SDK on demand. Each
155             `MetricReader` is completely independent and will collect separate streams of
156             metrics. TODO: reference ``PeriodicExportingMetricReader`` usage with push
157             exporters here.
158         resource: The resource representing what the metrics emitted from the SDK pertain to.
159         shutdown_on_exit: If true, registers an `atexit` handler to call
160             `MeterProvider.shutdown`
161         views: The views to configure the metric output the SDK
162 
163     By default, instruments which do not match any `View` (or if no `View`\ s are provided)
164     will report metrics with the default aggregation for the instrument's kind. To disable
165     instruments by default, configure a match-all `View` with `DropAggregation` and then create
166     `View`\ s to re-enable individual instruments:
167 
168     .. code-block:: python
169         :caption: Disable default views
170 
171         MeterProvider(
172             views=[
173                 View(instrument_name="*", aggregation=DropAggregation()),
174                 View(instrument_name="mycounter"),
175             ],
176             # ...
177         )
178     """
179 
180     def __init__(
181         self,
182         metric_readers: Sequence[MetricReader] = (),
183         resource: Resource = Resource.create({}),
184         shutdown_on_exit: bool = True,
185         views: Sequence[View] = (),
186     ):
187         self._lock = Lock()
188         self._meter_lock = Lock()
189         self._atexit_handler = None
190         self._sdk_config = SdkConfiguration(
191             resource=resource,
192             metric_readers=metric_readers,
193             views=views,
194         )
195         self._measurement_consumer = SynchronousMeasurementConsumer(
196             sdk_config=self._sdk_config
197         )
198 
199         if shutdown_on_exit:
200             self._atexit_handler = register(self.shutdown)
201 
202         self._meters = {}
203         self._metric_readers = metric_readers
204 
205         for metric_reader in self._sdk_config.metric_readers:
206             metric_reader._set_collect_callback(
207                 self._measurement_consumer.collect
208             )
209 
210         self._shutdown_once = Once()
211         self._shutdown = False
212 
213     def force_flush(self) -> bool:
214 
215         # FIXME implement a timeout
216 
217         for metric_reader in self._sdk_config.metric_readers:
218             metric_reader.collect()
219         return True
220 
221     def shutdown(self):
222         # FIXME implement a timeout
223 
224         def _shutdown():
225             self._shutdown = True
226 
227         did_shutdown = self._shutdown_once.do_once(_shutdown)
228 
229         if not did_shutdown:
230             _logger.warning("shutdown can only be called once")
231             return False
232 
233         overall_result = True
234 
235         for metric_reader in self._sdk_config.metric_readers:
236             metric_reader_result = metric_reader.shutdown()
237 
238             if not metric_reader_result:
239                 _logger.warning(
240                     "MetricReader %s failed to shutdown", metric_reader
241                 )
242 
243             overall_result = overall_result and metric_reader_result
244 
245         if self._atexit_handler is not None:
246             unregister(self._atexit_handler)
247             self._atexit_handler = None
248 
249         return overall_result
250 
251     def get_meter(
252         self,
253         name: str,
254         version: Optional[str] = None,
255         schema_url: Optional[str] = None,
256     ) -> Meter:
257 
258         if self._shutdown:
259             _logger.warning(
260                 "A shutdown `MeterProvider` can not provide a `Meter`"
261             )
262             return NoOpMeter(name, version=version, schema_url=schema_url)
263 
264         if not name:
265             _logger.warning("Meter name cannot be None or empty.")
266             return NoOpMeter(name, version=version, schema_url=schema_url)
267 
268         info = InstrumentationInfo(name, version, schema_url)
269         with self._meter_lock:
270             if not self._meters.get(info):
271                 self._meters[info] = Meter(
272                     info,
273                     self._measurement_consumer,
274                 )
275             return self._meters[info]
276
```
--- 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-sdk/src/opentelemetry/sdk/_metrics/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/__init__.py
--- a/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/__init__.py
+++ b/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/__init__.py
@@ -177,6 +177,9 @@
         )
     """
 
+    _all_metric_readers_lock = Lock()
+    _all_metric_readers = set()
+
     def __init__(
         self,
         metric_readers: Sequence[MetricReader] = (),
@@ -200,9 +203,18 @@
             self._atexit_handler = register(self.shutdown)
 
         self._meters = {}
-        self._metric_readers = metric_readers
 
         for metric_reader in self._sdk_config.metric_readers:
+
+            with self._all_metric_readers_lock:
+                if metric_reader in self._all_metric_readers:
+                    raise Exception(
+                        f"MetricReader {metric_reader} has been registered "
+                        "already in other MeterProvider instance"
+                    )
+
+                self._all_metric_readers.add(metric_reader)
+
             metric_reader._set_collect_callback(
                 self._measurement_consumer.collect
             )

{"golden_diff": "diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/__init__.py\n--- a/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/__init__.py\n+++ b/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/__init__.py\n@@ -177,6 +177,9 @@\n         )\n     \"\"\"\n \n+    _all_metric_readers_lock = Lock()\n+    _all_metric_readers = set()\n+\n     def __init__(\n         self,\n         metric_readers: Sequence[MetricReader] = (),\n@@ -200,9 +203,18 @@\n             self._atexit_handler = register(self.shutdown)\n \n         self._meters = {}\n-        self._metric_readers = metric_readers\n \n         for metric_reader in self._sdk_config.metric_readers:\n+\n+            with self._all_metric_readers_lock:\n+                if metric_reader in self._all_metric_readers:\n+                    raise Exception(\n+                        f\"MetricReader {metric_reader} has been registered \"\n+                        \"already in other MeterProvider instance\"\n+                    )\n+\n+                self._all_metric_readers.add(metric_reader)\n+\n             metric_reader._set_collect_callback(\n                 self._measurement_consumer.collect\n             )\n", "issue": "MetricReaders must be registered in only one MeterProvider instance\nFrom the [spec](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#metricreader):\r\n\r\n> The SDK MUST NOT allow a MetricReader instance to be registered on more than one MeterProvider instance.\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\nfrom atexit import register, unregister\nfrom logging import getLogger\nfrom threading import Lock\nfrom typing import Optional, Sequence\n\nfrom opentelemetry._metrics import Meter as APIMeter\nfrom opentelemetry._metrics import MeterProvider as APIMeterProvider\nfrom opentelemetry._metrics import NoOpMeter\nfrom opentelemetry._metrics.instrument import Counter as APICounter\nfrom opentelemetry._metrics.instrument import Histogram as APIHistogram\nfrom opentelemetry._metrics.instrument import (\n    ObservableCounter as APIObservableCounter,\n)\nfrom opentelemetry._metrics.instrument import (\n    ObservableGauge as APIObservableGauge,\n)\nfrom opentelemetry._metrics.instrument import (\n    ObservableUpDownCounter as APIObservableUpDownCounter,\n)\nfrom opentelemetry._metrics.instrument import UpDownCounter as APIUpDownCounter\nfrom opentelemetry.sdk._metrics.instrument import (\n    Counter,\n    Histogram,\n    ObservableCounter,\n    ObservableGauge,\n    ObservableUpDownCounter,\n    UpDownCounter,\n)\nfrom opentelemetry.sdk._metrics.measurement_consumer import (\n    MeasurementConsumer,\n    SynchronousMeasurementConsumer,\n)\nfrom opentelemetry.sdk._metrics.metric_reader import MetricReader\nfrom opentelemetry.sdk._metrics.sdk_configuration import SdkConfiguration\nfrom opentelemetry.sdk._metrics.view import View\nfrom opentelemetry.sdk.resources import Resource\nfrom opentelemetry.sdk.util.instrumentation import InstrumentationInfo\nfrom opentelemetry.util._once import Once\n\n_logger = getLogger(__name__)\n\n\nclass Meter(APIMeter):\n    def __init__(\n        self,\n        instrumentation_info: InstrumentationInfo,\n        measurement_consumer: MeasurementConsumer,\n    ):\n        super().__init__(instrumentation_info)\n        self._instrumentation_info = instrumentation_info\n        self._measurement_consumer = measurement_consumer\n\n    def create_counter(self, name, unit=None, description=None) -> APICounter:\n        return Counter(\n            name,\n            self._instrumentation_info,\n            self._measurement_consumer,\n            unit,\n            description,\n        )\n\n    def create_up_down_counter(\n        self, name, unit=None, description=None\n    ) -> APIUpDownCounter:\n        return UpDownCounter(\n            name,\n            self._instrumentation_info,\n            self._measurement_consumer,\n            unit,\n            description,\n        )\n\n    def create_observable_counter(\n        self, name, callback, unit=None, description=None\n    ) -> APIObservableCounter:\n\n        instrument = ObservableCounter(\n            name,\n            self._instrumentation_info,\n            self._measurement_consumer,\n            callback,\n            unit,\n            description,\n        )\n\n        self._measurement_consumer.register_asynchronous_instrument(instrument)\n\n        return instrument\n\n    def create_histogram(\n        self, name, unit=None, description=None\n    ) -> APIHistogram:\n        return Histogram(\n            name,\n            self._instrumentation_info,\n            self._measurement_consumer,\n            unit,\n            description,\n        )\n\n    def create_observable_gauge(\n        self, name, callback, unit=None, description=None\n    ) -> APIObservableGauge:\n\n        instrument = ObservableGauge(\n            name,\n            self._instrumentation_info,\n            self._measurement_consumer,\n            callback,\n            unit,\n            description,\n        )\n\n        self._measurement_consumer.register_asynchronous_instrument(instrument)\n\n        return instrument\n\n    def create_observable_up_down_counter(\n        self, name, callback, unit=None, description=None\n    ) -> APIObservableUpDownCounter:\n\n        instrument = ObservableUpDownCounter(\n            name,\n            self._instrumentation_info,\n            self._measurement_consumer,\n            callback,\n            unit,\n            description,\n        )\n\n        self._measurement_consumer.register_asynchronous_instrument(instrument)\n\n        return instrument\n\n\nclass MeterProvider(APIMeterProvider):\n    r\"\"\"See `opentelemetry._metrics.MeterProvider`.\n\n    Args:\n        metric_readers: Register metric readers to collect metrics from the SDK on demand. Each\n            `MetricReader` is completely independent and will collect separate streams of\n            metrics. TODO: reference ``PeriodicExportingMetricReader`` usage with push\n            exporters here.\n        resource: The resource representing what the metrics emitted from the SDK pertain to.\n        shutdown_on_exit: If true, registers an `atexit` handler to call\n            `MeterProvider.shutdown`\n        views: The views to configure the metric output the SDK\n\n    By default, instruments which do not match any `View` (or if no `View`\\ s are provided)\n    will report metrics with the default aggregation for the instrument's kind. To disable\n    instruments by default, configure a match-all `View` with `DropAggregation` and then create\n    `View`\\ s to re-enable individual instruments:\n\n    .. code-block:: python\n        :caption: Disable default views\n\n        MeterProvider(\n            views=[\n                View(instrument_name=\"*\", aggregation=DropAggregation()),\n                View(instrument_name=\"mycounter\"),\n            ],\n            # ...\n        )\n    \"\"\"\n\n    def __init__(\n        self,\n        metric_readers: Sequence[MetricReader] = (),\n        resource: Resource = Resource.create({}),\n        shutdown_on_exit: bool = True,\n        views: Sequence[View] = (),\n    ):\n        self._lock = Lock()\n        self._meter_lock = Lock()\n        self._atexit_handler = None\n        self._sdk_config = SdkConfiguration(\n            resource=resource,\n            metric_readers=metric_readers,\n            views=views,\n        )\n        self._measurement_consumer = SynchronousMeasurementConsumer(\n            sdk_config=self._sdk_config\n        )\n\n        if shutdown_on_exit:\n            self._atexit_handler = register(self.shutdown)\n\n        self._meters = {}\n        self._metric_readers = metric_readers\n\n        for metric_reader in self._sdk_config.metric_readers:\n            metric_reader._set_collect_callback(\n                self._measurement_consumer.collect\n            )\n\n        self._shutdown_once = Once()\n        self._shutdown = False\n\n    def force_flush(self) -> bool:\n\n        # FIXME implement a timeout\n\n        for metric_reader in self._sdk_config.metric_readers:\n            metric_reader.collect()\n        return True\n\n    def shutdown(self):\n        # FIXME implement a timeout\n\n        def _shutdown():\n            self._shutdown = True\n\n        did_shutdown = self._shutdown_once.do_once(_shutdown)\n\n        if not did_shutdown:\n            _logger.warning(\"shutdown can only be called once\")\n            return False\n\n        overall_result = True\n\n        for metric_reader in self._sdk_config.metric_readers:\n            metric_reader_result = metric_reader.shutdown()\n\n            if not metric_reader_result:\n                _logger.warning(\n                    \"MetricReader %s failed to shutdown\", metric_reader\n                )\n\n            overall_result = overall_result and metric_reader_result\n\n        if self._atexit_handler is not None:\n            unregister(self._atexit_handler)\n            self._atexit_handler = None\n\n        return overall_result\n\n    def get_meter(\n        self,\n        name: str,\n        version: Optional[str] = None,\n        schema_url: Optional[str] = None,\n    ) -> Meter:\n\n        if self._shutdown:\n            _logger.warning(\n                \"A shutdown `MeterProvider` can not provide a `Meter`\"\n            )\n            return NoOpMeter(name, version=version, schema_url=schema_url)\n\n        if not name:\n            _logger.warning(\"Meter name cannot be None or empty.\")\n            return NoOpMeter(name, version=version, schema_url=schema_url)\n\n        info = InstrumentationInfo(name, version, schema_url)\n        with self._meter_lock:\n            if not self._meters.get(info):\n                self._meters[info] = Meter(\n                    info,\n                    self._measurement_consumer,\n                )\n            return self._meters[info]\n", "path": "opentelemetry-sdk/src/opentelemetry/sdk/_metrics/__init__.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\nfrom atexit import register, unregister\nfrom logging import getLogger\nfrom threading import Lock\nfrom typing import Optional, Sequence\n\nfrom opentelemetry._metrics import Meter as APIMeter\nfrom opentelemetry._metrics import MeterProvider as APIMeterProvider\nfrom opentelemetry._metrics import NoOpMeter\nfrom opentelemetry._metrics.instrument import Counter as APICounter\nfrom opentelemetry._metrics.instrument import Histogram as APIHistogram\nfrom opentelemetry._metrics.instrument import (\n    ObservableCounter as APIObservableCounter,\n)\nfrom opentelemetry._metrics.instrument import (\n    ObservableGauge as APIObservableGauge,\n)\nfrom opentelemetry._metrics.instrument import (\n    ObservableUpDownCounter as APIObservableUpDownCounter,\n)\nfrom opentelemetry._metrics.instrument import UpDownCounter as APIUpDownCounter\nfrom opentelemetry.sdk._metrics.instrument import (\n    Counter,\n    Histogram,\n    ObservableCounter,\n    ObservableGauge,\n    ObservableUpDownCounter,\n    UpDownCounter,\n)\nfrom opentelemetry.sdk._metrics.measurement_consumer import (\n    MeasurementConsumer,\n    SynchronousMeasurementConsumer,\n)\nfrom opentelemetry.sdk._metrics.metric_reader import MetricReader\nfrom opentelemetry.sdk._metrics.sdk_configuration import SdkConfiguration\nfrom opentelemetry.sdk._metrics.view import View\nfrom opentelemetry.sdk.resources import Resource\nfrom opentelemetry.sdk.util.instrumentation import InstrumentationInfo\nfrom opentelemetry.util._once import Once\n\n_logger = getLogger(__name__)\n\n\nclass Meter(APIMeter):\n    def __init__(\n        self,\n        instrumentation_info: InstrumentationInfo,\n        measurement_consumer: MeasurementConsumer,\n    ):\n        super().__init__(instrumentation_info)\n        self._instrumentation_info = instrumentation_info\n        self._measurement_consumer = measurement_consumer\n\n    def create_counter(self, name, unit=None, description=None) -> APICounter:\n        return Counter(\n            name,\n            self._instrumentation_info,\n            self._measurement_consumer,\n            unit,\n            description,\n        )\n\n    def create_up_down_counter(\n        self, name, unit=None, description=None\n    ) -> APIUpDownCounter:\n        return UpDownCounter(\n            name,\n            self._instrumentation_info,\n            self._measurement_consumer,\n            unit,\n            description,\n        )\n\n    def create_observable_counter(\n        self, name, callback, unit=None, description=None\n    ) -> APIObservableCounter:\n\n        instrument = ObservableCounter(\n            name,\n            self._instrumentation_info,\n            self._measurement_consumer,\n            callback,\n            unit,\n            description,\n        )\n\n        self._measurement_consumer.register_asynchronous_instrument(instrument)\n\n        return instrument\n\n    def create_histogram(\n        self, name, unit=None, description=None\n    ) -> APIHistogram:\n        return Histogram(\n            name,\n            self._instrumentation_info,\n            self._measurement_consumer,\n            unit,\n            description,\n        )\n\n    def create_observable_gauge(\n        self, name, callback, unit=None, description=None\n    ) -> APIObservableGauge:\n\n        instrument = ObservableGauge(\n            name,\n            self._instrumentation_info,\n            self._measurement_consumer,\n            callback,\n            unit,\n            description,\n        )\n\n        self._measurement_consumer.register_asynchronous_instrument(instrument)\n\n        return instrument\n\n    def create_observable_up_down_counter(\n        self, name, callback, unit=None, description=None\n    ) -> APIObservableUpDownCounter:\n\n        instrument = ObservableUpDownCounter(\n            name,\n            self._instrumentation_info,\n            self._measurement_consumer,\n            callback,\n            unit,\n            description,\n        )\n\n        self._measurement_consumer.register_asynchronous_instrument(instrument)\n\n        return instrument\n\n\nclass MeterProvider(APIMeterProvider):\n    r\"\"\"See `opentelemetry._metrics.MeterProvider`.\n\n    Args:\n        metric_readers: Register metric readers to collect metrics from the SDK on demand. Each\n            `MetricReader` is completely independent and will collect separate streams of\n            metrics. TODO: reference ``PeriodicExportingMetricReader`` usage with push\n            exporters here.\n        resource: The resource representing what the metrics emitted from the SDK pertain to.\n        shutdown_on_exit: If true, registers an `atexit` handler to call\n            `MeterProvider.shutdown`\n        views: The views to configure the metric output the SDK\n\n    By default, instruments which do not match any `View` (or if no `View`\\ s are provided)\n    will report metrics with the default aggregation for the instrument's kind. To disable\n    instruments by default, configure a match-all `View` with `DropAggregation` and then create\n    `View`\\ s to re-enable individual instruments:\n\n    .. code-block:: python\n        :caption: Disable default views\n\n        MeterProvider(\n            views=[\n                View(instrument_name=\"*\", aggregation=DropAggregation()),\n                View(instrument_name=\"mycounter\"),\n            ],\n            # ...\n        )\n    \"\"\"\n\n    _all_metric_readers_lock = Lock()\n    _all_metric_readers = set()\n\n    def __init__(\n        self,\n        metric_readers: Sequence[MetricReader] = (),\n        resource: Resource = Resource.create({}),\n        shutdown_on_exit: bool = True,\n        views: Sequence[View] = (),\n    ):\n        self._lock = Lock()\n        self._meter_lock = Lock()\n        self._atexit_handler = None\n        self._sdk_config = SdkConfiguration(\n            resource=resource,\n            metric_readers=metric_readers,\n            views=views,\n        )\n        self._measurement_consumer = SynchronousMeasurementConsumer(\n            sdk_config=self._sdk_config\n        )\n\n        if shutdown_on_exit:\n            self._atexit_handler = register(self.shutdown)\n\n        self._meters = {}\n\n        for metric_reader in self._sdk_config.metric_readers:\n\n            with self._all_metric_readers_lock:\n                if metric_reader in self._all_metric_readers:\n                    raise Exception(\n                        f\"MetricReader {metric_reader} has been registered \"\n                        \"already in other MeterProvider instance\"\n                    )\n\n                self._all_metric_readers.add(metric_reader)\n\n            metric_reader._set_collect_callback(\n                self._measurement_consumer.collect\n            )\n\n        self._shutdown_once = Once()\n        self._shutdown = False\n\n    def force_flush(self) -> bool:\n\n        # FIXME implement a timeout\n\n        for metric_reader in self._sdk_config.metric_readers:\n            metric_reader.collect()\n        return True\n\n    def shutdown(self):\n        # FIXME implement a timeout\n\n        def _shutdown():\n            self._shutdown = True\n\n        did_shutdown = self._shutdown_once.do_once(_shutdown)\n\n        if not did_shutdown:\n            _logger.warning(\"shutdown can only be called once\")\n            return False\n\n        overall_result = True\n\n        for metric_reader in self._sdk_config.metric_readers:\n            metric_reader_result = metric_reader.shutdown()\n\n            if not metric_reader_result:\n                _logger.warning(\n                    \"MetricReader %s failed to shutdown\", metric_reader\n                )\n\n            overall_result = overall_result and metric_reader_result\n\n        if self._atexit_handler is not None:\n            unregister(self._atexit_handler)\n            self._atexit_handler = None\n\n        return overall_result\n\n    def get_meter(\n        self,\n        name: str,\n        version: Optional[str] = None,\n        schema_url: Optional[str] = None,\n    ) -> Meter:\n\n        if self._shutdown:\n            _logger.warning(\n                \"A shutdown `MeterProvider` can not provide a `Meter`\"\n            )\n            return NoOpMeter(name, version=version, schema_url=schema_url)\n\n        if not name:\n            _logger.warning(\"Meter name cannot be None or empty.\")\n            return NoOpMeter(name, version=version, schema_url=schema_url)\n\n        info = InstrumentationInfo(name, version, schema_url)\n        with self._meter_lock:\n            if not self._meters.get(info):\n                self._meters[info] = Meter(\n                    info,\n                    self._measurement_consumer,\n                )\n            return self._meters[info]\n", "path": "opentelemetry-sdk/src/opentelemetry/sdk/_metrics/__init__.py"}]}