|
7 | 7 | from importlib import import_module |
8 | 8 | from typing import TYPE_CHECKING, List, Dict, cast, overload |
9 | 9 | import warnings |
| 10 | +import json |
10 | 11 |
|
11 | 12 | from sentry_sdk._compat import check_uwsgi_thread_support |
12 | 13 | from sentry_sdk._metrics_batcher import MetricsBatcher |
|
27 | 28 | get_before_send_metric, |
28 | 29 | has_logs_enabled, |
29 | 30 | has_metrics_enabled, |
30 | | - serialize_attribute, |
31 | 31 | ) |
32 | 32 | from sentry_sdk.serializer import serialize |
33 | 33 | from sentry_sdk.tracing import trace |
| 34 | +from sentry_sdk.traces import SpanStatus |
34 | 35 | from sentry_sdk.tracing_utils import has_span_streaming_enabled |
35 | 36 | from sentry_sdk.transport import ( |
36 | 37 | HttpTransportCore, |
|
39 | 40 | ) |
40 | 41 | from sentry_sdk.consts import ( |
41 | 42 | SPANDATA, |
| 43 | + SPANSTATUS, |
42 | 44 | DEFAULT_MAX_VALUE_LENGTH, |
43 | 45 | DEFAULT_OPTIONS, |
44 | 46 | INSTRUMENTER, |
@@ -97,7 +99,7 @@ def _serialized_v1_span_to_serialized_v2_span( |
97 | 99 | ) -> "dict[str, Any]": |
98 | 100 | # See SpanBatcher._to_transport_format() for analogous population of all entries except "attributes". |
99 | 101 | res: "dict[str, Any]" = { |
100 | | - "status": "ok", |
| 102 | + "status": SpanStatus.OK.value, |
101 | 103 | "is_segment": False, |
102 | 104 | } |
103 | 105 |
|
@@ -133,7 +135,7 @@ def _serialized_v1_span_to_serialized_v2_span( |
133 | 135 | if "parent_span_id" in span: |
134 | 136 | res["parent_span_id"] = span["parent_span_id"] |
135 | 137 |
|
136 | | - if "status" in span and span["status"] != "ok": |
| 138 | + if "status" in span and span["status"] != SPANSTATUS.OK: |
137 | 139 | res["status"] = "error" |
138 | 140 |
|
139 | 141 | attributes: "Dict[str, Any]" = {} |
@@ -180,8 +182,58 @@ def _serialized_v1_span_to_serialized_v2_span( |
180 | 182 | if "version" in sdk_info: |
181 | 183 | attributes["sentry.sdk.version"] = sdk_info["version"] |
182 | 184 |
|
183 | | - if attributes: |
184 | | - res["attributes"] = {k: serialize_attribute(v) for k, v in attributes.items()} |
| 185 | + for key, value in attributes.items(): |
| 186 | + serialized_value = serialize(value) |
| 187 | + if isinstance(serialized_value, bool): |
| 188 | + res.setdefault("attributes", {})[key] = { |
| 189 | + "value": serialized_value, |
| 190 | + "type": "boolean", |
| 191 | + } |
| 192 | + continue |
| 193 | + |
| 194 | + if isinstance(serialized_value, int): |
| 195 | + res.setdefault("attributes", {})[key] = { |
| 196 | + "value": serialized_value, |
| 197 | + "type": "integer", |
| 198 | + } |
| 199 | + continue |
| 200 | + |
| 201 | + if isinstance(serialized_value, float): |
| 202 | + res.setdefault("attributes", {})[key] = { |
| 203 | + "value": serialized_value, |
| 204 | + "type": "double", |
| 205 | + } |
| 206 | + continue |
| 207 | + |
| 208 | + if isinstance(serialized_value, str): |
| 209 | + res.setdefault("attributes", {})[key] = { |
| 210 | + "value": serialized_value, |
| 211 | + "type": "string", |
| 212 | + } |
| 213 | + continue |
| 214 | + |
| 215 | + if isinstance(serialized_value, list): |
| 216 | + if not serialized_value: |
| 217 | + res.setdefault("attributes", {})[key] = {"value": [], "type": "array"} |
| 218 | + |
| 219 | + ty = type(serialized_value[0]) |
| 220 | + if ty in (int, str, bool, float) and all( |
| 221 | + type(v) is ty for v in serialized_value |
| 222 | + ): |
| 223 | + res.setdefault("attributes", {})[key] = { |
| 224 | + "value": serialized_value, |
| 225 | + "type": "array", |
| 226 | + } |
| 227 | + |
| 228 | + continue |
| 229 | + |
| 230 | + # Types returned when the serializer for V1 span attributes recurses into some container types. |
| 231 | + if isinstance(serialized_value, (dict, list)): |
| 232 | + res.setdefault("attributes", {})[key] = { |
| 233 | + "value": json.dumps(serialized_value), |
| 234 | + "type": "string", |
| 235 | + } |
| 236 | + continue |
185 | 237 |
|
186 | 238 | return res |
187 | 239 |
|
|
0 commit comments