Skip to content

Commit 54cb8a6

Browse files
Update Cloud Logging Exporter to handle bytes in dict body (#407)
* Add space to logging exporter README. Make minor update to releasing.md. * Fix byes in LogRecord bug * Run linter * fix pulint * Respond to comments * Update opentelemetry-exporter-gcp-logging/src/opentelemetry/exporter/cloud_logging/__init__.py Co-authored-by: Aaron Abbott <[email protected]> * Update opentelemetry-exporter-gcp-logging/src/opentelemetry/exporter/cloud_logging/__init__.py Co-authored-by: Aaron Abbott <[email protected]> * Address comments * Update constraints * Fix constraints * FIx lint issues in cloud monitoring exporter and add changelog entry * Bump api/sdk versions to 1.3 * Fix broken trace exporter test * Update constraints.txt * Update constraints again --------- Co-authored-by: Aaron Abbott <[email protected]>
1 parent 27c6609 commit 54cb8a6

File tree

16 files changed

+78
-16
lines changed

16 files changed

+78
-16
lines changed

dev-constraints.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,5 @@ setuptools==69.5.1
1717

1818
# pinned for snapshot tests. this should be bumped regularly and snapshots updated by running
1919
# tox -f py311-test -- --snapshot-update
20-
opentelemetry-api==1.20.0
21-
opentelemetry-sdk==1.20.0
20+
opentelemetry-api==1.30.0
21+
opentelemetry-sdk==1.30.0

e2e-test-server/constraints.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ importlib-metadata==6.8.0
2323
itsdangerous==2.1.2
2424
Jinja2==3.1.2
2525
MarkupSafe==2.1.3
26-
opentelemetry-api==1.20.0
27-
opentelemetry-sdk==1.20.0
28-
opentelemetry-semantic-conventions==0.41b0
26+
opentelemetry-api==1.30.0
27+
opentelemetry-sdk==1.30.0
28+
opentelemetry-semantic-conventions==0.51b0
2929
packaging==24.1
3030
proto-plus==1.22.3
3131
protobuf==4.24.4

opentelemetry-exporter-gcp-logging/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
## Unreleased
44

5+
Added support for when `bytes` or `list['bytes']` is in `LogRecord.body` and
6+
body is of type Mapping. Update opentelemetry-api/sdk dependencies to 1.3.
7+
58
## Version 1.9.0a0
69

710
Released 2025-02-03

opentelemetry-exporter-gcp-logging/setup.cfg

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ package_dir=
2727
packages=find_namespace:
2828
install_requires =
2929
google-cloud-logging ~= 3.0
30-
opentelemetry-sdk ~= 1.0
30+
opentelemetry-sdk ~= 1.30
31+
opentelemetry-api ~= 1.30
3132
opentelemetry-resourcedetector-gcp >= 1.5.0dev0, == 1.*
3233

3334
[options.packages.find]

opentelemetry-exporter-gcp-logging/src/opentelemetry/exporter/cloud_logging/__init__.py

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import json
1919
import logging
2020
import urllib.parse
21-
from typing import Any, Mapping, Optional, Sequence
21+
from typing import Any, Mapping, MutableMapping, Optional, Sequence
2222

2323
import google.auth
2424
from google.api.monitored_resource_pb2 import ( # pylint: disable = no-name-in-module
@@ -50,6 +50,7 @@
5050
from opentelemetry.sdk._logs.export import LogExporter
5151
from opentelemetry.sdk.resources import Resource
5252
from opentelemetry.trace import format_span_id, format_trace_id
53+
from opentelemetry.util.types import AnyValue
5354

5455
DEFAULT_MAX_ENTRY_SIZE = 256000 # 256 KB
5556
DEFAULT_MAX_REQUEST_SIZE = 10000000 # 10 MB
@@ -117,10 +118,37 @@ def _convert_any_value_to_string(value: Any) -> str:
117118
return ""
118119

119120

120-
def _set_payload_in_log_entry(log_entry: LogEntry, body: Any | None):
121+
# Be careful not to mutate original body. Make copies of anything that needs to change.
122+
def _sanitized_body(
123+
body: Mapping[str, AnyValue]
124+
) -> MutableMapping[str, AnyValue]:
125+
new_body: MutableMapping[str, AnyValue] = {}
126+
for key, value in body.items():
127+
if (
128+
isinstance(value, Sequence)
129+
and len(value) > 0
130+
and isinstance(value[0], bytes)
131+
):
132+
# Should not be possible for a non-bytes value to be present. AnyValue requires Sequence be of one type, and above
133+
# we verified the first value is type bytes.
134+
new_body[key] = [
135+
base64.b64encode(v).decode()
136+
for v in value
137+
if isinstance(v, bytes)
138+
]
139+
elif isinstance(value, bytes):
140+
new_body[key] = base64.b64encode(value).decode()
141+
elif isinstance(value, Mapping):
142+
new_body[key] = _sanitized_body(value)
143+
else:
144+
new_body[key] = value
145+
return new_body
146+
147+
148+
def _set_payload_in_log_entry(log_entry: LogEntry, body: AnyValue):
121149
struct = Struct()
122150
if isinstance(body, Mapping):
123-
struct.update(body)
151+
struct.update(_sanitized_body(body))
124152
log_entry.json_payload = struct
125153
elif isinstance(body, bytes):
126154
json_str = body.decode("utf-8", errors="replace")

opentelemetry-exporter-gcp-logging/tests/__snapshots__/test_cloud_logging/test_convert_otlp_dict_body.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44
{
55
"jsonPayload": {
66
"kvlistValue": {
7+
"bytes_field": "Ynl0ZXM=",
8+
"repeated_bytes_field": [
9+
"Ynl0ZXM=",
10+
"Ynl0ZXM=",
11+
"Ynl0ZXM="
12+
],
713
"values": [
814
{
915
"key": "content",

opentelemetry-exporter-gcp-logging/tests/test_cloud_logging.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,9 @@ def test_convert_otlp_dict_body(
9292
"stringValue": "You're a helpful assistant."
9393
},
9494
}
95-
]
95+
],
96+
"bytes_field": b"bytes",
97+
"repeated_bytes_field": [b"bytes", b"bytes", b"bytes"],
9698
}
9799
},
98100
),

opentelemetry-exporter-gcp-monitoring/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## Unreleased
44

5+
Update opentelemetry-api/sdk dependencies to 1.3.
6+
57
## Version 1.9.0a0
68

79
Released 2025-02-03

opentelemetry-exporter-gcp-monitoring/setup.cfg

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ package_dir=
2828
packages=find_namespace:
2929
install_requires =
3030
google-cloud-monitoring ~= 2.0
31-
opentelemetry-api ~= 1.0
32-
opentelemetry-sdk ~= 1.0
31+
opentelemetry-api ~= 1.30
32+
opentelemetry-sdk ~= 1.30
3333
opentelemetry-resourcedetector-gcp >= 1.5.0dev0, == 1.*
3434

3535
[options.packages.find]

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@
5555
)
5656
from opentelemetry.sdk import version as opentelemetry_sdk_version
5757
from opentelemetry.sdk.metrics.export import (
58+
ExponentialHistogram,
59+
ExponentialHistogramDataPoint,
5860
Gauge,
5961
Histogram,
6062
HistogramDataPoint,
@@ -209,6 +211,12 @@ def _get_metric_descriptor(
209211
descriptor.metric_kind = MetricDescriptor.MetricKind.GAUGE
210212
elif isinstance(data, Histogram):
211213
descriptor.metric_kind = MetricDescriptor.MetricKind.CUMULATIVE
214+
elif isinstance(data, ExponentialHistogram):
215+
logger.warning(
216+
"Unsupported metric data type %s, ignoring it",
217+
type(data).__name__,
218+
)
219+
return None
212220
else:
213221
# Exhaustive check
214222
_: NoReturn = data
@@ -342,6 +350,10 @@ def export(
342350
continue
343351

344352
for data_point in metric.data.data_points:
353+
if isinstance(
354+
data_point, ExponentialHistogramDataPoint
355+
):
356+
continue
345357
labels = {
346358
_normalize_label_key(key): str(value)
347359
for key, value in (

0 commit comments

Comments
 (0)