8000 fix: Ensure tags values are strings (#4459) · getsentry/sentry-python@401a003 · GitHub
[go: up one dir, main page]

Skip to content

Commit 401a003

Browse files
szokeasaurusrexcursoragentsentrivana
authored
fix: Ensure tags values are strings (#4459)
Ensure tag values are strings before serializing an event or a transaction to an `Event` dictionary. Fixes #4391 Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Ivana Kellyer <ivana.kellyer@sentry.io>
1 parent b07438d commit 401a003

File tree

13 files changed

+272
-27
lines changed

13 files changed

+272
-27
lines changed

MIGRATION_GUIDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Looking to upgrade from Sentry SDK 2.x to 3.x? Here's a comprehensive list of wh
1212

1313
- The SDK now supports Python 3.7 and higher.
1414
- The default of `traces_sample_rate` changed to `0`. Meaning: Incoming traces will be continued by default. For example, if your frontend sends a `sentry-trace/baggage` headers pair, your SDK will create Spans and send them to Sentry. (The default used to be `None` meaning by default no Spans where created, no matter what headers the frontend sent to your project.) See also: https://docs.sentry.io/platforms/python/configuration/options/#traces_sample_rate
15+
- Tag values on event dictionaries, which are passed to `before_send` and `before_send_transaction`, now are always `str` values. Previously, despite tag values being typed as `str`, they often had different values. Therefore, if you have configured any `before_send` and `before_send_transaction` functions which perform some logic based on tag values, you need to check and if needed update those functions to correctly handle `str` values.
1516
- `sentry_sdk.start_span` now only takes keyword arguments.
1617
- `sentry_sdk.start_transaction`/`sentry_sdk.start_span` no longer takes the following arguments: `span`, `parent_sampled`, `trace_id`, `span_id` or `parent_span_id`.
1718
- You can no longer change the sampled status of a span with `span.sampled = False` after starting it.

sentry_sdk/opentelemetry/span_processor.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
try_profile_lifecycle_trace_start,
3838
)
3939
from sentry_sdk.profiler.transaction_profiler import Profile
40+
from sentry_sdk.utils import safe_str
4041
from sentry_sdk._types import TYPE_CHECKING
4142

4243
if TYPE_CHECKING:
@@ -294,7 +295,9 @@ def _common_span_transaction_attributes_as_json(
294295

295296
tags = extract_span_attributes(span, SentrySpanAttribute.TAG)
296297
if tags:
297-
common_json["tags"] = tags
298+
common_json["tags"] = {
299+
tag: safe_str(tag_value) for tag, tag_value in tags.items()
300+
}
298301

299302
return common_json
300303

sentry_sdk/scope.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
event_from_exception,
4040
exc_info_from_error,
4141
logger,
42+
safe_str,
4243
)
4344

4445
from typing import TYPE_CHECKING
@@ -1141,7 +1142,9 @@ def _apply_tags_to_event(
11411142
self, event: Event, hint: Hint, options: Optional[Dict[str, Any]]
11421143
) -> None:
11431144
if self._tags:
1144-
event.setdefault("tags", {}).update(self._tags)
1145+
event.setdefault("tags", {}).update(
1146+
{k: safe_str(v) for k, v in self._tags.items()}
1147+
)
11451148

11461149
def _apply_contexts_to_event(
11471150
self, event: Event, hint: Hint, options: Optional[Dict[str, Any]]

tests/integrations/aws_lambda/test_aws_lambda.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -322,10 +322,10 @@ def test_non_dict_event(
322322
assert transaction_event["request"] == request_data
323323

324324
if batch_size > 1:
325-
assert error_event["tags"]["batch_size"] == batch_size
326-
assert error_event["tags"]["batch_request"] is True
327-
assert transaction_event["tags"]["batch_size"] == batch_size
328-
assert transaction_event["tags"]["batch_request"] is True
325+
assert error_event["tags"]["batch_size"] == str(batch_size)
326+
assert error_event["tags"]["batch_request"] == "True"
327+
assert transaction_event["tags"]["batch_size"] == str(batch_size)
328+
assert transaction_event["tags"]["batch_request"] == "True"
329329

330330

331331
def test_request_data(lambda_client, test_environment):

tests/integrations/redis/asyncio/test_redis_asyncio.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ async def test_async_redis_pipeline(
7878
}
7979
)
8080
assert span["tags"] == {
81-
"redis.transaction": is_transaction,
82-
"redis.is_cluster": False,
81+
"redis.transaction": str(is_transaction),
82+
"redis.is_cluster": "False",
8383
}
8484

8585

tests/integrations/redis/cluster/test_redis_cluster.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ def test_rediscluster_basic(sentry_init, capture_events, send_default_pii, descr
9494
assert span["tags"] == {
9595
"db.operation": "SET",
9696
"redis.command": "SET",
97-
"redis.is_cluster": True,
97+
"redis.is_cluster": "True",
9898
"redis.key": "bar",
9999
}
100100

@@ -139,8 +139,8 @@ def test_rediscluster_pipeline(
139139
}
140140
)
141141
assert span["tags"] == {
142-
"redis.transaction": False, # For Cluster, this is always False
143-
"redis.is_cluster": True,
142+
"redis.transaction": "False", # For Cluster, this is always False
143+
"redis.is_cluster": "True",
144144
}
145145

146146

tests/integrations/redis/cluster_asyncio/test_redis_cluster_asyncio.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ async def test_async_basic(sentry_init, capture_events, send_default_pii, descri
9494
}
9595
)
9696
assert span["tags"] == {
97-
"redis.is_cluster": True,
97+
"redis.is_cluster": "True",
9898
"db.operation": "SET",
9999
"redis.command": "SET",
100100
"redis.key": "bar",
@@ -142,8 +142,8 @@ async def test_async_redis_pipeline(
142142
}
143143
)
144144
assert span["tags"] == {
145-
"redis.transaction": False,
146-
"redis.is_cluster": True,
145+
"redis.transaction": "False",
146+
"redis.is_cluster": "True",
147147
}
148148
149149

tests/integrations/redis/test_redis.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ def test_redis_pipeline(
7575
assert span["data"]["redis.commands.count"] == 3
7676
assert span["data"]["redis.commands.first_ten"] == expected_first_ten
7777
assert span["tags"] == {
78-
"redis.transaction": is_transaction,
79-
"redis.is_cluster": False,
78+
"redis.transaction": str(is_transaction),
79+
"redis.is_cluster": "False",
8080
}
8181

8282

tests/integrations/redis_py_cluster_legacy/test_redis_py_cluster_legacy.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,8 @@ def test_rediscluster_pipeline(
106106
}
107107
)
108108
assert span["tags"] == {
109-
"redis.transaction": False, # For Cluster, this is always False
110-
"redis.is_cluster": True,
109+
"redis.transaction": "False", # For Cluster, this is always False
110+
"redis.is_cluster": "True",
111111
}
112112

113113

tests/opentelemetry/test_potel.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ def test_transaction_tags_started_with_otel(capture_envelopes):
263263
(item,) = envelope.items
264264
payload = item.payload.json
265265

266-
assert payload["tags"] == {"tag.global": 99, "tag.inner": "foo"}
266+
assert payload["tags"] == {"tag.global": "99", "tag.inner": "foo"}
267267

268268

269269
def test_transaction_tags_started_with_sentry(capture_envelopes):
@@ -277,7 +277,7 @@ def test_transaction_tags_started_with_sentry(capture_envelopes):
277277
(item,) = envelope.items
278278
payload = item.payload.json
279279

280-
assert payload["tags"] == {"tag.global": 99, "tag.inner": "foo"}
280+
assert payload["tags"] == {"tag.global": "99", "tag.inner": "foo"}
281281

282282

283283
def test_multiple_transaction_tags_isolation_scope_started_with_otel(capture_envelopes):
@@ -293,8 +293,8 @@ def test_multiple_transaction_tags_isolation_scope_started_with_otel(capture_env
293293

294294
(payload_a, payload_b) = [envelope.items[0].payload.json for envelope in envelopes]
295295

296-
assert payload_a["tags"] == {"tag.global": 99, "tag.inner.a": "a"}
297-
assert payload_b["tags"] == {"tag.global": 99, "tag.inner.b": "b"}
296+
assert payload_a["tags"] == {"tag.global": "99", "tag.inner.a": "a"}
297+
assert payload_b["tags"] == {"tag.global": "99", "tag.inner.b": "b"}
298298

299299

300300
def test_multiple_transaction_tags_isolation_scope_started_with_sentry(
@@ -312,8 +312,8 @@ def test_multiple_transaction_tags_isolation_scope_started_with_sentry(
312312

313313
(payload_a, payload_b) = [envelope.items[0].payload.json for envelope in envelopes]
314314

315-
assert payload_a["tags"] == {"tag.global": 99, "tag.inner.a": "a"}
316-
assert payload_b["tags"] == {"tag.global": 99, "tag.inner.b": "b"}
315+
assert payload_a["tags"] == {"tag.global": "99", "tag.inner.a": "a"}
316+
assert payload_b["tags"] == {"tag.global": "99", "tag.inner.b": "b"}
317317

318318

319319
def test_potel_span_root_span_references():

0 commit comments

Comments
 (0)
0