sentry-sdk 2.27.0__py2.py3-none-any.whl → 3.0.0a1__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 (110) hide show
  1. sentry_sdk/__init__.py +4 -8
  2. sentry_sdk/_compat.py +0 -1
  3. sentry_sdk/_init_implementation.py +6 -44
  4. sentry_sdk/_log_batcher.py +47 -28
  5. sentry_sdk/_types.py +2 -64
  6. sentry_sdk/ai/monitoring.py +14 -10
  7. sentry_sdk/ai/utils.py +1 -1
  8. sentry_sdk/api.py +69 -163
  9. sentry_sdk/client.py +25 -72
  10. sentry_sdk/consts.py +42 -23
  11. sentry_sdk/debug.py +0 -10
  12. sentry_sdk/envelope.py +2 -10
  13. sentry_sdk/feature_flags.py +2 -2
  14. sentry_sdk/integrations/__init__.py +4 -2
  15. sentry_sdk/integrations/_asgi_common.py +3 -3
  16. sentry_sdk/integrations/_wsgi_common.py +11 -40
  17. sentry_sdk/integrations/aiohttp.py +104 -57
  18. sentry_sdk/integrations/anthropic.py +10 -7
  19. sentry_sdk/integrations/arq.py +24 -13
  20. sentry_sdk/integrations/asgi.py +102 -83
  21. sentry_sdk/integrations/asyncio.py +1 -0
  22. sentry_sdk/integrations/asyncpg.py +45 -30
  23. sentry_sdk/integrations/aws_lambda.py +109 -92
  24. sentry_sdk/integrations/boto3.py +38 -9
  25. sentry_sdk/integrations/bottle.py +1 -1
  26. sentry_sdk/integrations/celery/__init__.py +48 -38
  27. sentry_sdk/integrations/clickhouse_driver.py +59 -28
  28. sentry_sdk/integrations/cohere.py +2 -0
  29. sentry_sdk/integrations/django/__init__.py +25 -46
  30. sentry_sdk/integrations/django/asgi.py +6 -2
  31. sentry_sdk/integrations/django/caching.py +13 -22
  32. sentry_sdk/integrations/django/middleware.py +1 -0
  33. sentry_sdk/integrations/django/signals_handlers.py +3 -1
  34. sentry_sdk/integrations/django/templates.py +8 -12
  35. sentry_sdk/integrations/django/transactions.py +1 -6
  36. sentry_sdk/integrations/django/views.py +5 -2
  37. sentry_sdk/integrations/falcon.py +7 -25
  38. sentry_sdk/integrations/fastapi.py +3 -3
  39. sentry_sdk/integrations/flask.py +1 -1
  40. sentry_sdk/integrations/gcp.py +63 -38
  41. sentry_sdk/integrations/graphene.py +6 -13
  42. sentry_sdk/integrations/grpc/aio/client.py +14 -8
  43. sentry_sdk/integrations/grpc/aio/server.py +19 -21
  44. sentry_sdk/integrations/grpc/client.py +8 -6
  45. sentry_sdk/integrations/grpc/server.py +12 -14
  46. sentry_sdk/integrations/httpx.py +47 -12
  47. sentry_sdk/integrations/huey.py +26 -22
  48. sentry_sdk/integrations/huggingface_hub.py +1 -0
  49. sentry_sdk/integrations/langchain.py +22 -15
  50. sentry_sdk/integrations/litestar.py +4 -2
  51. sentry_sdk/integrations/logging.py +12 -3
  52. sentry_sdk/integrations/openai.py +2 -0
  53. sentry_sdk/integrations/pymongo.py +18 -25
  54. sentry_sdk/integrations/pyramid.py +1 -1
  55. sentry_sdk/integrations/quart.py +3 -3
  56. sentry_sdk/integrations/ray.py +23 -17
  57. sentry_sdk/integrations/redis/_async_common.py +30 -18
  58. sentry_sdk/integrations/redis/_sync_common.py +28 -18
  59. sentry_sdk/integrations/redis/modules/caches.py +13 -10
  60. sentry_sdk/integrations/redis/modules/queries.py +14 -11
  61. sentry_sdk/integrations/redis/rb.py +4 -4
  62. sentry_sdk/integrations/redis/redis.py +6 -6
  63. sentry_sdk/integrations/redis/redis_cluster.py +18 -16
  64. sentry_sdk/integrations/redis/redis_py_cluster_legacy.py +4 -4
  65. sentry_sdk/integrations/redis/utils.py +63 -19
  66. sentry_sdk/integrations/rq.py +68 -23
  67. sentry_sdk/integrations/rust_tracing.py +28 -43
  68. sentry_sdk/integrations/sanic.py +23 -13
  69. sentry_sdk/integrations/socket.py +9 -5
  70. sentry_sdk/integrations/sqlalchemy.py +8 -8
  71. sentry_sdk/integrations/starlette.py +11 -31
  72. sentry_sdk/integrations/starlite.py +4 -2
  73. sentry_sdk/integrations/stdlib.py +56 -9
  74. sentry_sdk/integrations/strawberry.py +40 -59
  75. sentry_sdk/integrations/threading.py +10 -26
  76. sentry_sdk/integrations/tornado.py +57 -18
  77. sentry_sdk/integrations/trytond.py +4 -1
  78. sentry_sdk/integrations/wsgi.py +84 -38
  79. sentry_sdk/opentelemetry/__init__.py +9 -0
  80. sentry_sdk/opentelemetry/consts.py +33 -0
  81. sentry_sdk/opentelemetry/contextvars_context.py +73 -0
  82. sentry_sdk/{integrations/opentelemetry → opentelemetry}/propagator.py +19 -28
  83. sentry_sdk/opentelemetry/sampler.py +326 -0
  84. sentry_sdk/opentelemetry/scope.py +218 -0
  85. sentry_sdk/opentelemetry/span_processor.py +329 -0
  86. sentry_sdk/opentelemetry/tracing.py +35 -0
  87. sentry_sdk/opentelemetry/utils.py +476 -0
  88. sentry_sdk/profiler/__init__.py +0 -40
  89. sentry_sdk/profiler/continuous_profiler.py +1 -30
  90. sentry_sdk/profiler/transaction_profiler.py +5 -56
  91. sentry_sdk/scope.py +107 -351
  92. sentry_sdk/sessions.py +0 -87
  93. sentry_sdk/tracing.py +418 -1144
  94. sentry_sdk/tracing_utils.py +126 -164
  95. sentry_sdk/transport.py +4 -104
  96. sentry_sdk/utils.py +169 -152
  97. {sentry_sdk-2.27.0.dist-info → sentry_sdk-3.0.0a1.dist-info}/METADATA +3 -5
  98. sentry_sdk-3.0.0a1.dist-info/RECORD +154 -0
  99. {sentry_sdk-2.27.0.dist-info → sentry_sdk-3.0.0a1.dist-info}/WHEEL +1 -1
  100. sentry_sdk-3.0.0a1.dist-info/entry_points.txt +2 -0
  101. sentry_sdk/hub.py +0 -739
  102. sentry_sdk/integrations/opentelemetry/__init__.py +0 -7
  103. sentry_sdk/integrations/opentelemetry/consts.py +0 -5
  104. sentry_sdk/integrations/opentelemetry/integration.py +0 -58
  105. sentry_sdk/integrations/opentelemetry/span_processor.py +0 -391
  106. sentry_sdk/metrics.py +0 -965
  107. sentry_sdk-2.27.0.dist-info/RECORD +0 -152
  108. sentry_sdk-2.27.0.dist-info/entry_points.txt +0 -2
  109. {sentry_sdk-2.27.0.dist-info → sentry_sdk-3.0.0a1.dist-info}/licenses/LICENSE +0 -0
  110. {sentry_sdk-2.27.0.dist-info → sentry_sdk-3.0.0a1.dist-info}/top_level.txt +0 -0
@@ -1,12 +1,11 @@
1
1
  import asyncio
2
2
  import functools
3
- import warnings
4
3
  from collections.abc import Set
5
4
  from copy import deepcopy
6
5
  from json import JSONDecodeError
7
6
 
8
7
  import sentry_sdk
9
- from sentry_sdk.consts import OP
8
+ from sentry_sdk.consts import OP, SOURCE_FOR_STYLE, TransactionSource
10
9
  from sentry_sdk.integrations import (
11
10
  DidNotEnable,
12
11
  Integration,
@@ -14,16 +13,11 @@ from sentry_sdk.integrations import (
14
13
  )
15
14
  from sentry_sdk.integrations._wsgi_common import (
16
15
  DEFAULT_HTTP_METHODS_TO_CAPTURE,
17
- HttpCodeRangeContainer,
18
16
  _is_json_content_type,
19
17
  request_body_within_bounds,
20
18
  )
21
19
  from sentry_sdk.integrations.asgi import SentryAsgiMiddleware
22
20
  from sentry_sdk.scope import should_send_default_pii
23
- from sentry_sdk.tracing import (
24
- SOURCE_FOR_STYLE,
25
- TransactionSource,
26
- )
27
21
  from sentry_sdk.utils import (
28
22
  AnnotatedValue,
29
23
  capture_internal_exceptions,
@@ -37,9 +31,9 @@ from sentry_sdk.utils import (
37
31
  from typing import TYPE_CHECKING
38
32
 
39
33
  if TYPE_CHECKING:
40
- from typing import Any, Awaitable, Callable, Container, Dict, Optional, Tuple, Union
34
+ from typing import Any, Awaitable, Callable, Dict, Optional, Tuple
41
35
 
42
- from sentry_sdk._types import Event, HttpStatusCodeRange
36
+ from sentry_sdk._types import Event
43
37
 
44
38
  try:
45
39
  import starlette # type: ignore
@@ -89,7 +83,7 @@ class StarletteIntegration(Integration):
89
83
  def __init__(
90
84
  self,
91
85
  transaction_style="url", # type: str
92
- failed_request_status_codes=_DEFAULT_FAILED_REQUEST_STATUS_CODES, # type: Union[Set[int], list[HttpStatusCodeRange], None]
86
+ failed_request_status_codes=_DEFAULT_FAILED_REQUEST_STATUS_CODES, # type: Set[int]
93
87
  middleware_spans=True, # type: bool
94
88
  http_methods_to_capture=DEFAULT_HTTP_METHODS_TO_CAPTURE, # type: tuple[str, ...]
95
89
  ):
@@ -103,24 +97,7 @@ class StarletteIntegration(Integration):
103
97
  self.middleware_spans = middleware_spans
104
98
  self.http_methods_to_capture = tuple(map(str.upper, http_methods_to_capture))
105
99
 
106
- if isinstance(failed_request_status_codes, Set):
107
- self.failed_request_status_codes = (
108
- failed_request_status_codes
109
- ) # type: Container[int]
110
- else:
111
- warnings.warn(
112
- "Passing a list or None for failed_request_status_codes is deprecated. "
113
- "Please pass a set of int instead.",
114
- DeprecationWarning,
115
- stacklevel=2,
116
- )
117
-
118
- if failed_request_status_codes is None:
119
- self.failed_request_status_codes = _DEFAULT_FAILED_REQUEST_STATUS_CODES
120
- else:
121
- self.failed_request_status_codes = HttpCodeRangeContainer(
122
- failed_request_status_codes
123
- )
100
+ self.failed_request_status_codes = failed_request_status_codes
124
101
 
125
102
  @staticmethod
126
103
  def setup_once():
@@ -164,6 +141,7 @@ def _enable_span_for_middleware(middleware_class):
164
141
  op=OP.MIDDLEWARE_STARLETTE,
165
142
  name=middleware_name,
166
143
  origin=StarletteIntegration.origin,
144
+ only_if_parent=True,
167
145
  ) as middleware_span:
168
146
  middleware_span.set_tag("starlette.middleware_name", middleware_name)
169
147
 
@@ -174,6 +152,7 @@ def _enable_span_for_middleware(middleware_class):
174
152
  op=OP.MIDDLEWARE_STARLETTE_RECEIVE,
175
153
  name=getattr(receive, "__qualname__", str(receive)),
176
154
  origin=StarletteIntegration.origin,
155
+ only_if_parent=True,
177
156
  ) as span:
178
157
  span.set_tag("starlette.middleware_name", middleware_name)
179
158
  return await receive(*args, **kwargs)
@@ -189,6 +168,7 @@ def _enable_span_for_middleware(middleware_class):
189
168
  op=OP.MIDDLEWARE_STARLETTE_SEND,
190
169
  name=getattr(send, "__qualname__", str(send)),
191
170
  origin=StarletteIntegration.origin,
171
+ only_if_parent=True,
192
172
  ) as span:
193
173
  span.set_tag("starlette.middleware_name", middleware_name)
194
174
  return await send(*args, **kwargs)
@@ -329,7 +309,7 @@ def _add_user_to_sentry_scope(scope):
329
309
  user_info.setdefault("email", starlette_user.email)
330
310
 
331
311
  sentry_scope = sentry_sdk.get_isolation_scope()
332
- sentry_scope.user = user_info
312
+ sentry_scope.set_user(user_info)
333
313
 
334
314
 
335
315
  def patch_authentication_middleware(middleware_class):
@@ -493,8 +473,8 @@ def patch_request_response():
493
473
  return old_func(*args, **kwargs)
494
474
 
495
475
  current_scope = sentry_sdk.get_current_scope()
496
- if current_scope.transaction is not None:
497
- current_scope.transaction.update_active_thread()
476
+ if current_scope.root_span is not None:
477
+ current_scope.root_span.update_active_thread()
498
478
 
499
479
  sentry_scope = sentry_sdk.get_isolation_scope()
500
480
  if sentry_scope.profile is not None:
@@ -1,9 +1,8 @@
1
1
  import sentry_sdk
2
- from sentry_sdk.consts import OP
2
+ from sentry_sdk.consts import OP, SOURCE_FOR_STYLE, TransactionSource
3
3
  from sentry_sdk.integrations import DidNotEnable, Integration
4
4
  from sentry_sdk.integrations.asgi import SentryAsgiMiddleware
5
5
  from sentry_sdk.scope import should_send_default_pii
6
- from sentry_sdk.tracing import SOURCE_FOR_STYLE, TransactionSource
7
6
  from sentry_sdk.utils import (
8
7
  ensure_integration_enabled,
9
8
  event_from_exception,
@@ -140,6 +139,7 @@ def enable_span_for_middleware(middleware):
140
139
  op=OP.MIDDLEWARE_STARLITE,
141
140
  name=middleware_name,
142
141
  origin=StarliteIntegration.origin,
142
+ only_if_parent=True,
143
143
  ) as middleware_span:
144
144
  middleware_span.set_tag("starlite.middleware_name", middleware_name)
145
145
 
@@ -152,6 +152,7 @@ def enable_span_for_middleware(middleware):
152
152
  op=OP.MIDDLEWARE_STARLITE_RECEIVE,
153
153
  name=getattr(receive, "__qualname__", str(receive)),
154
154
  origin=StarliteIntegration.origin,
155
+ only_if_parent=True,
155
156
  ) as span:
156
157
  span.set_tag("starlite.middleware_name", middleware_name)
157
158
  return await receive(*args, **kwargs)
@@ -169,6 +170,7 @@ def enable_span_for_middleware(middleware):
169
170
  op=OP.MIDDLEWARE_STARLITE_SEND,
170
171
  name=getattr(send, "__qualname__", str(send)),
171
172
  origin=StarliteIntegration.origin,
173
+ only_if_parent=True,
172
174
  ) as span:
173
175
  span.set_tag("starlite.middleware_name", middleware_name)
174
176
  return await send(message)
@@ -13,10 +13,13 @@ from sentry_sdk.utils import (
13
13
  SENSITIVE_DATA_SUBSTITUTE,
14
14
  capture_internal_exceptions,
15
15
  ensure_integration_enabled,
16
+ get_current_thread_meta,
17
+ http_client_status_to_breadcrumb_level,
16
18
  is_sentry_url,
17
19
  logger,
18
20
  safe_repr,
19
21
  parse_url,
22
+ set_thread_info_from_span,
20
23
  )
21
24
 
22
25
  from typing import TYPE_CHECKING
@@ -71,7 +74,7 @@ def _install_httplib():
71
74
 
72
75
  client = sentry_sdk.get_client()
73
76
  if client.get_integration(StdlibIntegration) is None or is_sentry_url(
74
- client, host
77
+ client, f"{host}:{port}" # noqa: E231
75
78
  ):
76
79
  return real_putrequest(self, method, url, *args, **kwargs)
77
80
 
@@ -93,12 +96,22 @@ def _install_httplib():
93
96
  name="%s %s"
94
97
  % (method, parsed_url.url if parsed_url else SENSITIVE_DATA_SUBSTITUTE),
95
98
  origin="auto.http.stdlib.httplib",
99
+ only_if_parent=True,
96
100
  )
97
- span.set_data(SPANDATA.HTTP_METHOD, method)
101
+ span.__enter__()
102
+
103
+ data = {
104
+ SPANDATA.HTTP_METHOD: method,
105
+ }
106
+ set_thread_info_from_span(data, span)
107
+
98
108
  if parsed_url is not None:
99
- span.set_data("url", parsed_url.url)
100
- span.set_data(SPANDATA.HTTP_QUERY, parsed_url.query)
101
- span.set_data(SPANDATA.HTTP_FRAGMENT, parsed_url.fragment)
109
+ data["url"] = parsed_url.url
110
+ data[SPANDATA.HTTP_QUERY] = parsed_url.query
111
+ data[SPANDATA.HTTP_FRAGMENT] = parsed_url.fragment
112
+
113
+ for key, value in data.items():
114
+ span.set_attribute(key, value)
102
115
 
103
116
  rv = real_putrequest(self, method, url, *args, **kwargs)
104
117
 
@@ -117,6 +130,7 @@ def _install_httplib():
117
130
  self.putheader(key, value)
118
131
 
119
132
  self._sentrysdk_span = span # type: ignore[attr-defined]
133
+ self._sentrysdk_span_data = data # type: ignore[attr-defined]
120
134
 
121
135
  return rv
122
136
 
@@ -130,10 +144,22 @@ def _install_httplib():
130
144
  try:
131
145
  rv = real_getresponse(self, *args, **kwargs)
132
146
 
133
- span.set_http_status(int(rv.status))
134
- span.set_data("reason", rv.reason)
147
+ span_data = getattr(self, "_sentrysdk_span_data", {})
148
+ span_data[SPANDATA.HTTP_STATUS_CODE] = int(rv.status)
149
+ span_data["reason"] = rv.reason
150
+
151
+ status_code = int(rv.status)
152
+ span.set_http_status(status_code)
153
+ span.set_attribute("reason", rv.reason)
154
+
155
+ sentry_sdk.add_breadcrumb(
156
+ type="http",
157
+ category="httplib",
158
+ data=span_data,
159
+ level=http_client_status_to_breadcrumb_level(status_code),
160
+ )
135
161
  finally:
136
- span.finish()
162
+ span.__exit__(None, None, None)
137
163
 
138
164
  return rv
139
165
 
@@ -207,6 +233,7 @@ def _install_subprocess():
207
233
  op=OP.SUBPROCESS,
208
234
  name=description,
209
235
  origin="auto.subprocess.stdlib.subprocess",
236
+ only_if_parent=True,
210
237
  ) as span:
211
238
  for k, v in sentry_sdk.get_current_scope().iter_trace_propagation_headers(
212
239
  span=span
@@ -222,11 +249,29 @@ def _install_subprocess():
222
249
  env["SUBPROCESS_" + k.upper().replace("-", "_")] = v
223
250
 
224
251
  if cwd:
225
- span.set_data("subprocess.cwd", cwd)
252
+ span.set_attribute("subprocess.cwd", cwd)
226
253
 
227
254
  rv = old_popen_init(self, *a, **kw)
228
255
 
229
256
  span.set_tag("subprocess.pid", self.pid)
257
+
258
+ with capture_internal_exceptions():
259
+ thread_id, thread_name = get_current_thread_meta()
260
+ breadcrumb_data = {
261
+ "subprocess.pid": self.pid,
262
+ SPANDATA.THREAD_ID: thread_id,
263
+ SPANDATA.THREAD_NAME: thread_name,
264
+ }
265
+ if cwd:
266
+ breadcrumb_data["subprocess.cwd"] = cwd
267
+
268
+ sentry_sdk.add_breadcrumb(
269
+ type="subprocess",
270
+ category="subprocess",
271
+ message=description,
272
+ data=breadcrumb_data,
273
+ )
274
+
230
275
  return rv
231
276
 
232
277
  subprocess.Popen.__init__ = sentry_patched_popen_init # type: ignore
@@ -239,6 +284,7 @@ def _install_subprocess():
239
284
  with sentry_sdk.start_span(
240
285
  op=OP.SUBPROCESS_WAIT,
241
286
  origin="auto.subprocess.stdlib.subprocess",
287
+ only_if_parent=True,
242
288
  ) as span:
243
289
  span.set_tag("subprocess.pid", self.pid)
244
290
  return old_popen_wait(self, *a, **kw)
@@ -253,6 +299,7 @@ def _install_subprocess():
253
299
  with sentry_sdk.start_span(
254
300
  op=OP.SUBPROCESS_COMMUNICATE,
255
301
  origin="auto.subprocess.stdlib.subprocess",
302
+ only_if_parent=True,
256
303
  ) as span:
257
304
  span.set_tag("subprocess.pid", self.pid)
258
305
  return old_popen_communicate(self, *a, **kw)
@@ -107,14 +107,6 @@ def _patch_schema_init():
107
107
  "False" if should_use_async_extension else "True",
108
108
  )
109
109
 
110
- # remove the built in strawberry sentry extension, if present
111
- extensions = [
112
- extension
113
- for extension in extensions
114
- if extension
115
- not in (StrawberrySentryAsyncExtension, StrawberrySentrySyncExtension)
116
- ]
117
-
118
110
  # add our extension
119
111
  extensions.append(
120
112
  SentryAsyncExtension if should_use_async_extension else SentrySyncExtension
@@ -184,58 +176,52 @@ class SentryAsyncExtension(SchemaExtension):
184
176
  event_processor = _make_request_event_processor(self.execution_context)
185
177
  scope.add_event_processor(event_processor)
186
178
 
187
- span = sentry_sdk.get_current_span()
188
- if span:
189
- self.graphql_span = span.start_child(
190
- op=op,
191
- name=description,
192
- origin=StrawberryIntegration.origin,
193
- )
194
- else:
195
- self.graphql_span = sentry_sdk.start_span(
196
- op=op,
197
- name=description,
198
- origin=StrawberryIntegration.origin,
199
- )
179
+ with sentry_sdk.start_span(
180
+ op=op,
181
+ name=description,
182
+ origin=StrawberryIntegration.origin,
183
+ only_if_parent=True,
184
+ ) as graphql_span:
185
+ graphql_span.set_attribute("graphql.operation.type", operation_type)
186
+ graphql_span.set_attribute("graphql.document", self.execution_context.query)
187
+ graphql_span.set_attribute("graphql.resource_name", self._resource_name)
188
+
189
+ yield
200
190
 
201
- self.graphql_span.set_data("graphql.operation.type", operation_type)
202
- self.graphql_span.set_data("graphql.operation.name", self._operation_name)
203
- self.graphql_span.set_data("graphql.document", self.execution_context.query)
204
- self.graphql_span.set_data("graphql.resource_name", self._resource_name)
191
+ # we might have a more accurate operation_name after the parsing
192
+ self._operation_name = self.execution_context.operation_name
205
193
 
206
- yield
194
+ if self._operation_name is not None:
195
+ graphql_span.set_attribute(
196
+ "graphql.operation.name", self._operation_name
197
+ )
207
198
 
208
- transaction = self.graphql_span.containing_transaction
209
- if transaction and self.execution_context.operation_name:
210
- transaction.name = self.execution_context.operation_name
211
- transaction.source = TransactionSource.COMPONENT
212
- transaction.op = op
199
+ sentry_sdk.get_current_scope().set_transaction_name(
200
+ self._operation_name,
201
+ source=TransactionSource.COMPONENT,
202
+ )
213
203
 
214
- self.graphql_span.finish()
204
+ root_span = graphql_span.root_span
205
+ if root_span:
206
+ root_span.op = op
215
207
 
216
208
  def on_validate(self):
217
209
  # type: () -> Generator[None, None, None]
218
- self.validation_span = self.graphql_span.start_child(
210
+ with sentry_sdk.start_span(
219
211
  op=OP.GRAPHQL_VALIDATE,
220
212
  name="validation",
221
213
  origin=StrawberryIntegration.origin,
222
- )
223
-
224
- yield
225
-
226
- self.validation_span.finish()
214
+ ):
215
+ yield
227
216
 
228
217
  def on_parse(self):
229
218
  # type: () -> Generator[None, None, None]
230
- self.parsing_span = self.graphql_span.start_child(
219
+ with sentry_sdk.start_span(
231
220
  op=OP.GRAPHQL_PARSE,
232
221
  name="parsing",
233
222
  origin=StrawberryIntegration.origin,
234
- )
235
-
236
- yield
237
-
238
- self.parsing_span.finish()
223
+ ):
224
+ yield
239
225
 
240
226
  def should_skip_tracing(self, _next, info):
241
227
  # type: (Callable[[Any, GraphQLResolveInfo, Any, Any], Any], GraphQLResolveInfo) -> bool
@@ -257,15 +243,15 @@ class SentryAsyncExtension(SchemaExtension):
257
243
 
258
244
  field_path = "{}.{}".format(info.parent_type, info.field_name)
259
245
 
260
- with self.graphql_span.start_child(
246
+ with sentry_sdk.start_span(
261
247
  op=OP.GRAPHQL_RESOLVE,
262
248
  name="resolving {}".format(field_path),
263
249
  origin=StrawberryIntegration.origin,
264
250
  ) as span:
265
- span.set_data("graphql.field_name", info.field_name)
266
- span.set_data("graphql.parent_type", info.parent_type.name)
267
- span.set_data("graphql.field_path", field_path)
268
- span.set_data("graphql.path", ".".join(map(str, info.path.as_list())))
251
+ span.set_attribute("graphql.field_name", info.field_name)
252
+ span.set_attribute("graphql.parent_type", info.parent_type.name)
253
+ span.set_attribute("graphql.field_path", field_path)
254
+ span.set_attribute("graphql.path", ".".join(map(str, info.path.as_list())))
269
255
 
270
256
  return await self._resolve(_next, root, info, *args, **kwargs)
271
257
 
@@ -278,15 +264,15 @@ class SentrySyncExtension(SentryAsyncExtension):
278
264
 
279
265
  field_path = "{}.{}".format(info.parent_type, info.field_name)
280
266
 
281
- with self.graphql_span.start_child(
267
+ with sentry_sdk.start_span(
282
268
  op=OP.GRAPHQL_RESOLVE,
283
269
  name="resolving {}".format(field_path),
284
270
  origin=StrawberryIntegration.origin,
285
271
  ) as span:
286
- span.set_data("graphql.field_name", info.field_name)
287
- span.set_data("graphql.parent_type", info.parent_type.name)
288
- span.set_data("graphql.field_path", field_path)
289
- span.set_data("graphql.path", ".".join(map(str, info.path.as_list())))
272
+ span.set_attribute("graphql.field_name", info.field_name)
273
+ span.set_attribute("graphql.parent_type", info.parent_type.name)
274
+ span.set_attribute("graphql.field_path", field_path)
275
+ span.set_attribute("graphql.path", ".".join(map(str, info.path.as_list())))
290
276
 
291
277
  return _next(root, info, *args, **kwargs)
292
278
 
@@ -383,11 +369,6 @@ def _make_response_event_processor(response_data):
383
369
 
384
370
  def _guess_if_using_async(extensions):
385
371
  # type: (List[SchemaExtension]) -> bool
386
- if StrawberrySentryAsyncExtension in extensions:
387
- return True
388
- elif StrawberrySentrySyncExtension in extensions:
389
- return False
390
-
391
372
  return bool(
392
373
  {"starlette", "starlite", "litestar", "fastapi"} & set(_get_installed_modules())
393
374
  )
@@ -4,12 +4,12 @@ from functools import wraps
4
4
  from threading import Thread, current_thread
5
5
 
6
6
  import sentry_sdk
7
+ from sentry_sdk import Scope
8
+ from sentry_sdk.scope import ScopeType
7
9
  from sentry_sdk.integrations import Integration
8
- from sentry_sdk.scope import use_isolation_scope, use_scope
9
10
  from sentry_sdk.utils import (
10
11
  event_from_exception,
11
12
  capture_internal_exceptions,
12
- logger,
13
13
  reraise,
14
14
  )
15
15
 
@@ -19,7 +19,6 @@ if TYPE_CHECKING:
19
19
  from typing import Any
20
20
  from typing import TypeVar
21
21
  from typing import Callable
22
- from typing import Optional
23
22
 
24
23
  from sentry_sdk._types import ExcInfo
25
24
 
@@ -29,22 +28,10 @@ if TYPE_CHECKING:
29
28
  class ThreadingIntegration(Integration):
30
29
  identifier = "threading"
31
30
 
32
- def __init__(self, propagate_hub=None, propagate_scope=True):
33
- # type: (Optional[bool], bool) -> None
34
- if propagate_hub is not None:
35
- logger.warning(
36
- "Deprecated: propagate_hub is deprecated. This will be removed in the future."
37
- )
38
-
39
- # Note: propagate_hub did not have any effect on propagation of scope data
40
- # scope data was always propagated no matter what the value of propagate_hub was
41
- # This is why the default for propagate_scope is True
42
-
31
+ def __init__(self, propagate_scope=True):
32
+ # type: (bool) -> None
43
33
  self.propagate_scope = propagate_scope
44
34
 
45
- if propagate_hub is not None:
46
- self.propagate_scope = propagate_hub
47
-
48
35
  @staticmethod
49
36
  def setup_once():
50
37
  # type: () -> None
@@ -89,8 +76,8 @@ class ThreadingIntegration(Integration):
89
76
  isolation_scope = sentry_sdk.get_isolation_scope().fork()
90
77
  current_scope = sentry_sdk.get_current_scope().fork()
91
78
  else:
92
- isolation_scope = None
93
- current_scope = None
79
+ isolation_scope = Scope(ty=ScopeType.ISOLATION)
80
+ current_scope = Scope(ty=ScopeType.CURRENT)
94
81
 
95
82
  # Patching instance methods in `start()` creates a reference cycle if
96
83
  # done in a naive way. See
@@ -112,7 +99,7 @@ class ThreadingIntegration(Integration):
112
99
 
113
100
 
114
101
  def _wrap_run(isolation_scope_to_use, current_scope_to_use, old_run_func):
115
- # type: (Optional[sentry_sdk.Scope], Optional[sentry_sdk.Scope], F) -> F
102
+ # type: (sentry_sdk.Scope, sentry_sdk.Scope, F) -> F
116
103
  @wraps(old_run_func)
117
104
  def run(*a, **kw):
118
105
  # type: (*Any, **Any) -> Any
@@ -124,12 +111,9 @@ def _wrap_run(isolation_scope_to_use, current_scope_to_use, old_run_func):
124
111
  except Exception:
125
112
  reraise(*_capture_exception())
126
113
 
127
- if isolation_scope_to_use is not None and current_scope_to_use is not None:
128
- with use_isolation_scope(isolation_scope_to_use):
129
- with use_scope(current_scope_to_use):
130
- return _run_old_run_func()
131
- else:
132
- return _run_old_run_func()
114
+ with sentry_sdk.use_isolation_scope(isolation_scope_to_use):
115
+ with sentry_sdk.use_scope(current_scope_to_use):
116
+ return _run_old_run_func()
133
117
 
134
118
  return run # type: ignore
135
119
 
@@ -3,7 +3,6 @@ import contextlib
3
3
  from inspect import iscoroutinefunction
4
4
 
5
5
  import sentry_sdk
6
- from sentry_sdk.api import continue_trace
7
6
  from sentry_sdk.consts import OP
8
7
  from sentry_sdk.scope import should_send_default_pii
9
8
  from sentry_sdk.tracing import TransactionSource
@@ -20,13 +19,15 @@ from sentry_sdk.integrations._wsgi_common import (
20
19
  RequestExtractor,
21
20
  _filter_headers,
22
21
  _is_json_content_type,
22
+ _request_headers_to_span_attributes,
23
23
  )
24
24
  from sentry_sdk.integrations.logging import ignore_logger
25
25
 
26
26
  try:
27
27
  from tornado import version_info as TORNADO_VERSION
28
- from tornado.web import RequestHandler, HTTPError
29
28
  from tornado.gen import coroutine
29
+ from tornado.httputil import HTTPServerRequest
30
+ from tornado.web import RequestHandler, HTTPError
30
31
  except ImportError:
31
32
  raise DidNotEnable("Tornado not installed")
32
33
 
@@ -42,6 +43,14 @@ if TYPE_CHECKING:
42
43
  from sentry_sdk._types import Event, EventProcessor
43
44
 
44
45
 
46
+ REQUEST_PROPERTY_TO_ATTRIBUTE = {
47
+ "method": "http.request.method",
48
+ "path": "url.path",
49
+ "query": "url.query",
50
+ "protocol": "url.scheme",
51
+ }
52
+
53
+
45
54
  class TornadoIntegration(Integration):
46
55
  identifier = "tornado"
47
56
  origin = f"auto.http.{identifier}"
@@ -111,22 +120,19 @@ def _handle_request_impl(self):
111
120
  processor = _make_event_processor(weak_handler)
112
121
  scope.add_event_processor(processor)
113
122
 
114
- transaction = continue_trace(
115
- headers,
116
- op=OP.HTTP_SERVER,
117
- # Like with all other integrations, this is our
118
- # fallback transaction in case there is no route.
119
- # sentry_urldispatcher_resolve is responsible for
120
- # setting a transaction name later.
121
- name="generic Tornado request",
122
- source=TransactionSource.ROUTE,
123
- origin=TornadoIntegration.origin,
124
- )
125
-
126
- with sentry_sdk.start_transaction(
127
- transaction, custom_sampling_context={"tornado_request": self.request}
128
- ):
129
- yield
123
+ with sentry_sdk.continue_trace(headers):
124
+ with sentry_sdk.start_span(
125
+ op=OP.HTTP_SERVER,
126
+ # Like with all other integrations, this is our
127
+ # fallback transaction in case there is no route.
128
+ # sentry_urldispatcher_resolve is responsible for
129
+ # setting a transaction name later.
130
+ name="generic Tornado request",
131
+ source=TransactionSource.ROUTE,
132
+ origin=TornadoIntegration.origin,
133
+ attributes=_prepopulate_attributes(self.request),
134
+ ):
135
+ yield
130
136
 
131
137
 
132
138
  @ensure_integration_enabled(TornadoIntegration)
@@ -218,3 +224,36 @@ class TornadoRequestExtractor(RequestExtractor):
218
224
  def size_of_file(self, file):
219
225
  # type: (Any) -> int
220
226
  return len(file.body or ())
227
+
228
+
229
+ def _prepopulate_attributes(request):
230
+ # type: (HTTPServerRequest) -> dict[str, Any]
231
+ # https://www.tornadoweb.org/en/stable/httputil.html#tornado.httputil.HTTPServerRequest
232
+ attributes = {}
233
+
234
+ for prop, attr in REQUEST_PROPERTY_TO_ATTRIBUTE.items():
235
+ if getattr(request, prop, None) is not None:
236
+ attributes[attr] = getattr(request, prop)
237
+
238
+ if getattr(request, "version", None):
239
+ try:
240
+ proto, version = request.version.split("/")
241
+ attributes["network.protocol.name"] = proto
242
+ attributes["network.protocol.version"] = version
243
+ except ValueError:
244
+ attributes["network.protocol.name"] = request.version
245
+
246
+ if getattr(request, "host", None):
247
+ try:
248
+ address, port = request.host.split(":")
249
+ attributes["server.address"] = address
250
+ attributes["server.port"] = port
251
+ except ValueError:
252
+ attributes["server.address"] = request.host
253
+
254
+ with capture_internal_exceptions():
255
+ attributes["url.full"] = request.full_url()
256
+
257
+ attributes.update(_request_headers_to_span_attributes(request.headers))
258
+
259
+ return attributes
@@ -1,8 +1,9 @@
1
1
  import sentry_sdk
2
- from sentry_sdk.integrations import Integration
2
+ from sentry_sdk.integrations import _check_minimum_version, Integration
3
3
  from sentry_sdk.integrations.wsgi import SentryWsgiMiddleware
4
4
  from sentry_sdk.utils import ensure_integration_enabled, event_from_exception
5
5
 
6
+ from trytond import __version__ as trytond_version # type: ignore
6
7
  from trytond.exceptions import TrytonException # type: ignore
7
8
  from trytond.wsgi import app # type: ignore
8
9
 
@@ -19,6 +20,8 @@ class TrytondWSGIIntegration(Integration):
19
20
 
20
21
  @staticmethod
21
22
  def setup_once(): # type: () -> None
23
+ _check_minimum_version(TrytondWSGIIntegration, trytond_version)
24
+
22
25
  app.wsgi_app = SentryWsgiMiddleware(
23
26
  app.wsgi_app,
24
27
  span_origin=TrytondWSGIIntegration.origin,