Skip to content

Commit d7aebef

Browse files
authored
tests: Test preserialization of attributes (#5260)
Attributes set on logs, metrics, or scopes mustn't contain references to live objects. We don't have tests for this at the moment. It's important to be able to catch regressions in this behavior because it's part of the contract of `before_send_log` and `before_send_metric`.
1 parent bb78d3c commit d7aebef

File tree

3 files changed

+112
-0
lines changed

3 files changed

+112
-0
lines changed

tests/test_attributes.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,41 @@ def test_remove_attribute(sentry_init, capture_envelopes):
117117
(metric,) = metrics
118118

119119
assert "some.attribute" not in metric["attributes"]
120+
121+
122+
def test_scope_attributes_preserialized(sentry_init, capture_envelopes):
123+
def before_send_metric(metric, _):
124+
# Scope attrs show up serialized in before_send
125+
assert isinstance(metric["attributes"]["instance"], str)
126+
assert isinstance(metric["attributes"]["dictionary"], str)
127+
128+
return metric
129+
130+
sentry_init(before_send_metric=before_send_metric)
131+
132+
envelopes = capture_envelopes()
133+
134+
class Cat:
135+
pass
136+
137+
instance = Cat()
138+
dictionary = {"color": "tortoiseshell"}
139+
140+
with sentry_sdk.new_scope() as scope:
141+
scope.set_attribute("instance", instance)
142+
scope.set_attribute("dictionary", dictionary)
143+
144+
# Scope attrs are stored preserialized
145+
assert isinstance(scope._attributes["instance"], str)
146+
assert isinstance(scope._attributes["dictionary"], str)
147+
148+
sentry_sdk.metrics.count("test", 1)
149+
150+
sentry_sdk.get_client().flush()
151+
152+
metrics = envelopes_to_metrics(envelopes)
153+
(metric,) = metrics
154+
155+
# Attrs originally from the scope are serialized when sent
156+
assert isinstance(metric["attributes"]["instance"], str)
157+
assert isinstance(metric["attributes"]["dictionary"], str)

tests/test_logs.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,3 +597,40 @@ def test_log_attributes_override_scope_attributes(sentry_init, capture_envelopes
597597

598598
assert log["attributes"]["durable.attribute"] == "value1"
599599
assert log["attributes"]["temp.attribute"] == "value2"
600+
601+
602+
@minimum_python_37
603+
def test_attributes_preserialized_in_before_send(sentry_init, capture_envelopes):
604+
"""We don't surface references to objects in attributes."""
605+
606+
def before_send_log(log, _):
607+
assert isinstance(log["attributes"]["instance"], str)
608+
assert isinstance(log["attributes"]["dictionary"], str)
609+
610+
return log
611+
612+
sentry_init(enable_logs=True, before_send_log=before_send_log)
613+
614+
envelopes = capture_envelopes()
615+
616+
class Cat:
617+
pass
618+
619+
instance = Cat()
620+
dictionary = {"color": "tortoiseshell"}
621+
622+
sentry_sdk.logger.warning(
623+
"Hello world!",
624+
attributes={
625+
"instance": instance,
626+
"dictionary": dictionary,
627+
},
628+
)
629+
630+
get_client().flush()
631+
632+
logs = envelopes_to_logs(envelopes)
633+
(log,) = logs
634+
635+
assert isinstance(log["attributes"]["instance"], str)
636+
assert isinstance(log["attributes"]["dictionary"], str)

tests/test_metrics.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,3 +335,40 @@ def test_metric_attributes_override_scope_attributes(sentry_init, capture_envelo
335335

336336
assert metric["attributes"]["durable.attribute"] == "value1"
337337
assert metric["attributes"]["temp.attribute"] == "value2"
338+
339+
340+
def test_attributes_preserialized_in_before_send(sentry_init, capture_envelopes):
341+
"""We don't surface references to objects in attributes."""
342+
343+
def before_send_metric(metric, _):
344+
assert isinstance(metric["attributes"]["instance"], str)
345+
assert isinstance(metric["attributes"]["dictionary"], str)
346+
347+
return metric
348+
349+
sentry_init(before_send_metric=before_send_metric)
350+
351+
envelopes = capture_envelopes()
352+
353+
class Cat:
354+
pass
355+
356+
instance = Cat()
357+
dictionary = {"color": "tortoiseshell"}
358+
359+
sentry_sdk.metrics.count(
360+
"test.counter",
361+
1,
362+
attributes={
363+
"instance": instance,
364+
"dictionary": dictionary,
365+
},
366+
)
367+
368+
get_client().flush()
369+
370+
metrics = envelopes_to_metrics(envelopes)
371+
(metric,) = metrics
372+
373+
assert isinstance(metric["attributes"]["instance"], str)
374+
assert isinstance(metric["attributes"]["dictionary"], str)

0 commit comments

Comments
 (0)