|
8 | 8 | from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version |
9 | 9 | from sentry_sdk.integrations.logging import ignore_logger |
10 | 10 | from sentry_sdk.scope import should_send_default_pii |
11 | | -from sentry_sdk.tracing import TransactionSource |
| 11 | +from sentry_sdk.traces import SegmentSource |
| 12 | +from sentry_sdk.tracing import Span, TransactionSource |
| 13 | +from sentry_sdk.tracing_utils import StreamedSpan, has_span_streaming_enabled |
12 | 14 | from sentry_sdk.utils import ( |
13 | 15 | capture_internal_exceptions, |
14 | 16 | ensure_integration_enabled, |
@@ -183,50 +185,111 @@ def on_operation(self) -> "Generator[None, None, None]": |
183 | 185 | event_processor = _make_request_event_processor(self.execution_context) |
184 | 186 | scope.add_event_processor(event_processor) |
185 | 187 |
|
186 | | - graphql_span = sentry_sdk.start_span( |
187 | | - op=op, |
188 | | - name=description, |
189 | | - origin=StrawberryIntegration.origin, |
190 | | - ) |
191 | | - graphql_span.__enter__() |
| 188 | + client = sentry_sdk.get_client() |
| 189 | + is_span_streaming_enabled = has_span_streaming_enabled(client.options) |
| 190 | + if is_span_streaming_enabled: |
| 191 | + additional_attributes: "dict[str, Any]" = {} |
| 192 | + |
| 193 | + if should_send_default_pii(): |
| 194 | + additional_attributes["graphql.document"] = self.execution_context.query |
| 195 | + |
| 196 | + if operation_name: |
| 197 | + additional_attributes["graphql.operation.name"] = operation_name |
| 198 | + |
| 199 | + graphql_span = sentry_sdk.traces.start_span( |
| 200 | + name=description, |
| 201 | + attributes={ |
| 202 | + "sentry.origin": StrawberryIntegration.origin, |
| 203 | + "sentry.op": op, |
| 204 | + "graphql.operation.type": operation_type, |
| 205 | + **additional_attributes, |
| 206 | + }, |
| 207 | + ) |
| 208 | + else: |
| 209 | + graphql_span = sentry_sdk.start_span( |
| 210 | + op=op, |
| 211 | + name=description, |
| 212 | + origin=StrawberryIntegration.origin, |
| 213 | + ) |
| 214 | + graphql_span.__enter__() |
| 215 | + |
| 216 | + if type(graphql_span) is Span: |
| 217 | + if should_send_default_pii(): |
| 218 | + graphql_span.set_data("graphql.document", self.execution_context.query) |
192 | 219 |
|
193 | | - graphql_span.set_data("graphql.operation.type", operation_type) |
194 | | - graphql_span.set_data("graphql.operation.name", operation_name) |
195 | | - if should_send_default_pii(): |
196 | | - graphql_span.set_data("graphql.document", self.execution_context.query) |
197 | | - graphql_span.set_data("graphql.resource_name", self._resource_name) |
| 220 | + graphql_span.set_data("graphql.operation.type", operation_type) |
| 221 | + graphql_span.set_data("graphql.operation.name", operation_name) |
| 222 | + # This attribute is being removed in streamed spans |
| 223 | + graphql_span.set_data("graphql.resource_name", self._resource_name) |
198 | 224 |
|
199 | 225 | yield |
200 | 226 |
|
201 | | - transaction = graphql_span.containing_transaction |
202 | | - if transaction and self.execution_context.operation_name: |
203 | | - transaction.name = self.execution_context.operation_name |
204 | | - transaction.source = TransactionSource.COMPONENT |
205 | | - transaction.op = op |
| 227 | + if type(graphql_span) is StreamedSpan: |
| 228 | + if self.execution_context.operation_name: |
| 229 | + segment = graphql_span._segment |
| 230 | + segment.set_attribute("sentry.span.source", SegmentSource.COMPONENT) |
| 231 | + segment.set_attribute("sentry.op", op) |
| 232 | + segment.name = self.execution_context.operation_name |
| 233 | + elif isinstance(graphql_span, Span): |
| 234 | + transaction = graphql_span.containing_transaction |
| 235 | + if transaction and self.execution_context.operation_name: |
| 236 | + transaction.name = self.execution_context.operation_name |
| 237 | + transaction.source = TransactionSource.COMPONENT |
| 238 | + transaction.op = op |
206 | 239 |
|
207 | 240 | graphql_span.__exit__(None, None, None) |
208 | 241 |
|
209 | 242 | def on_validate(self) -> "Generator[None, None, None]": |
210 | | - validation_span = sentry_sdk.start_span( |
211 | | - op=OP.GRAPHQL_VALIDATE, |
212 | | - name="validation", |
213 | | - origin=StrawberryIntegration.origin, |
214 | | - ) |
| 243 | + client = sentry_sdk.get_client() |
| 244 | + is_span_streaming_enabled = has_span_streaming_enabled(client.options) |
| 245 | + |
| 246 | + if is_span_streaming_enabled: |
| 247 | + validation_span = sentry_sdk.traces.start_span( |
| 248 | + name="validation", |
| 249 | + attributes={ |
| 250 | + "sentry.op": OP.GRAPHQL_VALIDATE, |
| 251 | + "sentry.origin": StrawberryIntegration.origin, |
| 252 | + }, |
| 253 | + ) |
| 254 | + else: |
| 255 | + validation_span = sentry_sdk.start_span( |
| 256 | + op=OP.GRAPHQL_VALIDATE, |
| 257 | + name="validation", |
| 258 | + origin=StrawberryIntegration.origin, |
| 259 | + ) |
215 | 260 |
|
216 | 261 | yield |
217 | 262 |
|
218 | | - validation_span.finish() |
| 263 | + if isinstance(validation_span, StreamedSpan): |
| 264 | + validation_span.end() |
| 265 | + else: |
| 266 | + validation_span.finish() |
219 | 267 |
|
220 | 268 | def on_parse(self) -> "Generator[None, None, None]": |
221 | | - parsing_span = sentry_sdk.start_span( |
222 | | - op=OP.GRAPHQL_PARSE, |
223 | | - name="parsing", |
224 | | - origin=StrawberryIntegration.origin, |
225 | | - ) |
| 269 | + client = sentry_sdk.get_client() |
| 270 | + is_span_streaming_enabled = has_span_streaming_enabled(client.options) |
| 271 | + |
| 272 | + if is_span_streaming_enabled: |
| 273 | + parsing_span = sentry_sdk.traces.start_span( |
| 274 | + name="parsing", |
| 275 | + attributes={ |
| 276 | + "sentry.op": OP.GRAPHQL_PARSE, |
| 277 | + "sentry.origin": StrawberryIntegration.origin, |
| 278 | + }, |
| 279 | + ) |
| 280 | + else: |
| 281 | + parsing_span = sentry_sdk.start_span( |
| 282 | + op=OP.GRAPHQL_PARSE, |
| 283 | + name="parsing", |
| 284 | + origin=StrawberryIntegration.origin, |
| 285 | + ) |
226 | 286 |
|
227 | 287 | yield |
228 | 288 |
|
229 | | - parsing_span.finish() |
| 289 | + if isinstance(parsing_span, StreamedSpan): |
| 290 | + parsing_span.end() |
| 291 | + else: |
| 292 | + parsing_span.finish() |
230 | 293 |
|
231 | 294 | def should_skip_tracing( |
232 | 295 | self, |
@@ -263,6 +326,18 @@ async def resolve( |
263 | 326 |
|
264 | 327 | field_path = "{}.{}".format(info.parent_type, info.field_name) |
265 | 328 |
|
| 329 | + client = sentry_sdk.get_client() |
| 330 | + is_span_streaming_enabled = has_span_streaming_enabled(client.options) |
| 331 | + if is_span_streaming_enabled: |
| 332 | + with sentry_sdk.traces.start_span( |
| 333 | + name=f"resolving {field_path}", |
| 334 | + attributes={ |
| 335 | + "sentry.origin": StrawberryIntegration.origin, |
| 336 | + "sentry.op": OP.GRAPHQL_RESOLVE, |
| 337 | + }, |
| 338 | + ): |
| 339 | + return await self._resolve(_next, root, info, *args, **kwargs) |
| 340 | + |
266 | 341 | with sentry_sdk.start_span( |
267 | 342 | op=OP.GRAPHQL_RESOLVE, |
268 | 343 | name="resolving {}".format(field_path), |
@@ -290,6 +365,18 @@ def resolve( |
290 | 365 |
|
291 | 366 | field_path = "{}.{}".format(info.parent_type, info.field_name) |
292 | 367 |
|
| 368 | + client = sentry_sdk.get_client() |
| 369 | + is_span_streaming_enabled = has_span_streaming_enabled(client.options) |
| 370 | + if is_span_streaming_enabled: |
| 371 | + with sentry_sdk.traces.start_span( |
| 372 | + name=f"resolving {field_path}", |
| 373 | + attributes={ |
| 374 | + "sentry.origin": StrawberryIntegration.origin, |
| 375 | + "sentry.op": OP.GRAPHQL_RESOLVE, |
| 376 | + }, |
| 377 | + ): |
| 378 | + return _next(root, info, *args, **kwargs) |
| 379 | + |
293 | 380 | with sentry_sdk.start_span( |
294 | 381 | op=OP.GRAPHQL_RESOLVE, |
295 | 382 | name="resolving {}".format(field_path), |
|
0 commit comments