We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
OTLP Exporter: Add support for Histogram point types


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/_metric_exporter/__init__.py`
Content:
```
1 # Copyright The OpenTelemetry Authors
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at
5 #
6 #     http://www.apache.org/licenses/LICENSE-2.0
7 #
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
13 
14 import logging
15 from os import environ
16 from typing import Optional, Sequence
17 from grpc import ChannelCredentials, Compression
18 from opentelemetry.exporter.otlp.proto.grpc.exporter import (
19     OTLPExporterMixin,
20     get_resource_data,
21 )
22 from opentelemetry.proto.collector.metrics.v1.metrics_service_pb2 import (
23     ExportMetricsServiceRequest,
24 )
25 from opentelemetry.proto.collector.metrics.v1.metrics_service_pb2_grpc import (
26     MetricsServiceStub,
27 )
28 from opentelemetry.proto.common.v1.common_pb2 import InstrumentationLibrary
29 from opentelemetry.proto.metrics.v1 import metrics_pb2 as pb2
30 from opentelemetry.sdk.environment_variables import (
31     OTEL_EXPORTER_OTLP_METRICS_INSECURE,
32 )
33 from opentelemetry.sdk._metrics.point import (
34     Gauge,
35     Histogram,
36     Metric,
37     Sum,
38 )
39 
40 from opentelemetry.sdk._metrics.export import (
41     MetricExporter,
42     MetricExportResult,
43 )
44 
45 logger = logging.getLogger(__name__)
46 
47 
48 class OTLPMetricExporter(
49     MetricExporter,
50     OTLPExporterMixin[Metric, ExportMetricsServiceRequest, MetricExportResult],
51 ):
52     _result = MetricExportResult
53     _stub = MetricsServiceStub
54 
55     def __init__(
56         self,
57         endpoint: Optional[str] = None,
58         insecure: Optional[bool] = None,
59         credentials: Optional[ChannelCredentials] = None,
60         headers: Optional[Sequence] = None,
61         timeout: Optional[int] = None,
62         compression: Optional[Compression] = None,
63     ):
64 
65         if insecure is None:
66             insecure = environ.get(OTEL_EXPORTER_OTLP_METRICS_INSECURE)
67             if insecure is not None:
68                 insecure = insecure.lower() == "true"
69 
70         super().__init__(
71             **{
72                 "endpoint": endpoint,
73                 "insecure": insecure,
74                 "credentials": credentials,
75                 "headers": headers,
76                 "timeout": timeout,
77                 "compression": compression,
78             }
79         )
80 
81     def _translate_data(
82         self, data: Sequence[Metric]
83     ) -> ExportMetricsServiceRequest:
84         sdk_resource_instrumentation_library_metrics = {}
85 
86         for metric in data:
87             resource = metric.resource
88             instrumentation_library_map = (
89                 sdk_resource_instrumentation_library_metrics.get(resource, {})
90             )
91             if not instrumentation_library_map:
92                 sdk_resource_instrumentation_library_metrics[
93                     resource
94                 ] = instrumentation_library_map
95 
96             instrumentation_library_metrics = instrumentation_library_map.get(
97                 metric.instrumentation_info
98             )
99 
100             if not instrumentation_library_metrics:
101                 if metric.instrumentation_info is not None:
102                     instrumentation_library_map[
103                         metric.instrumentation_info
104                     ] = pb2.InstrumentationLibraryMetrics(
105                         instrumentation_library=InstrumentationLibrary(
106                             name=metric.instrumentation_info.name,
107                             version=metric.instrumentation_info.version,
108                         )
109                     )
110                 else:
111                     instrumentation_library_map[
112                         metric.instrumentation_info
113                     ] = pb2.InstrumentationLibraryMetrics()
114 
115             instrumentation_library_metrics = instrumentation_library_map.get(
116                 metric.instrumentation_info
117             )
118 
119             pbmetric = pb2.Metric(
120                 name=metric.name,
121                 description=metric.description,
122                 unit=metric.unit,
123             )
124             if isinstance(metric.point, Gauge):
125                 pt = pb2.NumberDataPoint(
126                     attributes=self._translate_attributes(metric.attributes),
127                     time_unix_nano=metric.point.time_unix_nano,
128                 )
129                 if isinstance(metric.point.value, int):
130                     pt.as_int = metric.point.value
131                 else:
132                     pt.as_double = metric.point.value
133                 pbmetric.gauge.data_points.append(pt)
134             elif isinstance(metric.point, Histogram):
135                 # TODO: implement histogram
136                 pbmetric.histogram = pb2.Histogram(
137                     data_points=[],
138                 )
139             elif isinstance(metric.point, Sum):
140                 pt = pb2.NumberDataPoint(
141                     attributes=self._translate_attributes(metric.attributes),
142                     start_time_unix_nano=metric.point.start_time_unix_nano,
143                     time_unix_nano=metric.point.time_unix_nano,
144                 )
145                 if isinstance(metric.point.value, int):
146                     pt.as_int = metric.point.value
147                 else:
148                     pt.as_double = metric.point.value
149                 # note that because sum is a message type, the fields must be
150                 # set individually rather than instantiating a pb2.Sum and setting
151                 # it once
152                 pbmetric.sum.aggregation_temporality = (
153                     metric.point.aggregation_temporality
154                 )
155                 pbmetric.sum.is_monotonic = metric.point.is_monotonic
156                 pbmetric.sum.data_points.append(pt)
157             else:
158                 logger.warn("unsupported datapoint type %s", metric.point)
159                 continue
160 
161             instrumentation_library_metrics.metrics.append(
162                 pbmetric,
163             )
164         return ExportMetricsServiceRequest(
165             resource_metrics=get_resource_data(
166                 sdk_resource_instrumentation_library_metrics,
167                 pb2.ResourceMetrics,
168                 "metrics",
169             )
170         )
171 
172     def export(self, metrics: Sequence[Metric]) -> MetricExportResult:
173         return self._export(metrics)
174 
175     def shutdown(self):
176         pass
177
```
--- 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/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/_metric_exporter/__init__.py b/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/_metric_exporter/__init__.py
--- a/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/_metric_exporter/__init__.py
+++ b/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/_metric_exporter/__init__.py
@@ -132,10 +132,18 @@
                     pt.as_double = metric.point.value
                 pbmetric.gauge.data_points.append(pt)
             elif isinstance(metric.point, Histogram):
-                # TODO: implement histogram
-                pbmetric.histogram = pb2.Histogram(
-                    data_points=[],
+                pt = pb2.HistogramDataPoint(
+                    attributes=self._translate_attributes(metric.attributes),
+                    time_unix_nano=metric.point.time_unix_nano,
+                    start_time_unix_nano=metric.point.start_time_unix_nano,
+                    count=sum(metric.point.bucket_counts),
+                    bucket_counts=metric.point.bucket_counts,
+                    explicit_bounds=metric.point.explicit_bounds,
+                )
+                pbmetric.histogram.aggregation_temporality = (
+                    metric.point.aggregation_temporality
                 )
+                pbmetric.histogram.data_points.append(pt)
             elif isinstance(metric.point, Sum):
                 pt = pb2.NumberDataPoint(
                     attributes=self._translate_attributes(metric.attributes),

{"golden_diff": "diff --git a/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/_metric_exporter/__init__.py b/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/_metric_exporter/__init__.py\n--- a/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/_metric_exporter/__init__.py\n+++ b/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/_metric_exporter/__init__.py\n@@ -132,10 +132,18 @@\n                     pt.as_double = metric.point.value\n                 pbmetric.gauge.data_points.append(pt)\n             elif isinstance(metric.point, Histogram):\n-                # TODO: implement histogram\n-                pbmetric.histogram = pb2.Histogram(\n-                    data_points=[],\n+                pt = pb2.HistogramDataPoint(\n+                    attributes=self._translate_attributes(metric.attributes),\n+                    time_unix_nano=metric.point.time_unix_nano,\n+                    start_time_unix_nano=metric.point.start_time_unix_nano,\n+                    count=sum(metric.point.bucket_counts),\n+                    bucket_counts=metric.point.bucket_counts,\n+                    explicit_bounds=metric.point.explicit_bounds,\n+                )\n+                pbmetric.histogram.aggregation_temporality = (\n+                    metric.point.aggregation_temporality\n                 )\n+                pbmetric.histogram.data_points.append(pt)\n             elif isinstance(metric.point, Sum):\n                 pt = pb2.NumberDataPoint(\n                     attributes=self._translate_attributes(metric.attributes),\n", "issue": "OTLP Exporter: Add support for Histogram point types\n\n", "before_files": [{"content": "# Copyright The OpenTelemetry Authors\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\nfrom os import environ\nfrom typing import Optional, Sequence\nfrom grpc import ChannelCredentials, Compression\nfrom opentelemetry.exporter.otlp.proto.grpc.exporter import (\n    OTLPExporterMixin,\n    get_resource_data,\n)\nfrom opentelemetry.proto.collector.metrics.v1.metrics_service_pb2 import (\n    ExportMetricsServiceRequest,\n)\nfrom opentelemetry.proto.collector.metrics.v1.metrics_service_pb2_grpc import (\n    MetricsServiceStub,\n)\nfrom opentelemetry.proto.common.v1.common_pb2 import InstrumentationLibrary\nfrom opentelemetry.proto.metrics.v1 import metrics_pb2 as pb2\nfrom opentelemetry.sdk.environment_variables import (\n    OTEL_EXPORTER_OTLP_METRICS_INSECURE,\n)\nfrom opentelemetry.sdk._metrics.point import (\n    Gauge,\n    Histogram,\n    Metric,\n    Sum,\n)\n\nfrom opentelemetry.sdk._metrics.export import (\n    MetricExporter,\n    MetricExportResult,\n)\n\nlogger = logging.getLogger(__name__)\n\n\nclass OTLPMetricExporter(\n    MetricExporter,\n    OTLPExporterMixin[Metric, ExportMetricsServiceRequest, MetricExportResult],\n):\n    _result = MetricExportResult\n    _stub = MetricsServiceStub\n\n    def __init__(\n        self,\n        endpoint: Optional[str] = None,\n        insecure: Optional[bool] = None,\n        credentials: Optional[ChannelCredentials] = None,\n        headers: Optional[Sequence] = None,\n        timeout: Optional[int] = None,\n        compression: Optional[Compression] = None,\n    ):\n\n        if insecure is None:\n            insecure = environ.get(OTEL_EXPORTER_OTLP_METRICS_INSECURE)\n            if insecure is not None:\n                insecure = insecure.lower() == \"true\"\n\n        super().__init__(\n            **{\n                \"endpoint\": endpoint,\n                \"insecure\": insecure,\n                \"credentials\": credentials,\n                \"headers\": headers,\n                \"timeout\": timeout,\n                \"compression\": compression,\n            }\n        )\n\n    def _translate_data(\n        self, data: Sequence[Metric]\n    ) -> ExportMetricsServiceRequest:\n        sdk_resource_instrumentation_library_metrics = {}\n\n        for metric in data:\n            resource = metric.resource\n            instrumentation_library_map = (\n                sdk_resource_instrumentation_library_metrics.get(resource, {})\n            )\n            if not instrumentation_library_map:\n                sdk_resource_instrumentation_library_metrics[\n                    resource\n                ] = instrumentation_library_map\n\n            instrumentation_library_metrics = instrumentation_library_map.get(\n                metric.instrumentation_info\n            )\n\n            if not instrumentation_library_metrics:\n                if metric.instrumentation_info is not None:\n                    instrumentation_library_map[\n                        metric.instrumentation_info\n                    ] = pb2.InstrumentationLibraryMetrics(\n                        instrumentation_library=InstrumentationLibrary(\n                            name=metric.instrumentation_info.name,\n                            version=metric.instrumentation_info.version,\n                        )\n                    )\n                else:\n                    instrumentation_library_map[\n                        metric.instrumentation_info\n                    ] = pb2.InstrumentationLibraryMetrics()\n\n            instrumentation_library_metrics = instrumentation_library_map.get(\n                metric.instrumentation_info\n            )\n\n            pbmetric = pb2.Metric(\n                name=metric.name,\n                description=metric.description,\n                unit=metric.unit,\n            )\n            if isinstance(metric.point, Gauge):\n                pt = pb2.NumberDataPoint(\n                    attributes=self._translate_attributes(metric.attributes),\n                    time_unix_nano=metric.point.time_unix_nano,\n                )\n                if isinstance(metric.point.value, int):\n                    pt.as_int = metric.point.value\n                else:\n                    pt.as_double = metric.point.value\n                pbmetric.gauge.data_points.append(pt)\n            elif isinstance(metric.point, Histogram):\n                # TODO: implement histogram\n                pbmetric.histogram = pb2.Histogram(\n                    data_points=[],\n                )\n            elif isinstance(metric.point, Sum):\n                pt = pb2.NumberDataPoint(\n                    attributes=self._translate_attributes(metric.attributes),\n                    start_time_unix_nano=metric.point.start_time_unix_nano,\n                    time_unix_nano=metric.point.time_unix_nano,\n                )\n                if isinstance(metric.point.value, int):\n                    pt.as_int = metric.point.value\n                else:\n                    pt.as_double = metric.point.value\n                # note that because sum is a message type, the fields must be\n                # set individually rather than instantiating a pb2.Sum and setting\n                # it once\n                pbmetric.sum.aggregation_temporality = (\n                    metric.point.aggregation_temporality\n                )\n                pbmetric.sum.is_monotonic = metric.point.is_monotonic\n                pbmetric.sum.data_points.append(pt)\n            else:\n                logger.warn(\"unsupported datapoint type %s\", metric.point)\n                continue\n\n            instrumentation_library_metrics.metrics.append(\n                pbmetric,\n            )\n        return ExportMetricsServiceRequest(\n            resource_metrics=get_resource_data(\n                sdk_resource_instrumentation_library_metrics,\n                pb2.ResourceMetrics,\n                \"metrics\",\n            )\n        )\n\n    def export(self, metrics: Sequence[Metric]) -> MetricExportResult:\n        return self._export(metrics)\n\n    def shutdown(self):\n        pass\n", "path": "exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/_metric_exporter/__init__.py"}], "after_files": [{"content": "# Copyright The OpenTelemetry Authors\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\nfrom os import environ\nfrom typing import Optional, Sequence\nfrom grpc import ChannelCredentials, Compression\nfrom opentelemetry.exporter.otlp.proto.grpc.exporter import (\n    OTLPExporterMixin,\n    get_resource_data,\n)\nfrom opentelemetry.proto.collector.metrics.v1.metrics_service_pb2 import (\n    ExportMetricsServiceRequest,\n)\nfrom opentelemetry.proto.collector.metrics.v1.metrics_service_pb2_grpc import (\n    MetricsServiceStub,\n)\nfrom opentelemetry.proto.common.v1.common_pb2 import InstrumentationLibrary\nfrom opentelemetry.proto.metrics.v1 import metrics_pb2 as pb2\nfrom opentelemetry.sdk.environment_variables import (\n    OTEL_EXPORTER_OTLP_METRICS_INSECURE,\n)\nfrom opentelemetry.sdk._metrics.point import (\n    Gauge,\n    Histogram,\n    Metric,\n    Sum,\n)\n\nfrom opentelemetry.sdk._metrics.export import (\n    MetricExporter,\n    MetricExportResult,\n)\n\nlogger = logging.getLogger(__name__)\n\n\nclass OTLPMetricExporter(\n    MetricExporter,\n    OTLPExporterMixin[Metric, ExportMetricsServiceRequest, MetricExportResult],\n):\n    _result = MetricExportResult\n    _stub = MetricsServiceStub\n\n    def __init__(\n        self,\n        endpoint: Optional[str] = None,\n        insecure: Optional[bool] = None,\n        credentials: Optional[ChannelCredentials] = None,\n        headers: Optional[Sequence] = None,\n        timeout: Optional[int] = None,\n        compression: Optional[Compression] = None,\n    ):\n\n        if insecure is None:\n            insecure = environ.get(OTEL_EXPORTER_OTLP_METRICS_INSECURE)\n            if insecure is not None:\n                insecure = insecure.lower() == \"true\"\n\n        super().__init__(\n            **{\n                \"endpoint\": endpoint,\n                \"insecure\": insecure,\n                \"credentials\": credentials,\n                \"headers\": headers,\n                \"timeout\": timeout,\n                \"compression\": compression,\n            }\n        )\n\n    def _translate_data(\n        self, data: Sequence[Metric]\n    ) -> ExportMetricsServiceRequest:\n        sdk_resource_instrumentation_library_metrics = {}\n\n        for metric in data:\n            resource = metric.resource\n            instrumentation_library_map = (\n                sdk_resource_instrumentation_library_metrics.get(resource, {})\n            )\n            if not instrumentation_library_map:\n                sdk_resource_instrumentation_library_metrics[\n                    resource\n                ] = instrumentation_library_map\n\n            instrumentation_library_metrics = instrumentation_library_map.get(\n                metric.instrumentation_info\n            )\n\n            if not instrumentation_library_metrics:\n                if metric.instrumentation_info is not None:\n                    instrumentation_library_map[\n                        metric.instrumentation_info\n                    ] = pb2.InstrumentationLibraryMetrics(\n                        instrumentation_library=InstrumentationLibrary(\n                            name=metric.instrumentation_info.name,\n                            version=metric.instrumentation_info.version,\n                        )\n                    )\n                else:\n                    instrumentation_library_map[\n                        metric.instrumentation_info\n                    ] = pb2.InstrumentationLibraryMetrics()\n\n            instrumentation_library_metrics = instrumentation_library_map.get(\n                metric.instrumentation_info\n            )\n\n            pbmetric = pb2.Metric(\n                name=metric.name,\n                description=metric.description,\n                unit=metric.unit,\n            )\n            if isinstance(metric.point, Gauge):\n                pt = pb2.NumberDataPoint(\n                    attributes=self._translate_attributes(metric.attributes),\n                    time_unix_nano=metric.point.time_unix_nano,\n                )\n                if isinstance(metric.point.value, int):\n                    pt.as_int = metric.point.value\n                else:\n                    pt.as_double = metric.point.value\n                pbmetric.gauge.data_points.append(pt)\n            elif isinstance(metric.point, Histogram):\n                pt = pb2.HistogramDataPoint(\n                    attributes=self._translate_attributes(metric.attributes),\n                    time_unix_nano=metric.point.time_unix_nano,\n                    start_time_unix_nano=metric.point.start_time_unix_nano,\n                    count=sum(metric.point.bucket_counts),\n                    bucket_counts=metric.point.bucket_counts,\n                    explicit_bounds=metric.point.explicit_bounds,\n                )\n                pbmetric.histogram.aggregation_temporality = (\n                    metric.point.aggregation_temporality\n                )\n                pbmetric.histogram.data_points.append(pt)\n            elif isinstance(metric.point, Sum):\n                pt = pb2.NumberDataPoint(\n                    attributes=self._translate_attributes(metric.attributes),\n                    start_time_unix_nano=metric.point.start_time_unix_nano,\n                    time_unix_nano=metric.point.time_unix_nano,\n                )\n                if isinstance(metric.point.value, int):\n                    pt.as_int = metric.point.value\n                else:\n                    pt.as_double = metric.point.value\n                # note that because sum is a message type, the fields must be\n                # set individually rather than instantiating a pb2.Sum and setting\n                # it once\n                pbmetric.sum.aggregation_temporality = (\n                    metric.point.aggregation_temporality\n                )\n                pbmetric.sum.is_monotonic = metric.point.is_monotonic\n                pbmetric.sum.data_points.append(pt)\n            else:\n                logger.warn(\"unsupported datapoint type %s\", metric.point)\n                continue\n\n            instrumentation_library_metrics.metrics.append(\n                pbmetric,\n            )\n        return ExportMetricsServiceRequest(\n            resource_metrics=get_resource_data(\n                sdk_resource_instrumentation_library_metrics,\n                pb2.ResourceMetrics,\n                \"metrics\",\n            )\n        )\n\n    def export(self, metrics: Sequence[Metric]) -> MetricExportResult:\n        return self._export(metrics)\n\n    def shutdown(self):\n        pass\n", "path": "exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/_metric_exporter/__init__.py"}]}