Skip to content

Commit bec74d8

Browse files
committed
Merge branch 'major/3.0' into ivana/major/remove-data-collection-from-experiments
2 parents e9b256f + dd7a983 commit bec74d8

32 files changed

Lines changed: 309 additions & 846 deletions

File tree

‎MIGRATION_GUIDE.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ Looking to upgrade from Sentry SDK 2.x to 3.x? Here's a comprehensive list of wh
164164
- `add_attachment` no longer accepts an `add_to_transactions` argument.
165165
- The `stream_gen_ai_spans` option was removed. All spans are streamed now.
166166
- The `data_collection` option is no longer accessible under `_experiments`. Use it as a top-level option instead.
167+
- The experimental `record_sql_params` option was removed. Use the `database_query_data` setting of `data_collection` instead.
168+
- The `record_params` option of `AsyncPGIntegration` and `AioMySQLIntegration` was removed. Use the `database_query_data` setting of `data_collection` instead.
167169

168170

169171
## Deprecated

‎sentry_sdk/client.py‎

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
)
2525
from sentry_sdk.envelope import Envelope, Item
2626
from sentry_sdk.integrations import setup_integrations
27-
from sentry_sdk.integrations.dedupe import DedupeIntegration
2827
from sentry_sdk.monitor import Monitor
2928
from sentry_sdk.profiler.continuous_profiler import setup_continuous_profiler
3029
from sentry_sdk.serializer import serialize
@@ -594,13 +593,6 @@ def _prepare_event(
594593
)
595594
self.transport.record_lost_event(reason, data_category="error")
596595

597-
# If this is an exception, reset the DedupeIntegration. It still
598-
# remembers the dropped exception as the last exception, meaning
599-
# that if the same exception happens again and is not dropped
600-
# in before_send, it'd get dropped by DedupeIntegration.
601-
if event.get("exception"):
602-
DedupeIntegration.reset_last_seen()
603-
604596
event = new_event
605597

606598
return event

‎sentry_sdk/consts.py‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ class CompressionAlgo(Enum):
6565
"Experiments",
6666
{
6767
"max_flags": Optional[int],
68-
"record_sql_params": Optional[bool],
6968
"continuous_profiling_auto_start": Optional[bool],
7069
"transport_zlib_compression_level": Optional[int],
7170
"transport_compression_level": Optional[int],
@@ -575,6 +574,12 @@ class SPANDATA:
575574
Example: "qa-pipeline"
576575
"""
577576

577+
GEN_AI_PROMPT_NAME = "gen_ai.prompt.name"
578+
"""
579+
The name of the prompt that uniquely identifies it.
580+
Example: "summarize_text"
581+
"""
582+
578583
GEN_AI_RESPONSE_FINISH_REASONS = "gen_ai.response.finish_reasons"
579584
"""
580585
The reason why the model stopped generating.
@@ -1086,12 +1091,18 @@ class SPANDATA:
10861091

10871092
MCP_TOOL_NAME = "mcp.tool.name"
10881093
"""
1094+
.. deprecated::
1095+
This attribute is deprecated. Use GEN_AI_TOOL_NAME instead.
1096+
10891097
The name of the MCP tool being called.
10901098
Example: "get_weather"
10911099
"""
10921100

10931101
MCP_PROMPT_NAME = "mcp.prompt.name"
10941102
"""
1103+
.. deprecated::
1104+
This attribute is deprecated. Use GEN_AI_PROMPT_NAME instead.
1105+
10951106
The name of the MCP prompt being retrieved.
10961107
Example: "code_review"
10971108
"""
@@ -1116,6 +1127,9 @@ class SPANDATA:
11161127

11171128
MCP_TOOL_RESULT_CONTENT = "mcp.tool.result.content"
11181129
"""
1130+
.. deprecated::
1131+
This attribute is deprecated. Use GEN_AI_TOOL_CALL_RESULT instead.
1132+
11191133
The result/output content from an MCP tool execution.
11201134
Example: "The weather is sunny"
11211135
"""

‎sentry_sdk/integrations/aiomysql.py‎

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
)
1414
from sentry_sdk.utils import (
1515
capture_internal_exceptions,
16-
has_data_collection_enabled,
1716
parse_version,
1817
)
1918

@@ -28,10 +27,6 @@
2827
class AioMySQLIntegration(Integration):
2928
identifier = "aiomysql"
3029
origin = f"auto.db.{identifier}"
31-
_record_params = False
32-
33-
def __init__(self, *, record_params: bool = False):
34-
AioMySQLIntegration._record_params = record_params
3530

3631
@staticmethod
3732
def setup_once() -> None:
@@ -84,12 +79,7 @@ async def _inner(*args: Any, **kwargs: Any) -> T:
8479
integration = sentry_sdk.get_client().get_integration(AioMySQLIntegration)
8580

8681
client = sentry_sdk.get_client()
87-
should_record_params = False
88-
if has_data_collection_enabled(client.options):
89-
if client.options["data_collection"]["database_query_data"]:
90-
should_record_params = True
91-
else:
92-
should_record_params = integration._record_params if integration else False
82+
should_record_params = client.options["data_collection"]["database_query_data"]
9383

9484
params_list = params if integration and should_record_params else None
9585
param_style = "pyformat" if params_list else None
@@ -134,12 +124,7 @@ async def _inner(*args: Any, **kwargs: Any) -> T:
134124

135125
integration = sentry_sdk.get_client().get_integration(AioMySQLIntegration)
136126
client = sentry_sdk.get_client()
137-
should_record_params = False
138-
if has_data_collection_enabled(client.options):
139-
if client.options["data_collection"]["database_query_data"]:
140-
should_record_params = True
141-
else:
142-
should_record_params = integration._record_params if integration else False
127+
should_record_params = client.options["data_collection"]["database_query_data"]
143128

144129
params_list = seq_of_params if integration and should_record_params else None
145130
param_style = "pyformat" if params_list else None

‎sentry_sdk/integrations/asyncpg.py‎

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,6 @@
3232
class AsyncPGIntegration(Integration):
3333
identifier = "asyncpg"
3434
origin = f"auto.db.{identifier}"
35-
_record_params = False
36-
37-
def __init__(self, *, record_params: bool = False):
38-
AsyncPGIntegration._record_params = record_params
3935

4036
@staticmethod
4137
def setup_once() -> None:
@@ -114,7 +110,10 @@ def _record(
114110
) -> "Iterator[Span]":
115111
client = sentry_sdk.get_client()
116112
integration = client.get_integration(AsyncPGIntegration)
117-
if integration is not None and not integration._record_params:
113+
if (
114+
integration is not None
115+
and not client.options["data_collection"]["database_query_data"]
116+
):
118117
params_list = None
119118

120119
param_style = "pyformat" if params_list else None

‎sentry_sdk/integrations/dedupe.py‎

Lines changed: 8 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,19 @@
1-
import weakref
2-
from contextvars import ContextVar
31
from typing import TYPE_CHECKING
42

53
import sentry_sdk
64
from sentry_sdk.integrations import Integration
75
from sentry_sdk.scope import add_global_event_processor
8-
from sentry_sdk.utils import logger
6+
from sentry_sdk.utils import capture_internal_exceptions, logger
97

108
if TYPE_CHECKING:
11-
from typing import Any, Optional
9+
from typing import Optional
1210

1311
from sentry_sdk._types import Event, Hint
1412

1513

1614
class DedupeIntegration(Integration):
1715
identifier = "dedupe"
1816

19-
def __init__(self) -> None:
20-
self._last_seen: "ContextVar[Any]" = ContextVar("last-seen")
21-
2217
@staticmethod
2318
def setup_once() -> None:
2419
@add_global_event_processor
@@ -34,30 +29,12 @@ def processor(event: "Event", hint: "Optional[Hint]") -> "Optional[Event]":
3429
if exc_info is None:
3530
return event
3631

37-
last_seen = integration._last_seen.get(None)
38-
if last_seen is not None:
39-
# last_seen is either a weakref or the original instance
40-
last_seen = (
41-
last_seen() if isinstance(last_seen, weakref.ref) else last_seen
42-
)
43-
4432
exc = exc_info[1]
45-
if last_seen is exc:
33+
34+
if getattr(exc, "_handled_by_sentry", False):
4635
logger.info("DedupeIntegration dropped duplicated error event %s", exc)
4736
return None
48-
49-
# we can only weakref non builtin types
50-
try:
51-
integration._last_seen.set(weakref.ref(exc))
52-
except TypeError:
53-
integration._last_seen.set(exc)
54-
55-
return event
56-
57-
@staticmethod
58-
def reset_last_seen() -> None:
59-
integration = sentry_sdk.get_client().get_integration(DedupeIntegration)
60-
if integration is None:
61-
return
62-
63-
integration._last_seen.set(None)
37+
else:
38+
with capture_internal_exceptions():
39+
exc._handled_by_sentry = True
40+
return event

‎sentry_sdk/integrations/gcp.py‎

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,13 @@
1111
from sentry_sdk.integrations import Integration
1212
from sentry_sdk.integrations._wsgi_common import _filter_headers
1313
from sentry_sdk.integrations.cloud_resource_context import CLOUD_PROVIDER
14-
from sentry_sdk.scope import Scope, should_send_default_pii
14+
from sentry_sdk.scope import Scope
1515
from sentry_sdk.traces import SegmentNameSource
1616
from sentry_sdk.utils import (
1717
AnnotatedValue,
1818
TimeoutThread,
1919
capture_internal_exceptions,
2020
event_from_exception,
21-
has_data_collection_enabled,
2221
logger,
2322
reraise,
2423
)
@@ -98,17 +97,12 @@ def sentry_func(
9897
if hasattr(gcp_event, "query_string"):
9998
query_string = gcp_event.query_string.decode("utf-8", errors="replace")
10099
if query_string:
101-
if has_data_collection_enabled(client.options):
102-
filtered_qs = _apply_data_collection_filtering_to_query_string(
103-
query_string=query_string,
104-
behaviour=client.options["data_collection"][
105-
"url_query_params"
106-
],
107-
)
108-
if filtered_qs:
109-
additional_attributes["url.query"] = filtered_qs
110-
elif should_send_default_pii():
111-
additional_attributes["url.query"] = query_string
100+
filtered_qs = _apply_data_collection_filtering_to_query_string(
101+
query_string=query_string,
102+
behaviour=client.options["data_collection"]["url_query_params"],
103+
)
104+
if filtered_qs:
105+
additional_attributes["url.query"] = filtered_qs
112106

113107
sampling_context = {
114108
"gcp_env": {
@@ -229,28 +223,19 @@ def event_processor(event: "Event", hint: "Hint") -> "Optional[Event]":
229223

230224
if hasattr(gcp_event, "query_string"):
231225
query_string = gcp_event.query_string.decode("utf-8", errors="replace")
232-
if has_data_collection_enabled(client_options):
233-
if query_string:
234-
filtered_qs = _apply_data_collection_filtering_to_query_string(
235-
query_string=query_string,
236-
behaviour=client_options["data_collection"]["url_query_params"],
237-
)
238-
if filtered_qs:
239-
request["query_string"] = filtered_qs
240-
else:
241-
request["query_string"] = query_string
226+
if query_string:
227+
filtered_qs = _apply_data_collection_filtering_to_query_string(
228+
query_string=query_string,
229+
behaviour=client_options["data_collection"]["url_query_params"],
230+
)
231+
if filtered_qs:
232+
request["query_string"] = filtered_qs
242233

243234
if hasattr(gcp_event, "headers"):
244235
request["headers"] = _filter_headers(gcp_event.headers)
245236

246237
if hasattr(gcp_event, "data"):
247-
if has_data_collection_enabled(client_options):
248-
if (
249-
"incoming_request"
250-
in client_options["data_collection"]["http_bodies"]
251-
):
252-
request["data"] = gcp_event.data
253-
elif should_send_default_pii():
238+
if "incoming_request" in client_options["data_collection"]["http_bodies"]:
254239
request["data"] = gcp_event.data
255240
else:
256241
# Unfortunately couldn't find a way to get structured body from GCP

‎sentry_sdk/integrations/google_genai/utils.py‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -710,7 +710,7 @@ async def async_wrapped(*args: "Any", **kwargs: "Any") -> "Any":
710710
tool_input = _capture_tool_input(args, kwargs, tool)
711711
with capture_internal_exceptions():
712712
span.set_attribute(
713-
SPANDATA.GEN_AI_TOOL_INPUT, safe_serialize(tool_input)
713+
SPANDATA.GEN_AI_TOOL_CALL_ARGUMENTS, safe_serialize(tool_input)
714714
)
715715

716716
try:
@@ -719,7 +719,7 @@ async def async_wrapped(*args: "Any", **kwargs: "Any") -> "Any":
719719
# Capture tool output
720720
with capture_internal_exceptions():
721721
span.set_attribute(
722-
SPANDATA.GEN_AI_TOOL_OUTPUT, safe_serialize(result)
722+
SPANDATA.GEN_AI_TOOL_CALL_RESULT, safe_serialize(result)
723723
)
724724

725725
return result
@@ -737,7 +737,7 @@ def sync_wrapped(*args: "Any", **kwargs: "Any") -> "Any":
737737
tool_input = _capture_tool_input(args, kwargs, tool)
738738
with capture_internal_exceptions():
739739
span.set_attribute(
740-
SPANDATA.GEN_AI_TOOL_INPUT, safe_serialize(tool_input)
740+
SPANDATA.GEN_AI_TOOL_CALL_ARGUMENTS, safe_serialize(tool_input)
741741
)
742742

743743
try:
@@ -746,7 +746,7 @@ def sync_wrapped(*args: "Any", **kwargs: "Any") -> "Any":
746746
# Capture tool output
747747
with capture_internal_exceptions():
748748
span.set_attribute(
749-
SPANDATA.GEN_AI_TOOL_OUTPUT, safe_serialize(result)
749+
SPANDATA.GEN_AI_TOOL_CALL_RESULT, safe_serialize(result)
750750
)
751751

752752
return result

‎sentry_sdk/integrations/gql.py‎

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import sentry_sdk
22
from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version
3-
from sentry_sdk.scope import should_send_default_pii
43
from sentry_sdk.utils import (
54
ensure_integration_enabled,
65
event_from_exception,
7-
has_data_collection_enabled,
86
parse_version,
97
)
108

@@ -61,10 +59,7 @@ def _data_from_document(document: "DocumentNode") -> "EventDataType":
6159
data: "EventDataType" = {"query": print_ast(document)}
6260

6361
if operation_ast is not None:
64-
if has_data_collection_enabled(client_options):
65-
if client_options["data_collection"]["graphql"]["variables"]:
66-
data["variables"] = operation_ast.variable_definitions
67-
elif should_send_default_pii():
62+
if client_options["data_collection"]["graphql"]["variables"]:
6863
data["variables"] = operation_ast.variable_definitions
6964

7065
if operation_ast.name is not None:
@@ -155,29 +150,7 @@ def processor(event: "Event", hint: "dict[str, Any]") -> "Event":
155150
)
156151

157152
client_options = sentry_sdk.get_client().options
158-
if has_data_collection_enabled(client_options):
159-
if client_options["data_collection"]["graphql"]["document"]:
160-
if GraphQLRequest is not None and isinstance(
161-
document_or_request, GraphQLRequest
162-
):
163-
# In v4.0.0, gql moved to using GraphQLRequest instead of
164-
# DocumentNode in execute
165-
# https://github.com/graphql-python/gql/pull/556
166-
document = document_or_request.document
167-
else:
168-
document = document_or_request
169-
170-
request["data"] = _data_from_document(document)
171-
contexts = event.setdefault("contexts", {})
172-
response = contexts.setdefault("response", {})
173-
response.update(
174-
{
175-
"data": {"errors": errors},
176-
"type": response,
177-
}
178-
)
179-
180-
elif should_send_default_pii():
153+
if client_options["data_collection"]["graphql"]["document"]:
181154
if GraphQLRequest is not None and isinstance(
182155
document_or_request, GraphQLRequest
183156
):

‎sentry_sdk/integrations/langchain.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -735,7 +735,7 @@ def on_tool_start(
735735

736736
set_data_normalized(
737737
span,
738-
SPANDATA.GEN_AI_TOOL_INPUT,
738+
SPANDATA.GEN_AI_TOOL_CALL_ARGUMENTS,
739739
kwargs.get("inputs", [input_str]),
740740
)
741741

@@ -755,7 +755,7 @@ def on_tool_end(
755755
)
756756

757757
if sentry_sdk.get_client().options["data_collection"]["gen_ai"]["outputs"]:
758-
set_data_normalized(span, SPANDATA.GEN_AI_TOOL_OUTPUT, output)
758+
set_data_normalized(span, SPANDATA.GEN_AI_TOOL_CALL_RESULT, output)
759759

760760
self._exit_span(span, run_id)
761761

0 commit comments

Comments
 (0)