sentry-sdk 3.0.0a2__py2.py3-none-any.whl → 3.0.0a4__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 (159) hide show
  1. sentry_sdk/__init__.py +4 -0
  2. sentry_sdk/_compat.py +5 -12
  3. sentry_sdk/_init_implementation.py +7 -7
  4. sentry_sdk/_log_batcher.py +17 -29
  5. sentry_sdk/_lru_cache.py +7 -9
  6. sentry_sdk/_queue.py +2 -4
  7. sentry_sdk/_types.py +9 -16
  8. sentry_sdk/_werkzeug.py +5 -7
  9. sentry_sdk/ai/monitoring.py +45 -33
  10. sentry_sdk/ai/utils.py +8 -5
  11. sentry_sdk/api.py +91 -87
  12. sentry_sdk/attachments.py +10 -12
  13. sentry_sdk/client.py +119 -159
  14. sentry_sdk/consts.py +432 -223
  15. sentry_sdk/crons/api.py +16 -17
  16. sentry_sdk/crons/decorator.py +25 -27
  17. sentry_sdk/debug.py +4 -6
  18. sentry_sdk/envelope.py +46 -112
  19. sentry_sdk/feature_flags.py +9 -15
  20. sentry_sdk/integrations/__init__.py +24 -19
  21. sentry_sdk/integrations/_asgi_common.py +16 -18
  22. sentry_sdk/integrations/_wsgi_common.py +22 -33
  23. sentry_sdk/integrations/aiohttp.py +33 -31
  24. sentry_sdk/integrations/anthropic.py +43 -38
  25. sentry_sdk/integrations/argv.py +3 -4
  26. sentry_sdk/integrations/ariadne.py +16 -18
  27. sentry_sdk/integrations/arq.py +20 -29
  28. sentry_sdk/integrations/asgi.py +63 -37
  29. sentry_sdk/integrations/asyncio.py +15 -17
  30. sentry_sdk/integrations/asyncpg.py +1 -1
  31. sentry_sdk/integrations/atexit.py +6 -10
  32. sentry_sdk/integrations/aws_lambda.py +26 -36
  33. sentry_sdk/integrations/beam.py +10 -18
  34. sentry_sdk/integrations/boto3.py +20 -18
  35. sentry_sdk/integrations/bottle.py +25 -34
  36. sentry_sdk/integrations/celery/__init__.py +40 -59
  37. sentry_sdk/integrations/celery/beat.py +22 -26
  38. sentry_sdk/integrations/celery/utils.py +15 -17
  39. sentry_sdk/integrations/chalice.py +8 -10
  40. sentry_sdk/integrations/clickhouse_driver.py +22 -32
  41. sentry_sdk/integrations/cloud_resource_context.py +9 -16
  42. sentry_sdk/integrations/cohere.py +19 -25
  43. sentry_sdk/integrations/dedupe.py +5 -8
  44. sentry_sdk/integrations/django/__init__.py +69 -74
  45. sentry_sdk/integrations/django/asgi.py +25 -33
  46. sentry_sdk/integrations/django/caching.py +24 -20
  47. sentry_sdk/integrations/django/middleware.py +18 -21
  48. sentry_sdk/integrations/django/signals_handlers.py +12 -11
  49. sentry_sdk/integrations/django/templates.py +21 -18
  50. sentry_sdk/integrations/django/transactions.py +16 -11
  51. sentry_sdk/integrations/django/views.py +8 -12
  52. sentry_sdk/integrations/dramatiq.py +21 -21
  53. sentry_sdk/integrations/excepthook.py +10 -10
  54. sentry_sdk/integrations/executing.py +3 -4
  55. sentry_sdk/integrations/falcon.py +27 -42
  56. sentry_sdk/integrations/fastapi.py +13 -16
  57. sentry_sdk/integrations/flask.py +31 -38
  58. sentry_sdk/integrations/gcp.py +13 -16
  59. sentry_sdk/integrations/gnu_backtrace.py +7 -20
  60. sentry_sdk/integrations/gql.py +16 -17
  61. sentry_sdk/integrations/graphene.py +14 -13
  62. sentry_sdk/integrations/grpc/__init__.py +3 -2
  63. sentry_sdk/integrations/grpc/aio/client.py +2 -2
  64. sentry_sdk/integrations/grpc/aio/server.py +15 -14
  65. sentry_sdk/integrations/grpc/client.py +21 -11
  66. sentry_sdk/integrations/grpc/consts.py +2 -0
  67. sentry_sdk/integrations/grpc/server.py +12 -8
  68. sentry_sdk/integrations/httpx.py +11 -14
  69. sentry_sdk/integrations/huey.py +14 -21
  70. sentry_sdk/integrations/huggingface_hub.py +17 -17
  71. sentry_sdk/integrations/langchain.py +204 -114
  72. sentry_sdk/integrations/launchdarkly.py +13 -10
  73. sentry_sdk/integrations/litestar.py +40 -38
  74. sentry_sdk/integrations/logging.py +29 -36
  75. sentry_sdk/integrations/loguru.py +16 -20
  76. sentry_sdk/integrations/modules.py +3 -4
  77. sentry_sdk/integrations/openai.py +421 -204
  78. sentry_sdk/integrations/openai_agents/__init__.py +49 -0
  79. sentry_sdk/integrations/openai_agents/consts.py +1 -0
  80. sentry_sdk/integrations/openai_agents/patches/__init__.py +4 -0
  81. sentry_sdk/integrations/openai_agents/patches/agent_run.py +152 -0
  82. sentry_sdk/integrations/openai_agents/patches/models.py +52 -0
  83. sentry_sdk/integrations/openai_agents/patches/runner.py +42 -0
  84. sentry_sdk/integrations/openai_agents/patches/tools.py +84 -0
  85. sentry_sdk/integrations/openai_agents/spans/__init__.py +5 -0
  86. sentry_sdk/integrations/openai_agents/spans/agent_workflow.py +20 -0
  87. sentry_sdk/integrations/openai_agents/spans/ai_client.py +46 -0
  88. sentry_sdk/integrations/openai_agents/spans/execute_tool.py +47 -0
  89. sentry_sdk/integrations/openai_agents/spans/handoff.py +24 -0
  90. sentry_sdk/integrations/openai_agents/spans/invoke_agent.py +41 -0
  91. sentry_sdk/integrations/openai_agents/utils.py +153 -0
  92. sentry_sdk/integrations/openfeature.py +12 -8
  93. sentry_sdk/integrations/pure_eval.py +6 -10
  94. sentry_sdk/integrations/pymongo.py +14 -18
  95. sentry_sdk/integrations/pyramid.py +31 -36
  96. sentry_sdk/integrations/quart.py +23 -28
  97. sentry_sdk/integrations/ray.py +73 -64
  98. sentry_sdk/integrations/redis/__init__.py +7 -4
  99. sentry_sdk/integrations/redis/_async_common.py +18 -12
  100. sentry_sdk/integrations/redis/_sync_common.py +16 -15
  101. sentry_sdk/integrations/redis/modules/caches.py +17 -8
  102. sentry_sdk/integrations/redis/modules/queries.py +9 -8
  103. sentry_sdk/integrations/redis/rb.py +3 -2
  104. sentry_sdk/integrations/redis/redis.py +4 -4
  105. sentry_sdk/integrations/redis/redis_cluster.py +10 -8
  106. sentry_sdk/integrations/redis/redis_py_cluster_legacy.py +3 -2
  107. sentry_sdk/integrations/redis/utils.py +21 -22
  108. sentry_sdk/integrations/rq.py +13 -16
  109. sentry_sdk/integrations/rust_tracing.py +10 -7
  110. sentry_sdk/integrations/sanic.py +34 -46
  111. sentry_sdk/integrations/serverless.py +22 -27
  112. sentry_sdk/integrations/socket.py +29 -17
  113. sentry_sdk/integrations/spark/__init__.py +1 -0
  114. sentry_sdk/integrations/spark/spark_driver.py +45 -83
  115. sentry_sdk/integrations/spark/spark_worker.py +7 -11
  116. sentry_sdk/integrations/sqlalchemy.py +22 -19
  117. sentry_sdk/integrations/starlette.py +89 -93
  118. sentry_sdk/integrations/starlite.py +31 -37
  119. sentry_sdk/integrations/statsig.py +5 -4
  120. sentry_sdk/integrations/stdlib.py +32 -28
  121. sentry_sdk/integrations/strawberry.py +63 -50
  122. sentry_sdk/integrations/sys_exit.py +7 -11
  123. sentry_sdk/integrations/threading.py +13 -15
  124. sentry_sdk/integrations/tornado.py +28 -32
  125. sentry_sdk/integrations/trytond.py +4 -3
  126. sentry_sdk/integrations/typer.py +8 -6
  127. sentry_sdk/integrations/unleash.py +5 -4
  128. sentry_sdk/integrations/wsgi.py +47 -46
  129. sentry_sdk/logger.py +13 -9
  130. sentry_sdk/monitor.py +16 -28
  131. sentry_sdk/opentelemetry/consts.py +11 -4
  132. sentry_sdk/opentelemetry/contextvars_context.py +17 -15
  133. sentry_sdk/opentelemetry/propagator.py +38 -21
  134. sentry_sdk/opentelemetry/sampler.py +51 -34
  135. sentry_sdk/opentelemetry/scope.py +46 -37
  136. sentry_sdk/opentelemetry/span_processor.py +43 -59
  137. sentry_sdk/opentelemetry/tracing.py +32 -12
  138. sentry_sdk/opentelemetry/utils.py +180 -196
  139. sentry_sdk/profiler/continuous_profiler.py +108 -97
  140. sentry_sdk/profiler/transaction_profiler.py +70 -97
  141. sentry_sdk/profiler/utils.py +11 -15
  142. sentry_sdk/scope.py +251 -264
  143. sentry_sdk/scrubber.py +22 -26
  144. sentry_sdk/serializer.py +48 -65
  145. sentry_sdk/session.py +44 -61
  146. sentry_sdk/sessions.py +35 -49
  147. sentry_sdk/spotlight.py +15 -21
  148. sentry_sdk/tracing.py +118 -184
  149. sentry_sdk/tracing_utils.py +103 -123
  150. sentry_sdk/transport.py +131 -157
  151. sentry_sdk/utils.py +278 -309
  152. sentry_sdk/worker.py +16 -28
  153. {sentry_sdk-3.0.0a2.dist-info → sentry_sdk-3.0.0a4.dist-info}/METADATA +1 -1
  154. sentry_sdk-3.0.0a4.dist-info/RECORD +168 -0
  155. sentry_sdk-3.0.0a2.dist-info/RECORD +0 -154
  156. {sentry_sdk-3.0.0a2.dist-info → sentry_sdk-3.0.0a4.dist-info}/WHEEL +0 -0
  157. {sentry_sdk-3.0.0a2.dist-info → sentry_sdk-3.0.0a4.dist-info}/entry_points.txt +0 -0
  158. {sentry_sdk-3.0.0a2.dist-info → sentry_sdk-3.0.0a4.dist-info}/licenses/LICENSE +0 -0
  159. {sentry_sdk-3.0.0a2.dist-info → sentry_sdk-3.0.0a4.dist-info}/top_level.txt +0 -0
@@ -1,3 +1,4 @@
1
+ from __future__ import annotations
1
2
  import sys
2
3
  import types
3
4
  from functools import wraps
@@ -35,8 +36,7 @@ class BeamIntegration(Integration):
35
36
  identifier = "beam"
36
37
 
37
38
  @staticmethod
38
- def setup_once():
39
- # type: () -> None
39
+ def setup_once() -> None:
40
40
  from apache_beam.transforms.core import DoFn, ParDo # type: ignore
41
41
 
42
42
  ignore_logger("root")
@@ -52,8 +52,7 @@ class BeamIntegration(Integration):
52
52
 
53
53
  old_init = ParDo.__init__
54
54
 
55
- def sentry_init_pardo(self, fn, *args, **kwargs):
56
- # type: (ParDo, Any, *Any, **Any) -> Any
55
+ def sentry_init_pardo(self: ParDo, fn: Any, *args: Any, **kwargs: Any) -> Any:
57
56
  # Do not monkey patch init twice
58
57
  if not getattr(self, "_sentry_is_patched", False):
59
58
  for func_name in function_patches:
@@ -79,14 +78,12 @@ class BeamIntegration(Integration):
79
78
  ParDo.__init__ = sentry_init_pardo
80
79
 
81
80
 
82
- def _wrap_inspect_call(cls, func_name):
83
- # type: (Any, Any) -> Any
81
+ def _wrap_inspect_call(cls: Any, func_name: Any) -> Any:
84
82
 
85
83
  if not hasattr(cls, func_name):
86
84
  return None
87
85
 
88
- def _inspect(self):
89
- # type: (Any) -> Any
86
+ def _inspect(self: Any) -> Any:
90
87
  """
91
88
  Inspect function overrides the way Beam gets argspec.
92
89
  """
@@ -113,15 +110,13 @@ def _wrap_inspect_call(cls, func_name):
113
110
  return _inspect
114
111
 
115
112
 
116
- def _wrap_task_call(func):
117
- # type: (F) -> F
113
+ def _wrap_task_call(func: F) -> F:
118
114
  """
119
115
  Wrap task call with a try catch to get exceptions.
120
116
  """
121
117
 
122
118
  @wraps(func)
123
- def _inner(*args, **kwargs):
124
- # type: (*Any, **Any) -> Any
119
+ def _inner(*args: Any, **kwargs: Any) -> Any:
125
120
  try:
126
121
  gen = func(*args, **kwargs)
127
122
  except Exception:
@@ -136,8 +131,7 @@ def _wrap_task_call(func):
136
131
 
137
132
 
138
133
  @ensure_integration_enabled(BeamIntegration)
139
- def _capture_exception(exc_info):
140
- # type: (ExcInfo) -> None
134
+ def _capture_exception(exc_info: ExcInfo) -> None:
141
135
  """
142
136
  Send Beam exception to Sentry.
143
137
  """
@@ -151,8 +145,7 @@ def _capture_exception(exc_info):
151
145
  sentry_sdk.capture_event(event, hint=hint)
152
146
 
153
147
 
154
- def raise_exception():
155
- # type: () -> None
148
+ def raise_exception() -> None:
156
149
  """
157
150
  Raise an exception.
158
151
  """
@@ -162,8 +155,7 @@ def raise_exception():
162
155
  reraise(*exc_info)
163
156
 
164
157
 
165
- def _wrap_generator_call(gen):
166
- # type: (Iterator[T]) -> Iterator[T]
158
+ def _wrap_generator_call(gen: Iterator[T]) -> Iterator[T]:
167
159
  """
168
160
  Wrap the generator to handle any failures.
169
161
  """
@@ -1,3 +1,4 @@
1
+ from __future__ import annotations
1
2
  from functools import partial
2
3
 
3
4
  import sentry_sdk
@@ -34,15 +35,15 @@ class Boto3Integration(Integration):
34
35
  origin = f"auto.http.{identifier}"
35
36
 
36
37
  @staticmethod
37
- def setup_once():
38
- # type: () -> None
38
+ def setup_once() -> None:
39
39
  version = parse_version(BOTOCORE_VERSION)
40
40
  _check_minimum_version(Boto3Integration, version, "botocore")
41
41
 
42
42
  orig_init = BaseClient.__init__
43
43
 
44
- def sentry_patched_init(self, *args, **kwargs):
45
- # type: (Type[BaseClient], *Any, **Any) -> None
44
+ def sentry_patched_init(
45
+ self: Type[BaseClient], *args: Any, **kwargs: Any
46
+ ) -> None:
46
47
  orig_init(self, *args, **kwargs)
47
48
  meta = self.meta
48
49
  service_id = meta.service_model.service_id.hyphenize()
@@ -57,14 +58,15 @@ class Boto3Integration(Integration):
57
58
 
58
59
 
59
60
  @ensure_integration_enabled(Boto3Integration)
60
- def _sentry_request_created(service_id, request, operation_name, **kwargs):
61
- # type: (str, AWSRequest, str, **Any) -> None
61
+ def _sentry_request_created(
62
+ service_id: str, request: AWSRequest, operation_name: str, **kwargs: Any
63
+ ) -> None:
62
64
  description = "aws.%s.%s" % (service_id, operation_name)
63
65
  span = sentry_sdk.start_span(
64
66
  op=OP.HTTP_CLIENT,
65
67
  name=description,
66
68
  origin=Boto3Integration.origin,
67
- only_if_parent=True,
69
+ only_as_child_span=True,
68
70
  )
69
71
 
70
72
  data = {
@@ -92,9 +94,10 @@ def _sentry_request_created(service_id, request, operation_name, **kwargs):
92
94
  request.context["_sentrysdk_span_data"] = data
93
95
 
94
96
 
95
- def _sentry_after_call(context, parsed, **kwargs):
96
- # type: (Dict[str, Any], Dict[str, Any], **Any) -> None
97
- span = context.pop("_sentrysdk_span", None) # type: Optional[Span]
97
+ def _sentry_after_call(
98
+ context: Dict[str, Any], parsed: Dict[str, Any], **kwargs: Any
99
+ ) -> None:
100
+ span: Optional[Span] = context.pop("_sentrysdk_span", None)
98
101
 
99
102
  # Span could be absent if the integration is disabled.
100
103
  if span is None:
@@ -117,13 +120,12 @@ def _sentry_after_call(context, parsed, **kwargs):
117
120
  op=OP.HTTP_CLIENT_STREAM,
118
121
  name=span.name,
119
122
  origin=Boto3Integration.origin,
120
- only_if_parent=True,
123
+ only_as_child_span=True,
121
124
  )
122
125
 
123
126
  orig_read = body.read
124
127
 
125
- def sentry_streaming_body_read(*args, **kwargs):
126
- # type: (*Any, **Any) -> bytes
128
+ def sentry_streaming_body_read(*args: Any, **kwargs: Any) -> bytes:
127
129
  try:
128
130
  ret = orig_read(*args, **kwargs)
129
131
  if not ret:
@@ -137,8 +139,7 @@ def _sentry_after_call(context, parsed, **kwargs):
137
139
 
138
140
  orig_close = body.close
139
141
 
140
- def sentry_streaming_body_close(*args, **kwargs):
141
- # type: (*Any, **Any) -> None
142
+ def sentry_streaming_body_close(*args: Any, **kwargs: Any) -> None:
142
143
  streaming_span.finish()
143
144
  orig_close(*args, **kwargs)
144
145
 
@@ -147,9 +148,10 @@ def _sentry_after_call(context, parsed, **kwargs):
147
148
  span.__exit__(None, None, None)
148
149
 
149
150
 
150
- def _sentry_after_call_error(context, exception, **kwargs):
151
- # type: (Dict[str, Any], Type[BaseException], **Any) -> None
152
- span = context.pop("_sentrysdk_span", None) # type: Optional[Span]
151
+ def _sentry_after_call_error(
152
+ context: Dict[str, Any], exception: Type[BaseException], **kwargs: Any
153
+ ) -> None:
154
+ span: Optional[Span] = context.pop("_sentrysdk_span", None)
153
155
 
154
156
  # Span could be absent if the integration is disabled.
155
157
  if span is None:
@@ -1,3 +1,4 @@
1
+ from __future__ import annotations
1
2
  import functools
2
3
 
3
4
  import sentry_sdk
@@ -55,11 +56,10 @@ class BottleIntegration(Integration):
55
56
 
56
57
  def __init__(
57
58
  self,
58
- transaction_style="endpoint", # type: str
59
+ transaction_style: str = "endpoint",
59
60
  *,
60
- failed_request_status_codes=_DEFAULT_FAILED_REQUEST_STATUS_CODES, # type: Set[int]
61
- ):
62
- # type: (...) -> None
61
+ failed_request_status_codes: Set[int] = _DEFAULT_FAILED_REQUEST_STATUS_CODES,
62
+ ) -> None:
63
63
 
64
64
  if transaction_style not in TRANSACTION_STYLE_VALUES:
65
65
  raise ValueError(
@@ -70,16 +70,16 @@ class BottleIntegration(Integration):
70
70
  self.failed_request_status_codes = failed_request_status_codes
71
71
 
72
72
  @staticmethod
73
- def setup_once():
74
- # type: () -> None
73
+ def setup_once() -> None:
75
74
  version = parse_version(BOTTLE_VERSION)
76
75
  _check_minimum_version(BottleIntegration, version)
77
76
 
78
77
  old_app = Bottle.__call__
79
78
 
80
79
  @ensure_integration_enabled(BottleIntegration, old_app)
81
- def sentry_patched_wsgi_app(self, environ, start_response):
82
- # type: (Any, Dict[str, str], Callable[..., Any]) -> _ScopedResponse
80
+ def sentry_patched_wsgi_app(
81
+ self: Any, environ: Dict[str, str], start_response: Callable[..., Any]
82
+ ) -> _ScopedResponse:
83
83
  middleware = SentryWsgiMiddleware(
84
84
  lambda *a, **kw: old_app(self, *a, **kw),
85
85
  span_origin=BottleIntegration.origin,
@@ -92,8 +92,7 @@ class BottleIntegration(Integration):
92
92
  old_handle = Bottle._handle
93
93
 
94
94
  @functools.wraps(old_handle)
95
- def _patched_handle(self, environ):
96
- # type: (Bottle, Dict[str, Any]) -> Any
95
+ def _patched_handle(self: Bottle, environ: Dict[str, Any]) -> Any:
97
96
  integration = sentry_sdk.get_client().get_integration(BottleIntegration)
98
97
  if integration is None:
99
98
  return old_handle(self, environ)
@@ -112,16 +111,14 @@ class BottleIntegration(Integration):
112
111
  old_make_callback = Route._make_callback
113
112
 
114
113
  @functools.wraps(old_make_callback)
115
- def patched_make_callback(self, *args, **kwargs):
116
- # type: (Route, *object, **object) -> Any
114
+ def patched_make_callback(self: Route, *args: object, **kwargs: object) -> Any:
117
115
  prepared_callback = old_make_callback(self, *args, **kwargs)
118
116
 
119
117
  integration = sentry_sdk.get_client().get_integration(BottleIntegration)
120
118
  if integration is None:
121
119
  return prepared_callback
122
120
 
123
- def wrapped_callback(*args, **kwargs):
124
- # type: (*object, **object) -> Any
121
+ def wrapped_callback(*args: object, **kwargs: object) -> Any:
125
122
  try:
126
123
  res = prepared_callback(*args, **kwargs)
127
124
  except Exception as exception:
@@ -142,38 +139,33 @@ class BottleIntegration(Integration):
142
139
 
143
140
 
144
141
  class BottleRequestExtractor(RequestExtractor):
145
- def env(self):
146
- # type: () -> Dict[str, str]
142
+ def env(self) -> Dict[str, str]:
147
143
  return self.request.environ
148
144
 
149
- def cookies(self):
150
- # type: () -> Dict[str, str]
145
+ def cookies(self) -> Dict[str, str]:
151
146
  return self.request.cookies
152
147
 
153
- def raw_data(self):
154
- # type: () -> bytes
148
+ def raw_data(self) -> bytes:
155
149
  return self.request.body.read()
156
150
 
157
- def form(self):
158
- # type: () -> FormsDict
151
+ def form(self) -> FormsDict:
159
152
  if self.is_json():
160
153
  return None
161
154
  return self.request.forms.decode()
162
155
 
163
- def files(self):
164
- # type: () -> Optional[Dict[str, str]]
156
+ def files(self) -> Optional[Dict[str, str]]:
165
157
  if self.is_json():
166
158
  return None
167
159
 
168
160
  return self.request.files
169
161
 
170
- def size_of_file(self, file):
171
- # type: (FileUpload) -> int
162
+ def size_of_file(self, file: FileUpload) -> int:
172
163
  return file.content_length
173
164
 
174
165
 
175
- def _set_transaction_name_and_source(event, transaction_style, request):
176
- # type: (Event, str, Any) -> None
166
+ def _set_transaction_name_and_source(
167
+ event: Event, transaction_style: str, request: Any
168
+ ) -> None:
177
169
  name = ""
178
170
 
179
171
  if transaction_style == "url":
@@ -196,11 +188,11 @@ def _set_transaction_name_and_source(event, transaction_style, request):
196
188
  event["transaction_info"] = {"source": SOURCE_FOR_STYLE[transaction_style]}
197
189
 
198
190
 
199
- def _make_request_event_processor(app, request, integration):
200
- # type: (Bottle, LocalRequest, BottleIntegration) -> EventProcessor
191
+ def _make_request_event_processor(
192
+ app: Bottle, request: LocalRequest, integration: BottleIntegration
193
+ ) -> EventProcessor:
201
194
 
202
- def event_processor(event, hint):
203
- # type: (Event, dict[str, Any]) -> Event
195
+ def event_processor(event: Event, hint: dict[str, Any]) -> Event:
204
196
  _set_transaction_name_and_source(event, integration.transaction_style, request)
205
197
 
206
198
  with capture_internal_exceptions():
@@ -211,8 +203,7 @@ def _make_request_event_processor(app, request, integration):
211
203
  return event_processor
212
204
 
213
205
 
214
- def _capture_exception(exception, handled):
215
- # type: (BaseException, bool) -> None
206
+ def _capture_exception(exception: BaseException, handled: bool) -> None:
216
207
  event, hint = event_from_exception(
217
208
  exception,
218
209
  client_options=sentry_sdk.get_client().options,
@@ -1,3 +1,4 @@
1
+ from __future__ import annotations
1
2
  import sys
2
3
  from collections.abc import Mapping
3
4
  from functools import wraps
@@ -62,11 +63,10 @@ class CeleryIntegration(Integration):
62
63
 
63
64
  def __init__(
64
65
  self,
65
- propagate_traces=True,
66
- monitor_beat_tasks=False,
67
- exclude_beat_tasks=None,
68
- ):
69
- # type: (bool, bool, Optional[List[str]]) -> None
66
+ propagate_traces: bool = True,
67
+ monitor_beat_tasks: bool = False,
68
+ exclude_beat_tasks: Optional[List[str]] = None,
69
+ ) -> None:
70
70
  self.propagate_traces = propagate_traces
71
71
  self.monitor_beat_tasks = monitor_beat_tasks
72
72
  self.exclude_beat_tasks = exclude_beat_tasks
@@ -76,8 +76,7 @@ class CeleryIntegration(Integration):
76
76
  _setup_celery_beat_signals(monitor_beat_tasks)
77
77
 
78
78
  @staticmethod
79
- def setup_once():
80
- # type: () -> None
79
+ def setup_once() -> None:
81
80
  _check_minimum_version(CeleryIntegration, CELERY_VERSION)
82
81
 
83
82
  _patch_build_tracer()
@@ -97,16 +96,14 @@ class CeleryIntegration(Integration):
97
96
  ignore_logger("celery.redirected")
98
97
 
99
98
 
100
- def _set_status(status):
101
- # type: (str) -> None
99
+ def _set_status(status: str) -> None:
102
100
  with capture_internal_exceptions():
103
101
  span = sentry_sdk.get_current_span()
104
102
  if span is not None:
105
103
  span.set_status(status)
106
104
 
107
105
 
108
- def _capture_exception(task, exc_info):
109
- # type: (Any, ExcInfo) -> None
106
+ def _capture_exception(task: Any, exc_info: ExcInfo) -> None:
110
107
  client = sentry_sdk.get_client()
111
108
  if client.get_integration(CeleryIntegration) is None:
112
109
  return
@@ -129,10 +126,10 @@ def _capture_exception(task, exc_info):
129
126
  sentry_sdk.capture_event(event, hint=hint)
130
127
 
131
128
 
132
- def _make_event_processor(task, uuid, args, kwargs, request=None):
133
- # type: (Any, Any, Any, Any, Optional[Any]) -> EventProcessor
134
- def event_processor(event, hint):
135
- # type: (Event, Hint) -> Optional[Event]
129
+ def _make_event_processor(
130
+ task: Any, uuid: Any, args: Any, kwargs: Any, request: Optional[Any] = None
131
+ ) -> EventProcessor:
132
+ def event_processor(event: Event, hint: Hint) -> Optional[Event]:
136
133
 
137
134
  with capture_internal_exceptions():
138
135
  tags = event.setdefault("tags", {})
@@ -158,8 +155,9 @@ def _make_event_processor(task, uuid, args, kwargs, request=None):
158
155
  return event_processor
159
156
 
160
157
 
161
- def _update_celery_task_headers(original_headers, span, monitor_beat_tasks):
162
- # type: (dict[str, Any], Optional[Span], bool) -> dict[str, Any]
158
+ def _update_celery_task_headers(
159
+ original_headers: dict[str, Any], span: Optional[Span], monitor_beat_tasks: bool
160
+ ) -> dict[str, Any]:
163
161
  """
164
162
  Updates the headers of the Celery task with the tracing information
165
163
  and eventually Sentry Crons monitoring information for beat tasks.
@@ -233,20 +231,16 @@ def _update_celery_task_headers(original_headers, span, monitor_beat_tasks):
233
231
 
234
232
 
235
233
  class NoOpMgr:
236
- def __enter__(self):
237
- # type: () -> None
234
+ def __enter__(self) -> None:
238
235
  return None
239
236
 
240
- def __exit__(self, exc_type, exc_value, traceback):
241
- # type: (Any, Any, Any) -> None
237
+ def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
242
238
  return None
243
239
 
244
240
 
245
- def _wrap_task_run(f):
246
- # type: (F) -> F
241
+ def _wrap_task_run(f: F) -> F:
247
242
  @wraps(f)
248
- def apply_async(*args, **kwargs):
249
- # type: (*Any, **Any) -> Any
243
+ def apply_async(*args: Any, **kwargs: Any) -> Any:
250
244
  # Note: kwargs can contain headers=None, so no setdefault!
251
245
  # Unsure which backend though.
252
246
  integration = sentry_sdk.get_client().get_integration(CeleryIntegration)
@@ -262,7 +256,7 @@ def _wrap_task_run(f):
262
256
  return f(*args, **kwargs)
263
257
 
264
258
  if isinstance(args[0], Task):
265
- task_name = args[0].name # type: str
259
+ task_name: str = args[0].name
266
260
  elif len(args) > 1 and isinstance(args[1], str):
267
261
  task_name = args[1]
268
262
  else:
@@ -270,16 +264,16 @@ def _wrap_task_run(f):
270
264
 
271
265
  task_started_from_beat = sentry_sdk.get_isolation_scope()._name == "celery-beat"
272
266
 
273
- span_mgr = (
267
+ span_mgr: Union[Span, NoOpMgr] = (
274
268
  sentry_sdk.start_span(
275
269
  op=OP.QUEUE_SUBMIT_CELERY,
276
270
  name=task_name,
277
271
  origin=CeleryIntegration.origin,
278
- only_if_parent=True,
272
+ only_as_child_span=True,
279
273
  )
280
274
  if not task_started_from_beat
281
275
  else NoOpMgr()
282
- ) # type: Union[Span, NoOpMgr]
276
+ )
283
277
 
284
278
  with span_mgr as span:
285
279
  kwargs["headers"] = _update_celery_task_headers(
@@ -290,8 +284,7 @@ def _wrap_task_run(f):
290
284
  return apply_async # type: ignore
291
285
 
292
286
 
293
- def _wrap_tracer(task, f):
294
- # type: (Any, F) -> F
287
+ def _wrap_tracer(task: Any, f: F) -> F:
295
288
 
296
289
  # Need to wrap tracer for pushing the scope before prerun is sent, and
297
290
  # popping it after postrun is sent.
@@ -301,8 +294,7 @@ def _wrap_tracer(task, f):
301
294
  # crashes.
302
295
  @wraps(f)
303
296
  @ensure_integration_enabled(CeleryIntegration, f)
304
- def _inner(*args, **kwargs):
305
- # type: (*Any, **Any) -> Any
297
+ def _inner(*args: Any, **kwargs: Any) -> Any:
306
298
  with isolation_scope() as scope:
307
299
  scope._name = "celery"
308
300
  scope.clear_breadcrumbs()
@@ -333,8 +325,7 @@ def _wrap_tracer(task, f):
333
325
  return _inner # type: ignore
334
326
 
335
327
 
336
- def _set_messaging_destination_name(task, span):
337
- # type: (Any, Span) -> None
328
+ def _set_messaging_destination_name(task: Any, span: Span) -> None:
338
329
  """Set "messaging.destination.name" tag for span"""
339
330
  with capture_internal_exceptions():
340
331
  delivery_info = task.request.delivery_info
@@ -346,8 +337,7 @@ def _set_messaging_destination_name(task, span):
346
337
  span.set_attribute(SPANDATA.MESSAGING_DESTINATION_NAME, routing_key)
347
338
 
348
339
 
349
- def _wrap_task_call(task, f):
350
- # type: (Any, F) -> F
340
+ def _wrap_task_call(task: Any, f: F) -> F:
351
341
 
352
342
  # Need to wrap task call because the exception is caught before we get to
353
343
  # see it. Also celery's reported stacktrace is untrustworthy.
@@ -358,14 +348,13 @@ def _wrap_task_call(task, f):
358
348
  # to add @functools.wraps(f) here.
359
349
  # https://github.com/getsentry/sentry-python/issues/421
360
350
  @ensure_integration_enabled(CeleryIntegration, f)
361
- def _inner(*args, **kwargs):
362
- # type: (*Any, **Any) -> Any
351
+ def _inner(*args: Any, **kwargs: Any) -> Any:
363
352
  try:
364
353
  with sentry_sdk.start_span(
365
354
  op=OP.QUEUE_PROCESS,
366
355
  name=task.name,
367
356
  origin=CeleryIntegration.origin,
368
- only_if_parent=True,
357
+ only_as_child_span=True,
369
358
  ) as span:
370
359
  _set_messaging_destination_name(task, span)
371
360
 
@@ -380,6 +369,7 @@ def _wrap_task_call(task, f):
380
369
  )
381
370
 
382
371
  if latency is not None:
372
+ latency *= 1000 # milliseconds
383
373
  span.set_attribute(
384
374
  SPANDATA.MESSAGING_MESSAGE_RECEIVE_LATENCY, latency
385
375
  )
@@ -409,14 +399,12 @@ def _wrap_task_call(task, f):
409
399
  return _inner # type: ignore
410
400
 
411
401
 
412
- def _patch_build_tracer():
413
- # type: () -> None
402
+ def _patch_build_tracer() -> None:
414
403
  import celery.app.trace as trace # type: ignore
415
404
 
416
405
  original_build_tracer = trace.build_tracer
417
406
 
418
- def sentry_build_tracer(name, task, *args, **kwargs):
419
- # type: (Any, Any, *Any, **Any) -> Any
407
+ def sentry_build_tracer(name: Any, task: Any, *args: Any, **kwargs: Any) -> Any:
420
408
  if not getattr(task, "_sentry_is_patched", False):
421
409
  # determine whether Celery will use __call__ or run and patch
422
410
  # accordingly
@@ -435,20 +423,17 @@ def _patch_build_tracer():
435
423
  trace.build_tracer = sentry_build_tracer
436
424
 
437
425
 
438
- def _patch_task_apply_async():
439
- # type: () -> None
426
+ def _patch_task_apply_async() -> None:
440
427
  Task.apply_async = _wrap_task_run(Task.apply_async)
441
428
 
442
429
 
443
- def _patch_celery_send_task():
444
- # type: () -> None
430
+ def _patch_celery_send_task() -> None:
445
431
  from celery import Celery
446
432
 
447
433
  Celery.send_task = _wrap_task_run(Celery.send_task)
448
434
 
449
435
 
450
- def _patch_worker_exit():
451
- # type: () -> None
436
+ def _patch_worker_exit() -> None:
452
437
 
453
438
  # Need to flush queue before worker shutdown because a crashing worker will
454
439
  # call os._exit
@@ -456,8 +441,7 @@ def _patch_worker_exit():
456
441
 
457
442
  original_workloop = Worker.workloop
458
443
 
459
- def sentry_workloop(*args, **kwargs):
460
- # type: (*Any, **Any) -> Any
444
+ def sentry_workloop(*args: Any, **kwargs: Any) -> Any:
461
445
  try:
462
446
  return original_workloop(*args, **kwargs)
463
447
  finally:
@@ -471,13 +455,11 @@ def _patch_worker_exit():
471
455
  Worker.workloop = sentry_workloop
472
456
 
473
457
 
474
- def _patch_producer_publish():
475
- # type: () -> None
458
+ def _patch_producer_publish() -> None:
476
459
  original_publish = Producer.publish
477
460
 
478
461
  @ensure_integration_enabled(CeleryIntegration, original_publish)
479
- def sentry_publish(self, *args, **kwargs):
480
- # type: (Producer, *Any, **Any) -> Any
462
+ def sentry_publish(self: Producer, *args: Any, **kwargs: Any) -> Any:
481
463
  kwargs_headers = kwargs.get("headers", {})
482
464
  if not isinstance(kwargs_headers, Mapping):
483
465
  # Ensure kwargs_headers is a Mapping, so we can safely call get().
@@ -498,7 +480,7 @@ def _patch_producer_publish():
498
480
  op=OP.QUEUE_PUBLISH,
499
481
  name=task_name,
500
482
  origin=CeleryIntegration.origin,
501
- only_if_parent=True,
483
+ only_as_child_span=True,
502
484
  ) as span:
503
485
  if task_id is not None:
504
486
  span.set_attribute(SPANDATA.MESSAGING_MESSAGE_ID, task_id)
@@ -521,8 +503,7 @@ def _patch_producer_publish():
521
503
  Producer.publish = sentry_publish
522
504
 
523
505
 
524
- def _prepopulate_attributes(task, args, kwargs):
525
- # type: (Any, *Any, **Any) -> dict[str, str]
506
+ def _prepopulate_attributes(task: Any, args: Any, kwargs: Any) -> dict[str, str]:
526
507
  attributes = {
527
508
  "celery.job.task": task.name,
528
509
  }