Skip to content

Commit f7d8dde

Browse files
authored
Merge branch 'master' into ivana/streaming-misc-tests
2 parents 73d3210 + 0cc4505 commit f7d8dde

6 files changed

Lines changed: 658 additions & 4 deletions

File tree

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ sentry_sdk.init(
4949
# Set traces_sample_rate to 1.0 to capture 100%
5050
# of traces for performance monitoring.
5151
traces_sample_rate=1.0,
52+
53+
# To disable sending user data and HTTP request/response bodies, uncomment
54+
# the line below. For more info visit:
55+
# https://docs.sentry.io/platforms/python/configuration/options/#data_collection
56+
# data_collection={"user_info": False, "http_bodies": []},
5257
)
5358
```
5459

sentry_sdk/_types.py

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ def substituted_because_contains_sensitive_data(cls) -> "AnnotatedValue":
141141
from collections.abc import Container, MutableMapping, Sequence
142142
from datetime import datetime
143143
from types import TracebackType
144-
from typing import Any, Callable, Dict, Mapping, NotRequired, Optional, Type
144+
from typing import Any, Callable, Dict, List, Mapping, NotRequired, Optional, Type
145145

146146
from typing_extensions import Literal, TypedDict
147147

@@ -152,6 +152,59 @@ class SDKInfo(TypedDict):
152152
version: str
153153
packages: "Sequence[Mapping[str, str]]"
154154

155+
class KeyValueCollectionBehaviour(TypedDict):
156+
mode: 'Literal["off", "denylist", "allowlist"]'
157+
terms: "NotRequired[List[str]]"
158+
159+
class GenAICollectionUserOptions(TypedDict, total=False):
160+
inputs: bool
161+
outputs: bool
162+
163+
class GenAICollectionBehaviour(TypedDict):
164+
inputs: bool
165+
outputs: bool
166+
167+
class GraphQLCollectionUserOptions(TypedDict, total=False):
168+
document: bool
169+
variables: bool
170+
171+
class GraphQLCollectionBehaviour(TypedDict):
172+
document: bool
173+
variables: bool
174+
175+
class HttpHeadersCollectionUserOptions(TypedDict, total=False):
176+
request: "KeyValueCollectionBehaviour"
177+
178+
class HttpHeadersCollectionBehaviour(TypedDict):
179+
request: "KeyValueCollectionBehaviour"
180+
181+
class DataCollectionUserOptions(TypedDict, total=False):
182+
user_info: bool
183+
cookies: "KeyValueCollectionBehaviour"
184+
http_headers: "HttpHeadersCollectionUserOptions"
185+
http_bodies: "List[str]"
186+
query_params: "KeyValueCollectionBehaviour"
187+
graphql: "GraphQLCollectionUserOptions"
188+
gen_ai: "GenAICollectionUserOptions"
189+
database_query_data: bool
190+
queues: bool
191+
stack_frame_variables: bool
192+
frame_context_lines: int
193+
194+
class DataCollection(TypedDict):
195+
provided_by_user: bool
196+
user_info: bool
197+
cookies: "KeyValueCollectionBehaviour"
198+
http_headers: "HttpHeadersCollectionBehaviour"
199+
http_bodies: "List[str]"
200+
query_params: "KeyValueCollectionBehaviour"
201+
graphql: "GraphQLCollectionBehaviour"
202+
gen_ai: "GenAICollectionBehaviour"
203+
database_query_data: bool
204+
queues: bool
205+
stack_frame_variables: bool
206+
frame_context_lines: int
207+
155208
# "critical" is an alias of "fatal" recognized by Relay
156209
LogLevelStr = Literal["fatal", "critical", "error", "warning", "info", "debug"]
157210

sentry_sdk/client.py

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323
VERSION,
2424
ClientConstructor,
2525
)
26+
from sentry_sdk.data_collection import (
27+
_map_from_send_default_pii,
28+
_resolve_data_collection,
29+
)
2630
from sentry_sdk.envelope import Envelope, Item, PayloadRef
2731
from sentry_sdk.integrations import _DEFAULT_INTEGRATIONS, setup_integrations
2832
from sentry_sdk.integrations.dedupe import DedupeIntegration
@@ -345,11 +349,13 @@ def _get_options(*args: "Optional[str]", **kwargs: "Any") -> "Dict[str, Any]":
345349
if rv["enable_tracing"] is True and rv["traces_sample_rate"] is None:
346350
rv["traces_sample_rate"] = 1.0
347351

352+
rv["data_collection"] = _resolve_data_collection(rv)
353+
348354
if rv["event_scrubber"] is None:
349355
rv["event_scrubber"] = EventScrubber(
350-
send_default_pii=(
351-
False if rv["send_default_pii"] is None else rv["send_default_pii"]
352-
)
356+
send_default_pii=False
357+
if rv["send_default_pii"] is None
358+
else rv["send_default_pii"]
353359
)
354360

355361
if rv["socket_options"] and not isinstance(rv["socket_options"], list):
@@ -614,6 +620,19 @@ def _record_lost_event(
614620
self.options["error_sampler"] = sample_all
615621
self.options["traces_sampler"] = sample_all
616622
self.options["profiles_sampler"] = sample_all
623+
# data_collection was resolved in _get_options() before this
624+
# spotlight override flipped send_default_pii on. Re-derive it so
625+
# data_collection agrees with should_send_default_pii() in
626+
# DSN-less spotlight mode (only when the user did not set
627+
# data_collection explicitly).
628+
if not self.options["data_collection"]["provided_by_user"]:
629+
self.options["data_collection"] = _map_from_send_default_pii(
630+
send_default_pii=True,
631+
include_local_variables=self.options["include_local_variables"]
632+
is not False,
633+
include_source_context=self.options["include_source_context"]
634+
is not False,
635+
)
617636

618637
self.session_flusher = SessionFlusher(capture_func=_capture_envelope)
619638

sentry_sdk/consts.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class CompressionAlgo(Enum):
4545
from sentry_sdk._types import (
4646
BreadcrumbProcessor,
4747
ContinuousProfilerMode,
48+
DataCollectionUserOptions,
4849
Event,
4950
EventProcessor,
5051
Hint,
@@ -1278,6 +1279,7 @@ def __init__(
12781279
transport_queue_size: int = DEFAULT_QUEUE_SIZE,
12791280
sample_rate: float = 1.0,
12801281
send_default_pii: "Optional[bool]" = None,
1282+
data_collection: "Optional[DataCollectionUserOptions]" = None,
12811283
http_proxy: "Optional[str]" = None,
12821284
https_proxy: "Optional[str]" = None,
12831285
ignore_errors: "Sequence[Union[type, str]]" = [], # noqa: B006
@@ -1432,6 +1434,25 @@ def __init__(
14321434
If you enable this option, be sure to manually remove what you don't want to send using our features for
14331435
managing `Sensitive Data <https://docs.sentry.io/data-management/sensitive-data/>`_.
14341436
1437+
:param data_collection: (EXPERIMENTAL) Structured configuration controlling what data integrations collect automatically,
1438+
superseding `send_default_pii`. Pass a dict to enable or
1439+
restrict collection per category (user identity, cookies, HTTP headers/bodies, query params, generative AI
1440+
inputs/outputs, stack frame variables, source context).
1441+
1442+
When `data_collection` is set, omitted fields use their defaults (most categories are collected, with the
1443+
sensitive denylist scrubbing values). When it is not set, the SDK derives behaviour from `send_default_pii`
1444+
so that upgrading without configuring `data_collection` changes nothing. If both are set, `data_collection`
1445+
takes precedence.
1446+
1447+
Example::
1448+
1449+
sentry_sdk.init(
1450+
dsn="...",
1451+
data_collection={"user_info": False, "http_bodies": []},
1452+
)
1453+
1454+
See https://docs.sentry.io/platforms/python/configuration/options/#data_collection for more details.
1455+
14351456
:param event_scrubber: Scrubs the event payload for sensitive information such as cookies, sessions, and
14361457
passwords from a `denylist`.
14371458

0 commit comments

Comments
 (0)