sentry-sdk 2.30.0__py2.py3-none-any.whl → 3.0.0a2__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of sentry-sdk might be problematic. Click here for more details.

Files changed (109) hide show
  1. sentry_sdk/__init__.py +3 -8
  2. sentry_sdk/_compat.py +0 -1
  3. sentry_sdk/_init_implementation.py +6 -44
  4. sentry_sdk/_types.py +2 -64
  5. sentry_sdk/ai/monitoring.py +14 -10
  6. sentry_sdk/ai/utils.py +1 -1
  7. sentry_sdk/api.py +56 -169
  8. sentry_sdk/client.py +27 -72
  9. sentry_sdk/consts.py +60 -23
  10. sentry_sdk/debug.py +0 -10
  11. sentry_sdk/envelope.py +1 -3
  12. sentry_sdk/feature_flags.py +1 -1
  13. sentry_sdk/integrations/__init__.py +4 -2
  14. sentry_sdk/integrations/_asgi_common.py +5 -6
  15. sentry_sdk/integrations/_wsgi_common.py +11 -40
  16. sentry_sdk/integrations/aiohttp.py +104 -57
  17. sentry_sdk/integrations/anthropic.py +10 -7
  18. sentry_sdk/integrations/arq.py +24 -13
  19. sentry_sdk/integrations/asgi.py +102 -83
  20. sentry_sdk/integrations/asyncio.py +1 -0
  21. sentry_sdk/integrations/asyncpg.py +45 -30
  22. sentry_sdk/integrations/aws_lambda.py +109 -92
  23. sentry_sdk/integrations/boto3.py +38 -9
  24. sentry_sdk/integrations/bottle.py +1 -1
  25. sentry_sdk/integrations/celery/__init__.py +51 -41
  26. sentry_sdk/integrations/clickhouse_driver.py +59 -28
  27. sentry_sdk/integrations/cohere.py +2 -0
  28. sentry_sdk/integrations/django/__init__.py +25 -46
  29. sentry_sdk/integrations/django/asgi.py +6 -2
  30. sentry_sdk/integrations/django/caching.py +13 -22
  31. sentry_sdk/integrations/django/middleware.py +1 -0
  32. sentry_sdk/integrations/django/signals_handlers.py +3 -1
  33. sentry_sdk/integrations/django/templates.py +8 -12
  34. sentry_sdk/integrations/django/transactions.py +1 -6
  35. sentry_sdk/integrations/django/views.py +5 -2
  36. sentry_sdk/integrations/falcon.py +7 -25
  37. sentry_sdk/integrations/fastapi.py +3 -3
  38. sentry_sdk/integrations/flask.py +1 -1
  39. sentry_sdk/integrations/gcp.py +63 -38
  40. sentry_sdk/integrations/graphene.py +6 -13
  41. sentry_sdk/integrations/grpc/aio/client.py +14 -8
  42. sentry_sdk/integrations/grpc/aio/server.py +19 -21
  43. sentry_sdk/integrations/grpc/client.py +8 -6
  44. sentry_sdk/integrations/grpc/server.py +12 -14
  45. sentry_sdk/integrations/httpx.py +47 -12
  46. sentry_sdk/integrations/huey.py +26 -22
  47. sentry_sdk/integrations/huggingface_hub.py +1 -0
  48. sentry_sdk/integrations/langchain.py +22 -15
  49. sentry_sdk/integrations/litestar.py +4 -2
  50. sentry_sdk/integrations/logging.py +7 -2
  51. sentry_sdk/integrations/openai.py +2 -0
  52. sentry_sdk/integrations/pymongo.py +18 -25
  53. sentry_sdk/integrations/pyramid.py +1 -1
  54. sentry_sdk/integrations/quart.py +3 -3
  55. sentry_sdk/integrations/ray.py +23 -17
  56. sentry_sdk/integrations/redis/_async_common.py +29 -18
  57. sentry_sdk/integrations/redis/_sync_common.py +28 -19
  58. sentry_sdk/integrations/redis/modules/caches.py +13 -10
  59. sentry_sdk/integrations/redis/modules/queries.py +14 -11
  60. sentry_sdk/integrations/redis/rb.py +4 -4
  61. sentry_sdk/integrations/redis/redis.py +6 -6
  62. sentry_sdk/integrations/redis/redis_cluster.py +18 -18
  63. sentry_sdk/integrations/redis/redis_py_cluster_legacy.py +4 -4
  64. sentry_sdk/integrations/redis/utils.py +64 -24
  65. sentry_sdk/integrations/rq.py +68 -23
  66. sentry_sdk/integrations/rust_tracing.py +28 -43
  67. sentry_sdk/integrations/sanic.py +23 -13
  68. sentry_sdk/integrations/socket.py +9 -5
  69. sentry_sdk/integrations/sqlalchemy.py +8 -8
  70. sentry_sdk/integrations/starlette.py +11 -31
  71. sentry_sdk/integrations/starlite.py +4 -2
  72. sentry_sdk/integrations/stdlib.py +56 -9
  73. sentry_sdk/integrations/strawberry.py +40 -59
  74. sentry_sdk/integrations/threading.py +10 -26
  75. sentry_sdk/integrations/tornado.py +57 -18
  76. sentry_sdk/integrations/trytond.py +4 -1
  77. sentry_sdk/integrations/wsgi.py +84 -38
  78. sentry_sdk/opentelemetry/__init__.py +9 -0
  79. sentry_sdk/opentelemetry/consts.py +33 -0
  80. sentry_sdk/opentelemetry/contextvars_context.py +81 -0
  81. sentry_sdk/{integrations/opentelemetry → opentelemetry}/propagator.py +19 -28
  82. sentry_sdk/opentelemetry/sampler.py +326 -0
  83. sentry_sdk/opentelemetry/scope.py +218 -0
  84. sentry_sdk/opentelemetry/span_processor.py +335 -0
  85. sentry_sdk/opentelemetry/tracing.py +59 -0
  86. sentry_sdk/opentelemetry/utils.py +484 -0
  87. sentry_sdk/profiler/__init__.py +0 -40
  88. sentry_sdk/profiler/continuous_profiler.py +1 -30
  89. sentry_sdk/profiler/transaction_profiler.py +5 -56
  90. sentry_sdk/scope.py +108 -361
  91. sentry_sdk/sessions.py +0 -87
  92. sentry_sdk/tracing.py +415 -1161
  93. sentry_sdk/tracing_utils.py +130 -166
  94. sentry_sdk/transport.py +4 -104
  95. sentry_sdk/utils.py +169 -152
  96. {sentry_sdk-2.30.0.dist-info → sentry_sdk-3.0.0a2.dist-info}/METADATA +3 -5
  97. sentry_sdk-3.0.0a2.dist-info/RECORD +154 -0
  98. sentry_sdk-3.0.0a2.dist-info/entry_points.txt +2 -0
  99. sentry_sdk/hub.py +0 -739
  100. sentry_sdk/integrations/opentelemetry/__init__.py +0 -7
  101. sentry_sdk/integrations/opentelemetry/consts.py +0 -5
  102. sentry_sdk/integrations/opentelemetry/integration.py +0 -58
  103. sentry_sdk/integrations/opentelemetry/span_processor.py +0 -391
  104. sentry_sdk/metrics.py +0 -965
  105. sentry_sdk-2.30.0.dist-info/RECORD +0 -152
  106. sentry_sdk-2.30.0.dist-info/entry_points.txt +0 -2
  107. {sentry_sdk-2.30.0.dist-info → sentry_sdk-3.0.0a2.dist-info}/WHEEL +0 -0
  108. {sentry_sdk-2.30.0.dist-info → sentry_sdk-3.0.0a2.dist-info}/licenses/LICENSE +0 -0
  109. {sentry_sdk-2.30.0.dist-info → sentry_sdk-3.0.0a2.dist-info}/top_level.txt +0 -0
@@ -50,6 +50,7 @@ def patch_signals():
50
50
 
51
51
  old_live_receivers = Signal._live_receivers
52
52
 
53
+ @wraps(old_live_receivers)
53
54
  def _sentry_live_receivers(self, sender):
54
55
  # type: (Signal, Any) -> Union[tuple[list[Callable[..., Any]], list[Callable[..., Any]]], list[Callable[..., Any]]]
55
56
  if DJANGO_VERSION >= (5, 0):
@@ -68,8 +69,9 @@ def patch_signals():
68
69
  op=OP.EVENT_DJANGO,
69
70
  name=signal_name,
70
71
  origin=DjangoIntegration.origin,
72
+ only_if_parent=True,
71
73
  ) as span:
72
- span.set_data("signal", signal_name)
74
+ span.set_attribute("signal", signal_name)
73
75
  return receiver(*args, **kwargs)
74
76
 
75
77
  return wrapper
@@ -1,8 +1,8 @@
1
1
  import functools
2
2
 
3
3
  from django.template import TemplateSyntaxError
4
+ from django.template.base import Origin
4
5
  from django.utils.safestring import mark_safe
5
- from django import VERSION as DJANGO_VERSION
6
6
 
7
7
  import sentry_sdk
8
8
  from sentry_sdk.consts import OP
@@ -17,13 +17,6 @@ if TYPE_CHECKING:
17
17
  from typing import Iterator
18
18
  from typing import Tuple
19
19
 
20
- try:
21
- # support Django 1.9
22
- from django.template.base import Origin
23
- except ImportError:
24
- # backward compatibility
25
- from django.template.loader import LoaderOrigin as Origin
26
-
27
20
 
28
21
  def get_template_frame_from_exception(exc_value):
29
22
  # type: (Optional[BaseException]) -> Optional[Dict[str, Any]]
@@ -72,14 +65,15 @@ def patch_templates():
72
65
  op=OP.TEMPLATE_RENDER,
73
66
  name=_get_template_name_description(self.template_name),
74
67
  origin=DjangoIntegration.origin,
68
+ only_if_parent=True,
75
69
  ) as span:
76
- span.set_data("context", self.context_data)
70
+ if isinstance(self.context_data, dict):
71
+ for k, v in self.context_data.items():
72
+ span.set_attribute(f"context.{k}", v)
77
73
  return real_rendered_content.fget(self)
78
74
 
79
75
  SimpleTemplateResponse.rendered_content = rendered_content
80
76
 
81
- if DJANGO_VERSION < (1, 7):
82
- return
83
77
  import django.shortcuts
84
78
 
85
79
  real_render = django.shortcuts.render
@@ -100,8 +94,10 @@ def patch_templates():
100
94
  op=OP.TEMPLATE_RENDER,
101
95
  name=_get_template_name_description(template_name),
102
96
  origin=DjangoIntegration.origin,
97
+ only_if_parent=True,
103
98
  ) as span:
104
- span.set_data("context", context)
99
+ for k, v in context.items():
100
+ span.set_attribute(f"context.{k}", v)
105
101
  return real_render(request, template_name, context, *args, **kwargs)
106
102
 
107
103
  django.shortcuts.render = render
@@ -19,12 +19,7 @@ if TYPE_CHECKING:
19
19
  from typing import Union
20
20
  from re import Pattern
21
21
 
22
- from django import VERSION as DJANGO_VERSION
23
-
24
- if DJANGO_VERSION >= (2, 0):
25
- from django.urls.resolvers import RoutePattern
26
- else:
27
- RoutePattern = None
22
+ from django.urls.resolvers import RoutePattern
28
23
 
29
24
  try:
30
25
  from django.urls import get_resolver
@@ -31,12 +31,14 @@ def patch_views():
31
31
  old_make_view_atomic = BaseHandler.make_view_atomic
32
32
  old_render = SimpleTemplateResponse.render
33
33
 
34
+ @functools.wraps(old_render)
34
35
  def sentry_patched_render(self):
35
36
  # type: (SimpleTemplateResponse) -> Any
36
37
  with sentry_sdk.start_span(
37
38
  op=OP.VIEW_RESPONSE_RENDER,
38
39
  name="serialize response",
39
40
  origin=DjangoIntegration.origin,
41
+ only_if_parent=True,
40
42
  ):
41
43
  return old_render(self)
42
44
 
@@ -77,8 +79,8 @@ def _wrap_sync_view(callback):
77
79
  def sentry_wrapped_callback(request, *args, **kwargs):
78
80
  # type: (Any, *Any, **Any) -> Any
79
81
  current_scope = sentry_sdk.get_current_scope()
80
- if current_scope.transaction is not None:
81
- current_scope.transaction.update_active_thread()
82
+ if current_scope.root_span is not None:
83
+ current_scope.root_span.update_active_thread()
82
84
 
83
85
  sentry_scope = sentry_sdk.get_isolation_scope()
84
86
  # set the active thread id to the handler thread for sync views
@@ -90,6 +92,7 @@ def _wrap_sync_view(callback):
90
92
  op=OP.VIEW_RENDER,
91
93
  name=request.resolver_match.view_name,
92
94
  origin=DjangoIntegration.origin,
95
+ only_if_parent=True,
93
96
  ):
94
97
  return callback(request, *args, **kwargs)
95
98
 
@@ -1,8 +1,8 @@
1
1
  import sentry_sdk
2
+ from sentry_sdk.consts import SOURCE_FOR_STYLE
2
3
  from sentry_sdk.integrations import _check_minimum_version, Integration, DidNotEnable
3
4
  from sentry_sdk.integrations._wsgi_common import RequestExtractor
4
5
  from sentry_sdk.integrations.wsgi import SentryWsgiMiddleware
5
- from sentry_sdk.tracing import SOURCE_FOR_STYLE
6
6
  from sentry_sdk.utils import (
7
7
  capture_internal_exceptions,
8
8
  ensure_integration_enabled,
@@ -19,8 +19,6 @@ if TYPE_CHECKING:
19
19
 
20
20
  from sentry_sdk._types import Event, EventProcessor
21
21
 
22
- # In Falcon 3.0 `falcon.api_helpers` is renamed to `falcon.app_helpers`
23
- # and `falcon.API` to `falcon.App`
24
22
 
25
23
  try:
26
24
  import falcon # type: ignore
@@ -29,24 +27,15 @@ try:
29
27
  except ImportError:
30
28
  raise DidNotEnable("Falcon not installed")
31
29
 
32
- try:
33
- import falcon.app_helpers # type: ignore
34
-
35
- falcon_helpers = falcon.app_helpers
36
- falcon_app_class = falcon.App
37
- FALCON3 = True
38
- except ImportError:
39
- import falcon.api_helpers # type: ignore
30
+ import falcon.app_helpers # type: ignore
40
31
 
41
- falcon_helpers = falcon.api_helpers
42
- falcon_app_class = falcon.API
43
- FALCON3 = False
32
+ falcon_helpers = falcon.app_helpers
33
+ falcon_app_class = falcon.App
44
34
 
45
35
 
46
36
  _FALCON_UNSET = None # type: Optional[object]
47
- if FALCON3: # falcon.request._UNSET is only available in Falcon 3.0+
48
- with capture_internal_exceptions():
49
- from falcon.request import _UNSET as _FALCON_UNSET # type: ignore[import-not-found, no-redef]
37
+ with capture_internal_exceptions():
38
+ from falcon.request import _UNSET as _FALCON_UNSET # type: ignore[import-not-found, no-redef]
50
39
 
51
40
 
52
41
  class FalconRequestExtractor(RequestExtractor):
@@ -232,14 +221,7 @@ def _exception_leads_to_http_5xx(ex, response):
232
221
  ex, (falcon.HTTPError, falcon.http_status.HTTPStatus)
233
222
  )
234
223
 
235
- # We only check the HTTP status on Falcon 3 because in Falcon 2, the status on the response
236
- # at the stage where we capture it is listed as 200, even though we would expect to see a 500
237
- # status. Since at the time of this change, Falcon 2 is ca. 4 years old, we have decided to
238
- # only perform this check on Falcon 3+, despite the risk that some handled errors might be
239
- # reported to Sentry as unhandled on Falcon 2.
240
- return (is_server_error or is_unhandled_error) and (
241
- not FALCON3 or _has_http_5xx_status(response)
242
- )
224
+ return (is_server_error or is_unhandled_error) and _has_http_5xx_status(response)
243
225
 
244
226
 
245
227
  def _has_http_5xx_status(response):
@@ -3,9 +3,9 @@ from copy import deepcopy
3
3
  from functools import wraps
4
4
 
5
5
  import sentry_sdk
6
+ from sentry_sdk.consts import SOURCE_FOR_STYLE, TransactionSource
6
7
  from sentry_sdk.integrations import DidNotEnable
7
8
  from sentry_sdk.scope import should_send_default_pii
8
- from sentry_sdk.tracing import SOURCE_FOR_STYLE, TransactionSource
9
9
  from sentry_sdk.utils import (
10
10
  transaction_from_function,
11
11
  logger,
@@ -89,8 +89,8 @@ def patch_get_request_handler():
89
89
  def _sentry_call(*args, **kwargs):
90
90
  # type: (*Any, **Any) -> Any
91
91
  current_scope = sentry_sdk.get_current_scope()
92
- if current_scope.transaction is not None:
93
- current_scope.transaction.update_active_thread()
92
+ if current_scope.root_span is not None:
93
+ current_scope.root_span.update_active_thread()
94
94
 
95
95
  sentry_scope = sentry_sdk.get_isolation_scope()
96
96
  if sentry_scope.profile is not None:
@@ -1,4 +1,5 @@
1
1
  import sentry_sdk
2
+ from sentry_sdk.consts import SOURCE_FOR_STYLE
2
3
  from sentry_sdk.integrations import _check_minimum_version, DidNotEnable, Integration
3
4
  from sentry_sdk.integrations._wsgi_common import (
4
5
  DEFAULT_HTTP_METHODS_TO_CAPTURE,
@@ -6,7 +7,6 @@ from sentry_sdk.integrations._wsgi_common import (
6
7
  )
7
8
  from sentry_sdk.integrations.wsgi import SentryWsgiMiddleware
8
9
  from sentry_sdk.scope import should_send_default_pii
9
- from sentry_sdk.tracing import SOURCE_FOR_STYLE
10
10
  from sentry_sdk.utils import (
11
11
  capture_internal_exceptions,
12
12
  ensure_integration_enabled,
@@ -5,10 +5,12 @@ from datetime import datetime, timedelta, timezone
5
5
  from os import environ
6
6
 
7
7
  import sentry_sdk
8
- from sentry_sdk.api import continue_trace
9
8
  from sentry_sdk.consts import OP
10
9
  from sentry_sdk.integrations import Integration
11
- from sentry_sdk.integrations._wsgi_common import _filter_headers
10
+ from sentry_sdk.integrations._wsgi_common import (
11
+ _filter_headers,
12
+ _request_headers_to_span_attributes,
13
+ )
12
14
  from sentry_sdk.scope import should_send_default_pii
13
15
  from sentry_sdk.tracing import TransactionSource
14
16
  from sentry_sdk.utils import (
@@ -84,42 +86,30 @@ def _wrap_func(func):
84
86
  if hasattr(gcp_event, "headers"):
85
87
  headers = gcp_event.headers
86
88
 
87
- transaction = continue_trace(
88
- headers,
89
- op=OP.FUNCTION_GCP,
90
- name=environ.get("FUNCTION_NAME", ""),
91
- source=TransactionSource.COMPONENT,
92
- origin=GcpIntegration.origin,
93
- )
94
- sampling_context = {
95
- "gcp_env": {
96
- "function_name": environ.get("FUNCTION_NAME"),
97
- "function_entry_point": environ.get("ENTRY_POINT"),
98
- "function_identity": environ.get("FUNCTION_IDENTITY"),
99
- "function_region": environ.get("FUNCTION_REGION"),
100
- "function_project": environ.get("GCP_PROJECT"),
101
- },
102
- "gcp_event": gcp_event,
103
- }
104
- with sentry_sdk.start_transaction(
105
- transaction, custom_sampling_context=sampling_context
106
- ):
107
- try:
108
- return func(functionhandler, gcp_event, *args, **kwargs)
109
- except Exception:
110
- exc_info = sys.exc_info()
111
- sentry_event, hint = event_from_exception(
112
- exc_info,
113
- client_options=client.options,
114
- mechanism={"type": "gcp", "handled": False},
115
- )
116
- sentry_sdk.capture_event(sentry_event, hint=hint)
117
- reraise(*exc_info)
118
- finally:
119
- if timeout_thread:
120
- timeout_thread.stop()
121
- # Flush out the event queue
122
- client.flush()
89
+ with sentry_sdk.continue_trace(headers):
90
+ with sentry_sdk.start_span(
91
+ op=OP.FUNCTION_GCP,
92
+ name=environ.get("FUNCTION_NAME", ""),
93
+ source=TransactionSource.COMPONENT,
94
+ origin=GcpIntegration.origin,
95
+ attributes=_prepopulate_attributes(gcp_event),
96
+ ):
97
+ try:
98
+ return func(functionhandler, gcp_event, *args, **kwargs)
99
+ except Exception:
100
+ exc_info = sys.exc_info()
101
+ sentry_event, hint = event_from_exception(
102
+ exc_info,
103
+ client_options=client.options,
104
+ mechanism={"type": "gcp", "handled": False},
105
+ )
106
+ sentry_sdk.capture_event(sentry_event, hint=hint)
107
+ reraise(*exc_info)
108
+ finally:
109
+ if timeout_thread:
110
+ timeout_thread.stop()
111
+ # Flush out the event queue
112
+ client.flush()
123
113
 
124
114
  return sentry_func # type: ignore
125
115
 
@@ -232,3 +222,38 @@ def _get_google_cloud_logs_url(final_time):
232
222
  )
233
223
 
234
224
  return url
225
+
226
+
227
+ ENV_TO_ATTRIBUTE = {
228
+ "FUNCTION_NAME": "faas.name",
229
+ "ENTRY_POINT": "gcp.function.entry_point",
230
+ "FUNCTION_IDENTITY": "gcp.function.identity",
231
+ "FUNCTION_REGION": "faas.region",
232
+ "GCP_PROJECT": "gcp.function.project",
233
+ }
234
+
235
+ EVENT_TO_ATTRIBUTE = {
236
+ "method": "http.request.method",
237
+ "query_string": "url.query",
238
+ }
239
+
240
+
241
+ def _prepopulate_attributes(gcp_event):
242
+ # type: (Any) -> dict[str, Any]
243
+ attributes = {
244
+ "cloud.provider": "gcp",
245
+ }
246
+
247
+ for key, attr in ENV_TO_ATTRIBUTE.items():
248
+ if environ.get(key):
249
+ attributes[attr] = environ[key]
250
+
251
+ for key, attr in EVENT_TO_ATTRIBUTE.items():
252
+ if getattr(gcp_event, key, None):
253
+ attributes[attr] = getattr(gcp_event, key)
254
+
255
+ if hasattr(gcp_event, "headers"):
256
+ headers = gcp_event.headers
257
+ attributes.update(_request_headers_to_span_attributes(headers))
258
+
259
+ return attributes
@@ -135,17 +135,10 @@ def graphql_span(schema, source, kwargs):
135
135
  },
136
136
  )
137
137
 
138
- scope = sentry_sdk.get_current_scope()
139
- if scope.span:
140
- _graphql_span = scope.span.start_child(op=op, name=operation_name)
141
- else:
142
- _graphql_span = sentry_sdk.start_span(op=op, name=operation_name)
143
-
144
- _graphql_span.set_data("graphql.document", source)
145
- _graphql_span.set_data("graphql.operation.name", operation_name)
146
- _graphql_span.set_data("graphql.operation.type", operation_type)
147
-
148
- try:
138
+ with sentry_sdk.start_span(
139
+ op=op, name=operation_name, only_if_parent=True
140
+ ) as graphql_span:
141
+ graphql_span.set_attribute("graphql.document", source)
142
+ graphql_span.set_attribute("graphql.operation.name", operation_name)
143
+ graphql_span.set_attribute("graphql.operation.type", operation_type)
149
144
  yield
150
- finally:
151
- _graphql_span.finish()
@@ -44,14 +44,17 @@ class SentryUnaryUnaryClientInterceptor(ClientInterceptor, UnaryUnaryClientInter
44
44
  request: Message,
45
45
  ) -> Union[UnaryUnaryCall, Message]:
46
46
  method = client_call_details.method
47
+ if isinstance(method, bytes):
48
+ method = method.decode()
47
49
 
48
50
  with sentry_sdk.start_span(
49
51
  op=OP.GRPC_CLIENT,
50
- name="unary unary call to %s" % method.decode(),
52
+ name="unary unary call to %s" % method,
51
53
  origin=SPAN_ORIGIN,
54
+ only_if_parent=True,
52
55
  ) as span:
53
- span.set_data("type", "unary unary")
54
- span.set_data("method", method)
56
+ span.set_attribute("type", "unary unary")
57
+ span.set_attribute("method", method)
55
58
 
56
59
  client_call_details = self._update_client_call_details_metadata_from_scope(
57
60
  client_call_details
@@ -59,7 +62,7 @@ class SentryUnaryUnaryClientInterceptor(ClientInterceptor, UnaryUnaryClientInter
59
62
 
60
63
  response = await continuation(client_call_details, request)
61
64
  status_code = await response.code()
62
- span.set_data("code", status_code.name)
65
+ span.set_attribute("code", status_code.name)
63
66
 
64
67
  return response
65
68
 
@@ -74,14 +77,17 @@ class SentryUnaryStreamClientInterceptor(
74
77
  request: Message,
75
78
  ) -> Union[AsyncIterable[Any], UnaryStreamCall]:
76
79
  method = client_call_details.method
80
+ if isinstance(method, bytes):
81
+ method = method.decode()
77
82
 
78
83
  with sentry_sdk.start_span(
79
84
  op=OP.GRPC_CLIENT,
80
- name="unary stream call to %s" % method.decode(),
85
+ name="unary stream call to %s" % method,
81
86
  origin=SPAN_ORIGIN,
87
+ only_if_parent=True,
82
88
  ) as span:
83
- span.set_data("type", "unary stream")
84
- span.set_data("method", method)
89
+ span.set_attribute("type", "unary stream")
90
+ span.set_attribute("method", method)
85
91
 
86
92
  client_call_details = self._update_client_call_details_metadata_from_scope(
87
93
  client_call_details
@@ -89,6 +95,6 @@ class SentryUnaryStreamClientInterceptor(
89
95
 
90
96
  response = await continuation(client_call_details, request)
91
97
  # status_code = await response.code()
92
- # span.set_data("code", status_code)
98
+ # span.set_attribute("code", status_code)
93
99
 
94
100
  return response
@@ -2,7 +2,7 @@ import sentry_sdk
2
2
  from sentry_sdk.consts import OP
3
3
  from sentry_sdk.integrations import DidNotEnable
4
4
  from sentry_sdk.integrations.grpc.consts import SPAN_ORIGIN
5
- from sentry_sdk.tracing import Transaction, TransactionSource
5
+ from sentry_sdk.tracing import TransactionSource
6
6
  from sentry_sdk.utils import event_from_exception
7
7
 
8
8
  from typing import TYPE_CHECKING
@@ -44,26 +44,24 @@ class ServerInterceptor(grpc.aio.ServerInterceptor): # type: ignore
44
44
  return await handler(request, context)
45
45
 
46
46
  # What if the headers are empty?
47
- transaction = Transaction.continue_from_headers(
48
- dict(context.invocation_metadata()),
49
- op=OP.GRPC_SERVER,
50
- name=name,
51
- source=TransactionSource.CUSTOM,
52
- origin=SPAN_ORIGIN,
53
- )
54
-
55
- with sentry_sdk.start_transaction(transaction=transaction):
56
- try:
57
- return await handler.unary_unary(request, context)
58
- except AbortError:
59
- raise
60
- except Exception as exc:
61
- event, hint = event_from_exception(
62
- exc,
63
- mechanism={"type": "grpc", "handled": False},
64
- )
65
- sentry_sdk.capture_event(event, hint=hint)
66
- raise
47
+ with sentry_sdk.continue_trace(dict(context.invocation_metadata())):
48
+ with sentry_sdk.start_span(
49
+ op=OP.GRPC_SERVER,
50
+ name=name,
51
+ source=TransactionSource.CUSTOM,
52
+ origin=SPAN_ORIGIN,
53
+ ):
54
+ try:
55
+ return await handler.unary_unary(request, context)
56
+ except AbortError:
57
+ raise
58
+ except Exception as exc:
59
+ event, hint = event_from_exception(
60
+ exc,
61
+ mechanism={"type": "grpc", "handled": False},
62
+ )
63
+ sentry_sdk.capture_event(event, hint=hint)
64
+ raise
67
65
 
68
66
  elif not handler.request_streaming and handler.response_streaming:
69
67
  handler_factory = grpc.unary_stream_rpc_method_handler
@@ -31,16 +31,17 @@ class ClientInterceptor(
31
31
  op=OP.GRPC_CLIENT,
32
32
  name="unary unary call to %s" % method,
33
33
  origin=SPAN_ORIGIN,
34
+ only_if_parent=True,
34
35
  ) as span:
35
- span.set_data("type", "unary unary")
36
- span.set_data("method", method)
36
+ span.set_attribute("type", "unary unary")
37
+ span.set_attribute("method", method)
37
38
 
38
39
  client_call_details = self._update_client_call_details_metadata_from_scope(
39
40
  client_call_details
40
41
  )
41
42
 
42
43
  response = continuation(client_call_details, request)
43
- span.set_data("code", response.code().name)
44
+ span.set_attribute("code", response.code().name)
44
45
 
45
46
  return response
46
47
 
@@ -52,9 +53,10 @@ class ClientInterceptor(
52
53
  op=OP.GRPC_CLIENT,
53
54
  name="unary stream call to %s" % method,
54
55
  origin=SPAN_ORIGIN,
56
+ only_if_parent=True,
55
57
  ) as span:
56
- span.set_data("type", "unary stream")
57
- span.set_data("method", method)
58
+ span.set_attribute("type", "unary stream")
59
+ span.set_attribute("method", method)
58
60
 
59
61
  client_call_details = self._update_client_call_details_metadata_from_scope(
60
62
  client_call_details
@@ -64,7 +66,7 @@ class ClientInterceptor(
64
66
  client_call_details, request
65
67
  ) # type: UnaryStreamCall
66
68
  # Setting code on unary-stream leads to execution getting stuck
67
- # span.set_data("code", response.code().name)
69
+ # span.set_attribute("code", response.code().name)
68
70
 
69
71
  return response
70
72
 
@@ -2,7 +2,7 @@ import sentry_sdk
2
2
  from sentry_sdk.consts import OP
3
3
  from sentry_sdk.integrations import DidNotEnable
4
4
  from sentry_sdk.integrations.grpc.consts import SPAN_ORIGIN
5
- from sentry_sdk.tracing import Transaction, TransactionSource
5
+ from sentry_sdk.tracing import TransactionSource
6
6
 
7
7
  from typing import TYPE_CHECKING
8
8
 
@@ -38,19 +38,17 @@ class ServerInterceptor(grpc.ServerInterceptor): # type: ignore
38
38
  if name:
39
39
  metadata = dict(context.invocation_metadata())
40
40
 
41
- transaction = Transaction.continue_from_headers(
42
- metadata,
43
- op=OP.GRPC_SERVER,
44
- name=name,
45
- source=TransactionSource.CUSTOM,
46
- origin=SPAN_ORIGIN,
47
- )
48
-
49
- with sentry_sdk.start_transaction(transaction=transaction):
50
- try:
51
- return handler.unary_unary(request, context)
52
- except BaseException as e:
53
- raise e
41
+ with sentry_sdk.continue_trace(metadata):
42
+ with sentry_sdk.start_span(
43
+ op=OP.GRPC_SERVER,
44
+ name=name,
45
+ source=TransactionSource.CUSTOM,
46
+ origin=SPAN_ORIGIN,
47
+ ):
48
+ try:
49
+ return handler.unary_unary(request, context)
50
+ except BaseException as e:
51
+ raise e
54
52
  else:
55
53
  return handler.unary_unary(request, context)
56
54