prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Implement InMemoryMetricExporter
  See [spec](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk_exporters/in-memory.md). This will be great for testing.
  
  IMO this should be a "pull exporter" (metric reader atm) that has a method `get_metrics()` or similar to return metrics from the SDK.
  
  --- 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/export/__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 import logging
  16 import os
  17 from abc import ABC, abstractmethod
  18 from enum import Enum
  19 from os import environ, linesep
  20 from sys import stdout
  21 from threading import Event, Thread
  22 from typing import IO, Callable, Iterable, Optional, Sequence
  23 
  24 from opentelemetry.context import (
  25     _SUPPRESS_INSTRUMENTATION_KEY,
  26     attach,
  27     detach,
  28     set_value,
  29 )
  30 from opentelemetry.sdk._metrics.metric_reader import MetricReader
  31 from opentelemetry.sdk._metrics.point import AggregationTemporality, Metric
  32 from opentelemetry.util._once import Once
  33 
  34 _logger = logging.getLogger(__name__)
  35 
  36 
  37 class MetricExportResult(Enum):
  38     SUCCESS = 0
  39     FAILURE = 1
  40 
  41 
  42 class MetricExporter(ABC):
  43     """Interface for exporting metrics.
  44 
  45     Interface to be implemented by services that want to export metrics received
  46     in their own format.
  47     """
  48 
  49     @property
  50     def preferred_temporality(self) -> AggregationTemporality:
  51         return AggregationTemporality.CUMULATIVE
  52 
  53     @abstractmethod
  54     def export(self, metrics: Sequence[Metric]) -> "MetricExportResult":
  55         """Exports a batch of telemetry data.
  56 
  57         Args:
  58             metrics: The list of `opentelemetry.sdk._metrics.data.MetricData` objects to be exported
  59 
  60         Returns:
  61             The result of the export
  62         """
  63 
  64     @abstractmethod
  65     def shutdown(self) -> None:
  66         """Shuts down the exporter.
  67 
  68         Called when the SDK is shut down.
  69         """
  70 
  71 
  72 class ConsoleMetricExporter(MetricExporter):
  73     """Implementation of :class:`MetricExporter` that prints metrics to the
  74     console.
  75 
  76     This class can be used for diagnostic purposes. It prints the exported
  77     metrics to the console STDOUT.
  78     """
  79 
  80     def __init__(
  81         self,
  82         out: IO = stdout,
  83         formatter: Callable[[Metric], str] = lambda metric: metric.to_json()
  84         + linesep,
  85     ):
  86         self.out = out
  87         self.formatter = formatter
  88 
  89     def export(self, metrics: Sequence[Metric]) -> MetricExportResult:
  90         for metric in metrics:
  91             self.out.write(self.formatter(metric))
  92         self.out.flush()
  93         return MetricExportResult.SUCCESS
  94 
  95     def shutdown(self) -> None:
  96         pass
  97 
  98 
  99 class PeriodicExportingMetricReader(MetricReader):
  100     """`PeriodicExportingMetricReader` is an implementation of `MetricReader`
  101     that collects metrics based on a user-configurable time interval, and passes the
  102     metrics to the configured exporter.
  103     """
  104 
  105     def __init__(
  106         self,
  107         exporter: MetricExporter,
  108         export_interval_millis: Optional[float] = None,
  109         export_timeout_millis: Optional[float] = None,
  110     ) -> None:
  111         super().__init__(preferred_temporality=exporter.preferred_temporality)
  112         self._exporter = exporter
  113         if export_interval_millis is None:
  114             try:
  115                 export_interval_millis = float(
  116                     environ.get("OTEL_METRIC_EXPORT_INTERVAL", 60000)
  117                 )
  118             except ValueError:
  119                 _logger.warning(
  120                     "Found invalid value for export interval, using default"
  121                 )
  122                 export_interval_millis = 60000
  123         if export_timeout_millis is None:
  124             try:
  125                 export_timeout_millis = float(
  126                     environ.get("OTEL_METRIC_EXPORT_TIMEOUT", 30000)
  127                 )
  128             except ValueError:
  129                 _logger.warning(
  130                     "Found invalid value for export timeout, using default"
  131                 )
  132                 export_timeout_millis = 30000
  133         self._export_interval_millis = export_interval_millis
  134         self._export_timeout_millis = export_timeout_millis
  135         self._shutdown = False
  136         self._shutdown_event = Event()
  137         self._shutdown_once = Once()
  138         self._daemon_thread = Thread(target=self._ticker, daemon=True)
  139         self._daemon_thread.start()
  140         if hasattr(os, "register_at_fork"):
  141             os.register_at_fork(
  142                 after_in_child=self._at_fork_reinit
  143             )  # pylint: disable=protected-access
  144 
  145     def _at_fork_reinit(self):
  146         self._daemon_thread = Thread(target=self._ticker, daemon=True)
  147         self._daemon_thread.start()
  148 
  149     def _ticker(self) -> None:
  150         interval_secs = self._export_interval_millis / 1e3
  151         while not self._shutdown_event.wait(interval_secs):
  152             self.collect()
  153         # one last collection below before shutting down completely
  154         self.collect()
  155 
  156     def _receive_metrics(self, metrics: Iterable[Metric]) -> None:
  157         if metrics is None:
  158             return
  159         token = attach(set_value(_SUPPRESS_INSTRUMENTATION_KEY, True))
  160         try:
  161             self._exporter.export(metrics)
  162         except Exception as e:  # pylint: disable=broad-except,invalid-name
  163             _logger.exception("Exception while exporting metrics %s", str(e))
  164         detach(token)
  165 
  166     def shutdown(self) -> bool:
  167         def _shutdown():
  168             self._shutdown = True
  169 
  170         did_set = self._shutdown_once.do_once(_shutdown)
  171         if not did_set:
  172             _logger.warning("Can't shutdown multiple times")
  173             return False
  174 
  175         self._shutdown_event.set()
  176         self._daemon_thread.join()
  177         self._exporter.shutdown()
  178         return True
  179
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/export/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/export/__init__.py
  --- a/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/export/__init__.py
  +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/export/__init__.py
  @@ -18,8 +18,8 @@
   from enum import Enum
   from os import environ, linesep
   from sys import stdout
  -from threading import Event, Thread
  -from typing import IO, Callable, Iterable, Optional, Sequence
  +from threading import Event, RLock, Thread
  +from typing import IO, Callable, Iterable, List, Optional, Sequence
   
   from opentelemetry.context import (
       _SUPPRESS_INSTRUMENTATION_KEY,
  @@ -96,6 +96,36 @@
           pass
   
   
  +class InMemoryMetricReader(MetricReader):
  +    """Implementation of :class:`MetricReader` that returns its metrics from :func:`metrics`.
  +
  +    This is useful for e.g. unit tests.
  +    """
  +
  +    def __init__(
  +        self,
  +        preferred_temporality: AggregationTemporality = AggregationTemporality.CUMULATIVE,
  +    ) -> None:
  +        super().__init__(preferred_temporality=preferred_temporality)
  +        self._lock = RLock()
  +        self._metrics: List[Metric] = []
  +
  +    def get_metrics(self) -> List[Metric]:
  +        """Reads and returns current metrics from the SDK"""
  +        with self._lock:
  +            self.collect()
  +            metrics = self._metrics
  +            self._metrics = []
  +        return metrics
  +
  +    def _receive_metrics(self, metrics: Iterable[Metric]):
  +        with self._lock:
  +            self._metrics = list(metrics)
  +
  +    def shutdown(self) -> bool:
  +        return True
  +
  +
   class PeriodicExportingMetricReader(MetricReader):
       """`PeriodicExportingMetricReader` is an implementation of `MetricReader`
       that collects metrics based on a user-configurable time interval, and passes the
  
verification_info: {"golden_diff": "diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/export/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/export/__init__.py\n--- a/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/export/__init__.py\n+++ b/opentelemetry-sdk/src/opentelemetry/sdk/_metrics/export/__init__.py\n@@ -18,8 +18,8 @@\n from enum import Enum\n from os import environ, linesep\n from sys import stdout\n-from threading import Event, Thread\n-from typing import IO, Callable, Iterable, Optional, Sequence\n+from threading import Event, RLock, Thread\n+from typing import IO, Callable, Iterable, List, Optional, Sequence\n \n from opentelemetry.context import (\n     _SUPPRESS_INSTRUMENTATION_KEY,\n@@ -96,6 +96,36 @@\n         pass\n \n \n+class InMemoryMetricReader(MetricReader):\n+    \"\"\"Implementation of :class:`MetricReader` that returns its metrics from :func:`metrics`.\n+\n+    This is useful for e.g. unit tests.\n+    \"\"\"\n+\n+    def __init__(\n+        self,\n+        preferred_temporality: AggregationTemporality = AggregationTemporality.CUMULATIVE,\n+    ) -> None:\n+        super().__init__(preferred_temporality=preferred_temporality)\n+        self._lock = RLock()\n+        self._metrics: List[Metric] = []\n+\n+    def get_metrics(self) -> List[Metric]:\n+        \"\"\"Reads and returns current metrics from the SDK\"\"\"\n+        with self._lock:\n+            self.collect()\n+            metrics = self._metrics\n+            self._metrics = []\n+        return metrics\n+\n+    def _receive_metrics(self, metrics: Iterable[Metric]):\n+        with self._lock:\n+            self._metrics = list(metrics)\n+\n+    def shutdown(self) -> bool:\n+        return True\n+\n+\n class PeriodicExportingMetricReader(MetricReader):\n     \"\"\"`PeriodicExportingMetricReader` is an implementation of `MetricReader`\n     that collects metrics based on a user-configurable time interval, and passes the\n", "issue": "Implement InMemoryMetricExporter\nSee [spec](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk_exporters/in-memory.md). This will be great for testing.\r\n\r\nIMO this should be a \"pull exporter\" (metric reader atm) that has a method `get_metrics()` or similar to return metrics from the SDK.\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\nimport logging\nimport os\nfrom abc import ABC, abstractmethod\nfrom enum import Enum\nfrom os import environ, linesep\nfrom sys import stdout\nfrom threading import Event, Thread\nfrom typing import IO, Callable, Iterable, Optional, Sequence\n\nfrom opentelemetry.context import (\n    _SUPPRESS_INSTRUMENTATION_KEY,\n    attach,\n    detach,\n    set_value,\n)\nfrom opentelemetry.sdk._metrics.metric_reader import MetricReader\nfrom opentelemetry.sdk._metrics.point import AggregationTemporality, Metric\nfrom opentelemetry.util._once import Once\n\n_logger = logging.getLogger(__name__)\n\n\nclass MetricExportResult(Enum):\n    SUCCESS = 0\n    FAILURE = 1\n\n\nclass MetricExporter(ABC):\n    \"\"\"Interface for exporting metrics.\n\n    Interface to be implemented by services that want to export metrics received\n    in their own format.\n    \"\"\"\n\n    @property\n    def preferred_temporality(self) -> AggregationTemporality:\n        return AggregationTemporality.CUMULATIVE\n\n    @abstractmethod\n    def export(self, metrics: Sequence[Metric]) -> \"MetricExportResult\":\n        \"\"\"Exports a batch of telemetry data.\n\n        Args:\n            metrics: The list of `opentelemetry.sdk._metrics.data.MetricData` objects to be exported\n\n        Returns:\n            The result of the export\n        \"\"\"\n\n    @abstractmethod\n    def shutdown(self) -> None:\n        \"\"\"Shuts down the exporter.\n\n        Called when the SDK is shut down.\n        \"\"\"\n\n\nclass ConsoleMetricExporter(MetricExporter):\n    \"\"\"Implementation of :class:`MetricExporter` that prints metrics to the\n    console.\n\n    This class can be used for diagnostic purposes. It prints the exported\n    metrics to the console STDOUT.\n    \"\"\"\n\n    def __init__(\n        self,\n        out: IO = stdout,\n        formatter: Callable[[Metric], str] = lambda metric: metric.to_json()\n        + linesep,\n    ):\n        self.out = out\n        self.formatter = formatter\n\n    def export(self, metrics: Sequence[Metric]) -> MetricExportResult:\n        for metric in metrics:\n            self.out.write(self.formatter(metric))\n        self.out.flush()\n        return MetricExportResult.SUCCESS\n\n    def shutdown(self) -> None:\n        pass\n\n\nclass PeriodicExportingMetricReader(MetricReader):\n    \"\"\"`PeriodicExportingMetricReader` is an implementation of `MetricReader`\n    that collects metrics based on a user-configurable time interval, and passes the\n    metrics to the configured exporter.\n    \"\"\"\n\n    def __init__(\n        self,\n        exporter: MetricExporter,\n        export_interval_millis: Optional[float] = None,\n        export_timeout_millis: Optional[float] = None,\n    ) -> None:\n        super().__init__(preferred_temporality=exporter.preferred_temporality)\n        self._exporter = exporter\n        if export_interval_millis is None:\n            try:\n                export_interval_millis = float(\n                    environ.get(\"OTEL_METRIC_EXPORT_INTERVAL\", 60000)\n                )\n            except ValueError:\n                _logger.warning(\n                    \"Found invalid value for export interval, using default\"\n                )\n                export_interval_millis = 60000\n        if export_timeout_millis is None:\n            try:\n                export_timeout_millis = float(\n                    environ.get(\"OTEL_METRIC_EXPORT_TIMEOUT\", 30000)\n                )\n            except ValueError:\n                _logger.warning(\n                    \"Found invalid value for export timeout, using default\"\n                )\n                export_timeout_millis = 30000\n        self._export_interval_millis = export_interval_millis\n        self._export_timeout_millis = export_timeout_millis\n        self._shutdown = False\n        self._shutdown_event = Event()\n        self._shutdown_once = Once()\n        self._daemon_thread = Thread(target=self._ticker, daemon=True)\n        self._daemon_thread.start()\n        if hasattr(os, \"register_at_fork\"):\n            os.register_at_fork(\n                after_in_child=self._at_fork_reinit\n            )  # pylint: disable=protected-access\n\n    def _at_fork_reinit(self):\n        self._daemon_thread = Thread(target=self._ticker, daemon=True)\n        self._daemon_thread.start()\n\n    def _ticker(self) -> None:\n        interval_secs = self._export_interval_millis / 1e3\n        while not self._shutdown_event.wait(interval_secs):\n            self.collect()\n        # one last collection below before shutting down completely\n        self.collect()\n\n    def _receive_metrics(self, metrics: Iterable[Metric]) -> None:\n        if metrics is None:\n            return\n        token = attach(set_value(_SUPPRESS_INSTRUMENTATION_KEY, True))\n        try:\n            self._exporter.export(metrics)\n        except Exception as e:  # pylint: disable=broad-except,invalid-name\n            _logger.exception(\"Exception while exporting metrics %s\", str(e))\n        detach(token)\n\n    def shutdown(self) -> bool:\n        def _shutdown():\n            self._shutdown = True\n\n        did_set = self._shutdown_once.do_once(_shutdown)\n        if not did_set:\n            _logger.warning(\"Can't shutdown multiple times\")\n            return False\n\n        self._shutdown_event.set()\n        self._daemon_thread.join()\n        self._exporter.shutdown()\n        return True\n", "path": "opentelemetry-sdk/src/opentelemetry/sdk/_metrics/export/__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\nimport logging\nimport os\nfrom abc import ABC, abstractmethod\nfrom enum import Enum\nfrom os import environ, linesep\nfrom sys import stdout\nfrom threading import Event, RLock, Thread\nfrom typing import IO, Callable, Iterable, List, Optional, Sequence\n\nfrom opentelemetry.context import (\n    _SUPPRESS_INSTRUMENTATION_KEY,\n    attach,\n    detach,\n    set_value,\n)\nfrom opentelemetry.sdk._metrics.metric_reader import MetricReader\nfrom opentelemetry.sdk._metrics.point import AggregationTemporality, Metric\nfrom opentelemetry.util._once import Once\n\n_logger = logging.getLogger(__name__)\n\n\nclass MetricExportResult(Enum):\n    SUCCESS = 0\n    FAILURE = 1\n\n\nclass MetricExporter(ABC):\n    \"\"\"Interface for exporting metrics.\n\n    Interface to be implemented by services that want to export metrics received\n    in their own format.\n    \"\"\"\n\n    @property\n    def preferred_temporality(self) -> AggregationTemporality:\n        return AggregationTemporality.CUMULATIVE\n\n    @abstractmethod\n    def export(self, metrics: Sequence[Metric]) -> \"MetricExportResult\":\n        \"\"\"Exports a batch of telemetry data.\n\n        Args:\n            metrics: The list of `opentelemetry.sdk._metrics.data.MetricData` objects to be exported\n\n        Returns:\n            The result of the export\n        \"\"\"\n\n    @abstractmethod\n    def shutdown(self) -> None:\n        \"\"\"Shuts down the exporter.\n\n        Called when the SDK is shut down.\n        \"\"\"\n\n\nclass ConsoleMetricExporter(MetricExporter):\n    \"\"\"Implementation of :class:`MetricExporter` that prints metrics to the\n    console.\n\n    This class can be used for diagnostic purposes. It prints the exported\n    metrics to the console STDOUT.\n    \"\"\"\n\n    def __init__(\n        self,\n        out: IO = stdout,\n        formatter: Callable[[Metric], str] = lambda metric: metric.to_json()\n        + linesep,\n    ):\n        self.out = out\n        self.formatter = formatter\n\n    def export(self, metrics: Sequence[Metric]) -> MetricExportResult:\n        for metric in metrics:\n            self.out.write(self.formatter(metric))\n        self.out.flush()\n        return MetricExportResult.SUCCESS\n\n    def shutdown(self) -> None:\n        pass\n\n\nclass InMemoryMetricReader(MetricReader):\n    \"\"\"Implementation of :class:`MetricReader` that returns its metrics from :func:`metrics`.\n\n    This is useful for e.g. unit tests.\n    \"\"\"\n\n    def __init__(\n        self,\n        preferred_temporality: AggregationTemporality = AggregationTemporality.CUMULATIVE,\n    ) -> None:\n        super().__init__(preferred_temporality=preferred_temporality)\n        self._lock = RLock()\n        self._metrics: List[Metric] = []\n\n    def get_metrics(self) -> List[Metric]:\n        \"\"\"Reads and returns current metrics from the SDK\"\"\"\n        with self._lock:\n            self.collect()\n            metrics = self._metrics\n            self._metrics = []\n        return metrics\n\n    def _receive_metrics(self, metrics: Iterable[Metric]):\n        with self._lock:\n            self._metrics = list(metrics)\n\n    def shutdown(self) -> bool:\n        return True\n\n\nclass PeriodicExportingMetricReader(MetricReader):\n    \"\"\"`PeriodicExportingMetricReader` is an implementation of `MetricReader`\n    that collects metrics based on a user-configurable time interval, and passes the\n    metrics to the configured exporter.\n    \"\"\"\n\n    def __init__(\n        self,\n        exporter: MetricExporter,\n        export_interval_millis: Optional[float] = None,\n        export_timeout_millis: Optional[float] = None,\n    ) -> None:\n        super().__init__(preferred_temporality=exporter.preferred_temporality)\n        self._exporter = exporter\n        if export_interval_millis is None:\n            try:\n                export_interval_millis = float(\n                    environ.get(\"OTEL_METRIC_EXPORT_INTERVAL\", 60000)\n                )\n            except ValueError:\n                _logger.warning(\n                    \"Found invalid value for export interval, using default\"\n                )\n                export_interval_millis = 60000\n        if export_timeout_millis is None:\n            try:\n                export_timeout_millis = float(\n                    environ.get(\"OTEL_METRIC_EXPORT_TIMEOUT\", 30000)\n                )\n            except ValueError:\n                _logger.warning(\n                    \"Found invalid value for export timeout, using default\"\n                )\n                export_timeout_millis = 30000\n        self._export_interval_millis = export_interval_millis\n        self._export_timeout_millis = export_timeout_millis\n        self._shutdown = False\n        self._shutdown_event = Event()\n        self._shutdown_once = Once()\n        self._daemon_thread = Thread(target=self._ticker, daemon=True)\n        self._daemon_thread.start()\n        if hasattr(os, \"register_at_fork\"):\n            os.register_at_fork(\n                after_in_child=self._at_fork_reinit\n            )  # pylint: disable=protected-access\n\n    def _at_fork_reinit(self):\n        self._daemon_thread = Thread(target=self._ticker, daemon=True)\n        self._daemon_thread.start()\n\n    def _ticker(self) -> None:\n        interval_secs = self._export_interval_millis / 1e3\n        while not self._shutdown_event.wait(interval_secs):\n            self.collect()\n        # one last collection below before shutting down completely\n        self.collect()\n\n    def _receive_metrics(self, metrics: Iterable[Metric]) -> None:\n        if metrics is None:\n            return\n        token = attach(set_value(_SUPPRESS_INSTRUMENTATION_KEY, True))\n        try:\n            self._exporter.export(metrics)\n        except Exception as e:  # pylint: disable=broad-except,invalid-name\n            _logger.exception(\"Exception while exporting metrics %s\", str(e))\n        detach(token)\n\n    def shutdown(self) -> bool:\n        def _shutdown():\n            self._shutdown = True\n\n        did_set = self._shutdown_once.do_once(_shutdown)\n        if not did_set:\n            _logger.warning(\"Can't shutdown multiple times\")\n            return False\n\n        self._shutdown_event.set()\n        self._daemon_thread.join()\n        self._exporter.shutdown()\n        return True\n", "path": "opentelemetry-sdk/src/opentelemetry/sdk/_metrics/export/__init__.py"}]}