Skip to content

Commit 408d1a3

Browse files
authored
Merge branch 'main' into logname_change
2 parents fab20c9 + b56379b commit 408d1a3

File tree

16 files changed

+1910
-1643
lines changed

16 files changed

+1910
-1643
lines changed

.github/workflows/ci.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ jobs:
1313
strategy:
1414
matrix:
1515
py:
16-
- { version: "3.8", tox: "38" }
1716
- { version: "3.9", tox: "39" }
1817
- { version: "3.10", tox: "310" }
1918
- { version: "3.11", tox: "311" }

docs/contributing.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,17 +55,17 @@ tox -e dev
5555

5656
### Running tests
5757

58-
This project supports python versions 3.5 to 3.9. To run tests, use `tox`:
58+
This project supports python versions 3.9 to 3.13. To run tests, use `tox`:
5959

6060
```sh
6161
# List all tox environments
6262
tox -l
6363

64-
# Run python3.8 exporter tests
65-
tox -e py38-ci-test-exporter
64+
# Run python3.12 exporter tests
65+
tox -e py312-ci-test-exporter
6666

67-
# Run all python3.8 tests in parallel
68-
tox -f py38-test -pauto
67+
# Run all python3.12 tests in parallel
68+
tox -f py312-test -pauto
6969

7070
# All checks that run in continuous integration use the "ci" factor, which
7171
# makes it easy to test without submitting a PR. To run all of them in

opentelemetry-exporter-gcp-logging/setup.cfg

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,13 @@ classifiers =
1414
License :: OSI Approved :: Apache Software License
1515
Programming Language :: Python
1616
Programming Language :: Python :: 3
17-
Programming Language :: Python :: 3.8
1817
Programming Language :: Python :: 3.9
1918
Programming Language :: Python :: 3.10
2019
Programming Language :: Python :: 3.11
2120
Programming Language :: Python :: 3.12
2221

2322
[options]
24-
python_requires = >=3.8
23+
python_requires = >=3.9
2524
package_dir=
2625
=src
2726
packages=find_namespace:

opentelemetry-exporter-gcp-monitoring/setup.cfg

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,14 @@ classifiers =
1414
License :: OSI Approved :: Apache Software License
1515
Programming Language :: Python
1616
Programming Language :: Python :: 3
17-
Programming Language :: Python :: 3.8
1817
Programming Language :: Python :: 3.9
1918
Programming Language :: Python :: 3.10
2019
Programming Language :: Python :: 3.11
2120
Programming Language :: Python :: 3.12
2221
Programming Language :: Python :: 3.13
2322

2423
[options]
25-
python_requires = >=3.8
24+
python_requires = >=3.9
2625
package_dir=
2726
=src
2827
packages=find_namespace:

opentelemetry-exporter-gcp-monitoring/src/opentelemetry/exporter/cloud_monitoring/__init__.py

Lines changed: 56 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# limitations under the License.
1414

1515
import logging
16+
import math
1617
import random
1718
from dataclasses import replace
1819
from time import time_ns
@@ -212,11 +213,7 @@ def _get_metric_descriptor(
212213
elif isinstance(data, Histogram):
213214
descriptor.metric_kind = MetricDescriptor.MetricKind.CUMULATIVE
214215
elif isinstance(data, ExponentialHistogram):
215-
logger.warning(
216-
"Unsupported metric data type %s, ignoring it",
217-
type(data).__name__,
218-
)
219-
return None
216+
descriptor.metric_kind = MetricDescriptor.MetricKind.CUMULATIVE
220217
else:
221218
# Exhaustive check
222219
_: NoReturn = data
@@ -235,6 +232,8 @@ def _get_metric_descriptor(
235232
)
236233
elif isinstance(first_point, HistogramDataPoint):
237234
descriptor.value_type = MetricDescriptor.ValueType.DISTRIBUTION
235+
elif isinstance(first_point, ExponentialHistogramDataPoint):
236+
descriptor.value_type = MetricDescriptor.ValueType.DISTRIBUTION
238237
elif first_point is None:
239238
pass
240239
else:
@@ -265,7 +264,9 @@ def _get_metric_descriptor(
265264
@staticmethod
266265
def _to_point(
267266
kind: "MetricDescriptor.MetricKind.V",
268-
data_point: Union[NumberDataPoint, HistogramDataPoint],
267+
data_point: Union[
268+
NumberDataPoint, HistogramDataPoint, ExponentialHistogramDataPoint
269+
],
269270
) -> Point:
270271
if isinstance(data_point, HistogramDataPoint):
271272
mean = (
@@ -283,6 +284,55 @@ def _to_point(
283284
),
284285
)
285286
)
287+
elif isinstance(data_point, ExponentialHistogramDataPoint):
288+
# Adapted from https://github.com/GoogleCloudPlatform/opentelemetry-operations-go/blob/v1.8.0/exporter/collector/metrics.go#L582
289+
290+
# Calculate underflow bucket (zero count + negative buckets)
291+
underflow = data_point.zero_count
292+
if data_point.negative.bucket_counts:
293+
underflow += sum(data_point.negative.bucket_counts)
294+
295+
# Create bucket counts array: [underflow, positive_buckets..., overflow=0]
296+
bucket_counts = [underflow]
297+
if data_point.positive.bucket_counts:
298+
bucket_counts.extend(data_point.positive.bucket_counts)
299+
bucket_counts.append(0) # overflow bucket is always empty
300+
301+
# Determine bucket options
302+
if not data_point.positive.bucket_counts:
303+
# If no positive buckets, use explicit buckets with bounds=[0]
304+
bucket_options = Distribution.BucketOptions(
305+
explicit_buckets=Distribution.BucketOptions.Explicit(
306+
bounds=[0.0],
307+
)
308+
)
309+
else:
310+
# Use exponential bucket options
311+
# growth_factor = 2^(2^(-scale))
312+
growth_factor = math.pow(2, math.pow(2, -data_point.scale))
313+
# scale = growth_factor^(positive_bucket_offset)
314+
scale = math.pow(growth_factor, data_point.positive.offset)
315+
num_finite_buckets = len(bucket_counts) - 2
316+
317+
bucket_options = Distribution.BucketOptions(
318+
exponential_buckets=Distribution.BucketOptions.Exponential(
319+
num_finite_buckets=num_finite_buckets,
320+
growth_factor=growth_factor,
321+
scale=scale,
322+
)
323+
)
324+
325+
mean = (
326+
data_point.sum / data_point.count if data_point.count else 0.0
327+
)
328+
point_value = TypedValue(
329+
distribution_value=Distribution(
330+
count=data_point.count,
331+
mean=mean,
332+
bucket_counts=bucket_counts,
333+
bucket_options=bucket_options,
334+
)
335+
)
286336
else:
287337
if isinstance(data_point.value, int):
288338
point_value = TypedValue(int64_value=data_point.value)
@@ -350,10 +400,6 @@ def export(
350400
continue
351401

352402
for data_point in metric.data.data_points:
353-
if isinstance(
354-
data_point, ExponentialHistogramDataPoint
355-
):
356-
continue
357403
labels = {
358404
_normalize_label_key(key): str(value)
359405
for key, value in (

0 commit comments

Comments
 (0)