Skip to content

Commit 3217cca

Browse files
authored
fix(integrations): Do not patch execute (#4026)
New Strawberry version removes the `execute` and `execute_sync` functions that we were monkeypatching in favor of integrating the code directly in `Schema.execute` and `Schema.execute_sync`. We were previously patching `execute` instead of `Schema.execute` that's calling it because that way we had access to a populated `execution_context` which contains data that we wanted to put on the event via an event processor. We have access to the `execution_context` directly in the extension hooks Strawberry provides, so we now add the event processor there instead of monkeypatching anything. This should also work for older Strawberry versions, so shouldn't be necessary to keep the old implementation around for compat. Closes #4037
1 parent 0cda7d9 commit 3217cca

File tree

5 files changed

+29
-55
lines changed

5 files changed

+29
-55
lines changed

Diff for: requirements-linting.txt

+1
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ openfeature-sdk
1919
launchdarkly-server-sdk
2020
UnleashClient
2121
typer
22+
strawberry-graphql

Diff for: sentry_sdk/integrations/ariadne.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
if TYPE_CHECKING:
2626
from typing import Any, Dict, List, Optional
2727
from ariadne.types import GraphQLError, GraphQLResult, GraphQLSchema, QueryParser # type: ignore
28-
from graphql.language.ast import DocumentNode # type: ignore
28+
from graphql.language.ast import DocumentNode
2929
from sentry_sdk._types import Event, EventProcessor
3030

3131

Diff for: sentry_sdk/integrations/gql.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@
1010

1111
try:
1212
import gql # type: ignore[import-not-found]
13-
from graphql import print_ast, get_operation_ast, DocumentNode, VariableDefinitionNode # type: ignore[import-not-found]
13+
from graphql import (
14+
print_ast,
15+
get_operation_ast,
16+
DocumentNode,
17+
VariableDefinitionNode,
18+
)
1419
from gql.transport import Transport, AsyncTransport # type: ignore[import-not-found]
1520
from gql.transport.exceptions import TransportQueryError # type: ignore[import-not-found]
1621
except ImportError:

Diff for: sentry_sdk/integrations/graphene.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222
from collections.abc import Generator
2323
from typing import Any, Dict, Union
2424
from graphene.language.source import Source # type: ignore
25-
from graphql.execution import ExecutionResult # type: ignore
26-
from graphql.type import GraphQLSchema # type: ignore
25+
from graphql.execution import ExecutionResult
26+
from graphql.type import GraphQLSchema
2727
from sentry_sdk._types import Event
2828

2929

Diff for: sentry_sdk/integrations/strawberry.py

+19-51
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,17 @@
2727
raise DidNotEnable("strawberry-graphql integration requires Python 3.8 or newer")
2828

2929
try:
30-
import strawberry.schema.schema as strawberry_schema # type: ignore
3130
from strawberry import Schema
32-
from strawberry.extensions import SchemaExtension # type: ignore
33-
from strawberry.extensions.tracing.utils import should_skip_tracing as strawberry_should_skip_tracing # type: ignore
34-
from strawberry.http import async_base_view, sync_base_view # type: ignore
31+
from strawberry.extensions import SchemaExtension
32+
from strawberry.extensions.tracing.utils import (
33+
should_skip_tracing as strawberry_should_skip_tracing,
34+
)
35+
from strawberry.http import async_base_view, sync_base_view
3536
except ImportError:
3637
raise DidNotEnable("strawberry-graphql is not installed")
3738

3839
try:
39-
from strawberry.extensions.tracing import ( # type: ignore
40+
from strawberry.extensions.tracing import (
4041
SentryTracingExtension as StrawberrySentryAsyncExtension,
4142
SentryTracingExtensionSync as StrawberrySentrySyncExtension,
4243
)
@@ -47,10 +48,10 @@
4748
from typing import TYPE_CHECKING
4849

4950
if TYPE_CHECKING:
50-
from typing import Any, Callable, Generator, List, Optional, Union
51-
from graphql import GraphQLError, GraphQLResolveInfo # type: ignore
51+
from typing import Any, Callable, Generator, List, Optional
52+
from graphql import GraphQLError, GraphQLResolveInfo
5253
from strawberry.http import GraphQLHTTPResponse
53-
from strawberry.types import ExecutionContext, ExecutionResult, SubscriptionExecutionResult # type: ignore
54+
from strawberry.types import ExecutionContext
5455
from sentry_sdk._types import Event, EventProcessor
5556

5657

@@ -78,7 +79,6 @@ def setup_once():
7879
_check_minimum_version(StrawberryIntegration, version, "strawberry-graphql")
7980

8081
_patch_schema_init()
81-
_patch_execute()
8282
_patch_views()
8383

8484

@@ -124,10 +124,10 @@ def _sentry_patched_schema_init(self, *args, **kwargs):
124124

125125
return old_schema_init(self, *args, **kwargs)
126126

127-
Schema.__init__ = _sentry_patched_schema_init
127+
Schema.__init__ = _sentry_patched_schema_init # type: ignore[method-assign]
128128

129129

130-
class SentryAsyncExtension(SchemaExtension): # type: ignore
130+
class SentryAsyncExtension(SchemaExtension):
131131
def __init__(
132132
self,
133133
*,
@@ -140,7 +140,7 @@ def __init__(
140140
@cached_property
141141
def _resource_name(self):
142142
# type: () -> str
143-
query_hash = self.hash_query(self.execution_context.query)
143+
query_hash = self.hash_query(self.execution_context.query) # type: ignore
144144

145145
if self.execution_context.operation_name:
146146
return "{}:{}".format(self.execution_context.operation_name, query_hash)
@@ -180,6 +180,10 @@ def on_operation(self):
180180
},
181181
)
182182

183+
scope = sentry_sdk.get_isolation_scope()
184+
event_processor = _make_request_event_processor(self.execution_context)
185+
scope.add_event_processor(event_processor)
186+
183187
span = sentry_sdk.get_current_span()
184188
if span:
185189
self.graphql_span = span.start_child(
@@ -287,41 +291,6 @@ def resolve(self, _next, root, info, *args, **kwargs):
287291
return _next(root, info, *args, **kwargs)
288292

289293

290-
def _patch_execute():
291-
# type: () -> None
292-
old_execute_async = strawberry_schema.execute
293-
old_execute_sync = strawberry_schema.execute_sync
294-
295-
async def _sentry_patched_execute_async(*args, **kwargs):
296-
# type: (Any, Any) -> Union[ExecutionResult, SubscriptionExecutionResult]
297-
result = await old_execute_async(*args, **kwargs)
298-
299-
if sentry_sdk.get_client().get_integration(StrawberryIntegration) is None:
300-
return result
301-
302-
if "execution_context" in kwargs:
303-
scope = sentry_sdk.get_isolation_scope()
304-
event_processor = _make_request_event_processor(kwargs["execution_context"])
305-
scope.add_event_processor(event_processor)
306-
307-
return result
308-
309-
@ensure_integration_enabled(StrawberryIntegration, old_execute_sync)
310-
def _sentry_patched_execute_sync(*args, **kwargs):
311-
# type: (Any, Any) -> ExecutionResult
312-
result = old_execute_sync(*args, **kwargs)
313-
314-
if "execution_context" in kwargs:
315-
scope = sentry_sdk.get_isolation_scope()
316-
event_processor = _make_request_event_processor(kwargs["execution_context"])
317-
scope.add_event_processor(event_processor)
318-
319-
return result
320-
321-
strawberry_schema.execute = _sentry_patched_execute_async
322-
strawberry_schema.execute_sync = _sentry_patched_execute_sync
323-
324-
325294
def _patch_views():
326295
# type: () -> None
327296
old_async_view_handle_errors = async_base_view.AsyncBaseHTTPView._handle_errors
@@ -359,10 +328,10 @@ def _sentry_patched_handle_errors(self, errors, response_data):
359328
)
360329
sentry_sdk.capture_event(event, hint=hint)
361330

362-
async_base_view.AsyncBaseHTTPView._handle_errors = (
331+
async_base_view.AsyncBaseHTTPView._handle_errors = ( # type: ignore[method-assign]
363332
_sentry_patched_async_view_handle_errors
364333
)
365-
sync_base_view.SyncBaseHTTPView._handle_errors = (
334+
sync_base_view.SyncBaseHTTPView._handle_errors = ( # type: ignore[method-assign]
366335
_sentry_patched_sync_view_handle_errors
367336
)
368337

@@ -378,8 +347,7 @@ def inner(event, hint):
378347
request_data["api_target"] = "graphql"
379348

380349
if not request_data.get("data"):
381-
data = {"query": execution_context.query}
382-
350+
data = {"query": execution_context.query} # type: dict[str, Any]
383351
if execution_context.variables:
384352
data["variables"] = execution_context.variables
385353
if execution_context.operation_name:

0 commit comments

Comments
 (0)