Skip to content

Commit df8fec6

Browse files
feat: Remove string truncation for events (#5095)
Remove the default string limit applied when serializing envelopes. The `max_value_length` parameter now accepts `None`, which disables string truncation. The default value is changed to `None`. The change follows on from raising the limit in #4632. Replaces `DEFAULT_MAX_VALUE_LENGTH` with the value 1024 in tests, which was the original limit. Closes #4988
1 parent d864ba0 commit df8fec6

File tree

11 files changed

+192
-153
lines changed

11 files changed

+192
-153
lines changed

sentry_sdk/client.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
from sentry_sdk.transport import BaseHttpTransport, make_transport
3535
from sentry_sdk.consts import (
3636
SPANDATA,
37-
DEFAULT_MAX_VALUE_LENGTH,
3837
DEFAULT_OPTIONS,
3938
INSTRUMENTER,
4039
VERSION,
@@ -584,7 +583,7 @@ def _prepare_event(
584583
"include_local_variables", True
585584
),
586585
max_value_length=self.options.get(
587-
"max_value_length", DEFAULT_MAX_VALUE_LENGTH
586+
"max_value_length", None
588587
),
589588
),
590589
"crashed": False,

sentry_sdk/consts.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,6 @@
22
from enum import Enum
33
from typing import TYPE_CHECKING
44

5-
# up top to prevent circular import due to integration import
6-
# This is more or less an arbitrary large-ish value for now, so that we allow
7-
# pretty long strings (like LLM prompts), but still have *some* upper limit
8-
# until we verify that removing the trimming completely is safe.
9-
DEFAULT_MAX_VALUE_LENGTH = 100_000
10-
115
DEFAULT_MAX_STACK_FRAMES = 100
126
DEFAULT_ADD_FULL_STACK = False
137

@@ -996,7 +990,7 @@ def __init__(
996990
], # type: Optional[Sequence[str]]
997991
functions_to_trace=[], # type: Sequence[Dict[str, str]] # noqa: B006
998992
event_scrubber=None, # type: Optional[sentry_sdk.scrubber.EventScrubber]
999-
max_value_length=DEFAULT_MAX_VALUE_LENGTH, # type: int
993+
max_value_length=None, # type: Optional[int]
1000994
enable_backpressure_handling=True, # type: bool
1001995
error_sampler=None, # type: Optional[Callable[[Event, Hint], Union[float, bool]]]
1002996
enable_db_query_source=True, # type: bool

sentry_sdk/serializer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ def serialize(event, **kwargs):
119119
* Annotating the payload with the _meta field whenever trimming happens.
120120
121121
:param max_request_body_size: If set to "always", will never trim request bodies.
122-
:param max_value_length: The max length to strip strings to, defaults to sentry_sdk.consts.DEFAULT_MAX_VALUE_LENGTH
122+
:param max_value_length: The max length to strip strings to, or None to disable string truncation. Defaults to None.
123123
:param is_vars: If we're serializing vars early, we want to repr() things that are JSON-serializable to make their type more apparent. For example, it's useful to see the difference between a unicode-string and a bytestring when viewing a stacktrace.
124124
:param custom_repr: A custom repr function that runs before safe_repr on the object to be serialized. If it returns None or throws internally, we will fallback to safe_repr.
125125

sentry_sdk/utils.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
from sentry_sdk.consts import (
3030
DEFAULT_ADD_FULL_STACK,
3131
DEFAULT_MAX_STACK_FRAMES,
32-
DEFAULT_MAX_VALUE_LENGTH,
3332
EndpointType,
3433
)
3534
from sentry_sdk._types import Annotated, AnnotatedValue, SENSITIVE_DATA_SUBSTITUTE
@@ -730,7 +729,7 @@ def single_exception_from_error_tuple(
730729
if client_options is None:
731730
include_local_variables = True
732731
include_source_context = True
733-
max_value_length = DEFAULT_MAX_VALUE_LENGTH # fallback
732+
max_value_length = None # fallback
734733
custom_repr = None
735734
else:
736735
include_local_variables = client_options["include_local_variables"]
@@ -1211,7 +1210,7 @@ def strip_string(value, max_length=None):
12111210
return value
12121211

12131212
if max_length is None:
1214-
max_length = DEFAULT_MAX_VALUE_LENGTH
1213+
return value
12151214

12161215
byte_size = _get_size_in_bytes(value)
12171216
text_size = len(value)

tests/integrations/bottle/test_bottle.py

Lines changed: 57 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
from io import BytesIO
66
from bottle import Bottle, debug as set_debug, abort, redirect, HTTPResponse
77
from sentry_sdk import capture_message
8-
from sentry_sdk.consts import DEFAULT_MAX_VALUE_LENGTH
98
from sentry_sdk.integrations.bottle import BottleIntegration
109
from sentry_sdk.serializer import MAX_DATABAG_BREADTH
1110

@@ -121,10 +120,17 @@ def index():
121120
assert event["exception"]["values"][0]["mechanism"]["handled"] is False
122121

123122

124-
def test_large_json_request(sentry_init, capture_events, app, get_client):
125-
sentry_init(integrations=[BottleIntegration()], max_request_body_size="always")
123+
@pytest.mark.parametrize("max_value_length", [1024, None])
124+
def test_large_json_request(
125+
sentry_init, capture_events, app, get_client, max_value_length
126+
):
127+
sentry_init(
128+
integrations=[BottleIntegration()],
129+
max_request_body_size="always",
130+
max_value_length=max_value_length,
131+
)
126132

127-
data = {"foo": {"bar": "a" * (DEFAULT_MAX_VALUE_LENGTH + 10)}}
133+
data = {"foo": {"bar": "a" * (1034)}}
128134

129135
@app.route("/", method="POST")
130136
def index():
@@ -144,15 +150,17 @@ def index():
144150
assert response[1] == "200 OK"
145151

146152
(event,) = events
147-
assert event["_meta"]["request"]["data"]["foo"]["bar"] == {
148-
"": {
149-
"len": DEFAULT_MAX_VALUE_LENGTH + 10,
150-
"rem": [
151-
["!limit", "x", DEFAULT_MAX_VALUE_LENGTH - 3, DEFAULT_MAX_VALUE_LENGTH]
152-
],
153+
154+
if max_value_length:
155+
assert event["_meta"]["request"]["data"]["foo"]["bar"] == {
156+
"": {
157+
"len": 1034,
158+
"rem": [["!limit", "x", 1021, 1024]],
159+
}
153160
}
154-
}
155-
assert len(event["request"]["data"]["foo"]["bar"]) == DEFAULT_MAX_VALUE_LENGTH
161+
assert len(event["request"]["data"]["foo"]["bar"]) == 1024
162+
else:
163+
assert len(event["request"]["data"]["foo"]["bar"]) == 1034
156164

157165

158166
@pytest.mark.parametrize("data", [{}, []], ids=["empty-dict", "empty-list"])
@@ -179,10 +187,17 @@ def index():
179187
assert event["request"]["data"] == data
180188

181189

182-
def test_medium_formdata_request(sentry_init, capture_events, app, get_client):
183-
sentry_init(integrations=[BottleIntegration()], max_request_body_size="always")
190+
@pytest.mark.parametrize("max_value_length", [1024, None])
191+
def test_medium_formdata_request(
192+
sentry_init, capture_events, app, get_client, max_value_length
193+
):
194+
sentry_init(
195+
integrations=[BottleIntegration()],
196+
max_request_body_size="always",
197+
max_value_length=max_value_length,
198+
)
184199

185-
data = {"foo": "a" * (DEFAULT_MAX_VALUE_LENGTH + 10)}
200+
data = {"foo": "a" * (1034)}
186201

187202
@app.route("/", method="POST")
188203
def index():
@@ -199,15 +214,17 @@ def index():
199214
assert response[1] == "200 OK"
200215

201216
(event,) = events
202-
assert event["_meta"]["request"]["data"]["foo"] == {
203-
"": {
204-
"len": DEFAULT_MAX_VALUE_LENGTH + 10,
205-
"rem": [
206-
["!limit", "x", DEFAULT_MAX_VALUE_LENGTH - 3, DEFAULT_MAX_VALUE_LENGTH]
207-
],
217+
218+
if max_value_length:
219+
assert event["_meta"]["request"]["data"]["foo"] == {
220+
"": {
221+
"len": 1034,
222+
"rem": [["!limit", "x", 1021, 1024]],
223+
}
208224
}
209-
}
210-
assert len(event["request"]["data"]["foo"]) == DEFAULT_MAX_VALUE_LENGTH
225+
assert len(event["request"]["data"]["foo"]) == 1024
226+
else:
227+
assert len(event["request"]["data"]["foo"]) == 1034
211228

212229

213230
@pytest.mark.parametrize("input_char", ["a", b"a"])
@@ -241,11 +258,16 @@ def index():
241258
assert not event["request"]["data"]
242259

243260

244-
def test_files_and_form(sentry_init, capture_events, app, get_client):
245-
sentry_init(integrations=[BottleIntegration()], max_request_body_size="always")
261+
@pytest.mark.parametrize("max_value_length", [1024, None])
262+
def test_files_and_form(sentry_init, capture_events, app, get_client, max_value_length):
263+
sentry_init(
264+
integrations=[BottleIntegration()],
265+
max_request_body_size="always",
266+
max_value_length=max_value_length,
267+
)
246268

247269
data = {
248-
"foo": "a" * (DEFAULT_MAX_VALUE_LENGTH + 10),
270+
"foo": "a" * (1034),
249271
"file": (BytesIO(b"hello"), "hello.txt"),
250272
}
251273

@@ -266,15 +288,16 @@ def index():
266288
assert response[1] == "200 OK"
267289

268290
(event,) = events
269-
assert event["_meta"]["request"]["data"]["foo"] == {
270-
"": {
271-
"len": DEFAULT_MAX_VALUE_LENGTH + 10,
272-
"rem": [
273-
["!limit", "x", DEFAULT_MAX_VALUE_LENGTH - 3, DEFAULT_MAX_VALUE_LENGTH]
274-
],
291+
if max_value_length:
292+
assert event["_meta"]["request"]["data"]["foo"] == {
293+
"": {
294+
"len": 1034,
295+
"rem": [["!limit", "x", 1021, 1024]],
296+
}
275297
}
276-
}
277-
assert len(event["request"]["data"]["foo"]) == DEFAULT_MAX_VALUE_LENGTH
298+
assert len(event["request"]["data"]["foo"]) == 1024
299+
else:
300+
assert len(event["request"]["data"]["foo"]) == 1034
278301

279302
assert event["_meta"]["request"]["data"]["file"] == {
280303
"": {

tests/integrations/falcon/test_falcon.py

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import falcon
66
import falcon.testing
77
import sentry_sdk
8-
from sentry_sdk.consts import DEFAULT_MAX_VALUE_LENGTH
98
from sentry_sdk.integrations.falcon import FalconIntegration
109
from sentry_sdk.integrations.logging import LoggingIntegration
1110
from sentry_sdk.utils import parse_version
@@ -207,10 +206,15 @@ def on_get(self, req, resp):
207206
assert len(events) == 0
208207

209208

210-
def test_falcon_large_json_request(sentry_init, capture_events):
211-
sentry_init(integrations=[FalconIntegration()], max_request_body_size="always")
209+
@pytest.mark.parametrize("max_value_length", [1024, None])
210+
def test_falcon_large_json_request(sentry_init, capture_events, max_value_length):
211+
sentry_init(
212+
integrations=[FalconIntegration()],
213+
max_request_body_size="always",
214+
max_value_length=max_value_length,
215+
)
212216

213-
data = {"foo": {"bar": "a" * (DEFAULT_MAX_VALUE_LENGTH + 10)}}
217+
data = {"foo": {"bar": "a" * (1034)}}
214218

215219
class Resource:
216220
def on_post(self, req, resp):
@@ -228,15 +232,16 @@ def on_post(self, req, resp):
228232
assert response.status == falcon.HTTP_200
229233

230234
(event,) = events
231-
assert event["_meta"]["request"]["data"]["foo"]["bar"] == {
232-
"": {
233-
"len": DEFAULT_MAX_VALUE_LENGTH + 10,
234-
"rem": [
235-
["!limit", "x", DEFAULT_MAX_VALUE_LENGTH - 3, DEFAULT_MAX_VALUE_LENGTH]
236-
],
235+
if max_value_length:
236+
assert event["_meta"]["request"]["data"]["foo"]["bar"] == {
237+
"": {
238+
"len": 1034,
239+
"rem": [["!limit", "x", 1021, 1024]],
240+
}
237241
}
238-
}
239-
assert len(event["request"]["data"]["foo"]["bar"]) == DEFAULT_MAX_VALUE_LENGTH
242+
assert len(event["request"]["data"]["foo"]["bar"]) == 1024
243+
else:
244+
assert len(event["request"]["data"]["foo"]["bar"]) == 1034
240245

241246

242247
@pytest.mark.parametrize("data", [{}, []], ids=["empty-dict", "empty-list"])

0 commit comments

Comments
 (0)