From 75a6710f4a5defde33718b64d70a3c8e5ec27f6d Mon Sep 17 00:00:00 2001 From: Ivana Kellyerova Date: Tue, 16 May 2023 16:26:06 +0200 Subject: [PATCH 1/2] Serialize local vars early on No need to have actual references floating around. --- sentry_sdk/utils.py | 6 +++++- tests/test_utils.py | 8 ++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/sentry_sdk/utils.py b/sentry_sdk/utils.py index ddbc329932..ff8f4127e2 100644 --- a/sentry_sdk/utils.py +++ b/sentry_sdk/utils.py @@ -627,7 +627,11 @@ def serialize_frame( ) if include_local_variables: - rv["vars"] = frame.f_locals + # repr local vars here already to avoid changing stuff + # by reference later (e.g. when scrubbing PII) + from sentry_sdk.serializer import serialize + + rv["vars"] = serialize(frame.f_locals, should_repr_strings=True) return rv diff --git a/tests/test_utils.py b/tests/test_utils.py index aa88d26c44..f54c31cc1e 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -241,3 +241,11 @@ def test_include_source_context_when_serializing_frame(include_source_context): assert include_source_context ^ ("pre_context" in result) ^ True assert include_source_context ^ ("context_line" in result) ^ True assert include_source_context ^ ("post_context" in result) ^ True + + +def test_local_vars_serialized_when_serializing_frame(): + local_var = lambda: "cats" # noqa: F841 + frame = sys._getframe() + result = serialize_frame(frame) + + assert all(isinstance(val, str) for val in result["vars"].values()) From 6628cf59f9cb13618384056825e8efcb6f0eb1b7 Mon Sep 17 00:00:00 2001 From: Ivana Kellyerova Date: Tue, 16 May 2023 16:50:58 +0200 Subject: [PATCH 2/2] fix double serialization --- sentry_sdk/client.py | 6 +++++- sentry_sdk/serializer.py | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/sentry_sdk/client.py b/sentry_sdk/client.py index 204b99ce0c..8269cb3da7 100644 --- a/sentry_sdk/client.py +++ b/sentry_sdk/client.py @@ -320,7 +320,11 @@ def _prepare_event( # Postprocess the event here so that annotated types do # generally not surface in before_send if event is not None: - event = serialize(event, request_bodies=self.options.get("request_bodies")) + event = serialize( + event, + request_bodies=self.options.get("request_bodies"), + ignore_local_vars=True, + ) before_send = self.options["before_send"] if ( diff --git a/sentry_sdk/serializer.py b/sentry_sdk/serializer.py index b3f8012c28..20cf9deb77 100644 --- a/sentry_sdk/serializer.py +++ b/sentry_sdk/serializer.py @@ -121,6 +121,7 @@ def serialize(event, **kwargs): meta_stack = [] # type: List[Dict[str, Any]] keep_request_bodies = kwargs.pop("request_bodies", None) == "always" # type: bool + ignore_local_vars = kwargs.pop("ignore_local_vars", False) def _annotate(**meta): # type: (**Any) -> None @@ -380,7 +381,8 @@ def _serialize_node_impl( return rv_list if should_repr_strings: - obj = safe_repr(obj) + if not ignore_local_vars: + obj = safe_repr(obj) else: if isinstance(obj, bytes) or isinstance(obj, bytearray): obj = obj.decode("utf-8", "replace")