|
18 | 18 | import json |
19 | 19 | import logging |
20 | 20 | import urllib.parse |
21 | | -from typing import Any, Mapping, Optional, Sequence |
| 21 | +from typing import Any, Mapping, MutableMapping, Optional, Sequence |
22 | 22 |
|
23 | 23 | import google.auth |
24 | 24 | from google.api.monitored_resource_pb2 import ( # pylint: disable = no-name-in-module |
|
50 | 50 | from opentelemetry.sdk._logs.export import LogExporter |
51 | 51 | from opentelemetry.sdk.resources import Resource |
52 | 52 | from opentelemetry.trace import format_span_id, format_trace_id |
| 53 | +from opentelemetry.util.types import AnyValue |
53 | 54 |
|
54 | 55 | DEFAULT_MAX_ENTRY_SIZE = 256000 # 256 KB |
55 | 56 | DEFAULT_MAX_REQUEST_SIZE = 10000000 # 10 MB |
@@ -117,10 +118,37 @@ def _convert_any_value_to_string(value: Any) -> str: |
117 | 118 | return "" |
118 | 119 |
|
119 | 120 |
|
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): |
121 | 149 | struct = Struct() |
122 | 150 | if isinstance(body, Mapping): |
123 | | - struct.update(body) |
| 151 | + struct.update(_sanitized_body(body)) |
124 | 152 | log_entry.json_payload = struct |
125 | 153 | elif isinstance(body, bytes): |
126 | 154 | json_str = body.decode("utf-8", errors="replace") |
|
0 commit comments