sentry-sdk 0.18.0__py2.py3-none-any.whl → 2.46.0__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.
Files changed (193) hide show
  1. sentry_sdk/__init__.py +48 -6
  2. sentry_sdk/_compat.py +64 -56
  3. sentry_sdk/_init_implementation.py +84 -0
  4. sentry_sdk/_log_batcher.py +172 -0
  5. sentry_sdk/_lru_cache.py +47 -0
  6. sentry_sdk/_metrics_batcher.py +167 -0
  7. sentry_sdk/_queue.py +81 -19
  8. sentry_sdk/_types.py +311 -11
  9. sentry_sdk/_werkzeug.py +98 -0
  10. sentry_sdk/ai/__init__.py +7 -0
  11. sentry_sdk/ai/monitoring.py +137 -0
  12. sentry_sdk/ai/utils.py +144 -0
  13. sentry_sdk/api.py +409 -67
  14. sentry_sdk/attachments.py +75 -0
  15. sentry_sdk/client.py +849 -103
  16. sentry_sdk/consts.py +1389 -34
  17. sentry_sdk/crons/__init__.py +10 -0
  18. sentry_sdk/crons/api.py +62 -0
  19. sentry_sdk/crons/consts.py +4 -0
  20. sentry_sdk/crons/decorator.py +135 -0
  21. sentry_sdk/debug.py +12 -15
  22. sentry_sdk/envelope.py +112 -61
  23. sentry_sdk/feature_flags.py +71 -0
  24. sentry_sdk/hub.py +442 -386
  25. sentry_sdk/integrations/__init__.py +228 -58
  26. sentry_sdk/integrations/_asgi_common.py +108 -0
  27. sentry_sdk/integrations/_wsgi_common.py +131 -40
  28. sentry_sdk/integrations/aiohttp.py +221 -72
  29. sentry_sdk/integrations/anthropic.py +439 -0
  30. sentry_sdk/integrations/argv.py +4 -6
  31. sentry_sdk/integrations/ariadne.py +161 -0
  32. sentry_sdk/integrations/arq.py +247 -0
  33. sentry_sdk/integrations/asgi.py +237 -135
  34. sentry_sdk/integrations/asyncio.py +144 -0
  35. sentry_sdk/integrations/asyncpg.py +208 -0
  36. sentry_sdk/integrations/atexit.py +13 -18
  37. sentry_sdk/integrations/aws_lambda.py +233 -80
  38. sentry_sdk/integrations/beam.py +27 -35
  39. sentry_sdk/integrations/boto3.py +137 -0
  40. sentry_sdk/integrations/bottle.py +91 -69
  41. sentry_sdk/integrations/celery/__init__.py +529 -0
  42. sentry_sdk/integrations/celery/beat.py +293 -0
  43. sentry_sdk/integrations/celery/utils.py +43 -0
  44. sentry_sdk/integrations/chalice.py +35 -28
  45. sentry_sdk/integrations/clickhouse_driver.py +177 -0
  46. sentry_sdk/integrations/cloud_resource_context.py +280 -0
  47. sentry_sdk/integrations/cohere.py +274 -0
  48. sentry_sdk/integrations/dedupe.py +32 -8
  49. sentry_sdk/integrations/django/__init__.py +343 -89
  50. sentry_sdk/integrations/django/asgi.py +201 -22
  51. sentry_sdk/integrations/django/caching.py +204 -0
  52. sentry_sdk/integrations/django/middleware.py +80 -32
  53. sentry_sdk/integrations/django/signals_handlers.py +91 -0
  54. sentry_sdk/integrations/django/templates.py +69 -2
  55. sentry_sdk/integrations/django/transactions.py +39 -14
  56. sentry_sdk/integrations/django/views.py +69 -16
  57. sentry_sdk/integrations/dramatiq.py +226 -0
  58. sentry_sdk/integrations/excepthook.py +19 -13
  59. sentry_sdk/integrations/executing.py +5 -6
  60. sentry_sdk/integrations/falcon.py +128 -65
  61. sentry_sdk/integrations/fastapi.py +141 -0
  62. sentry_sdk/integrations/flask.py +114 -75
  63. sentry_sdk/integrations/gcp.py +67 -36
  64. sentry_sdk/integrations/gnu_backtrace.py +14 -22
  65. sentry_sdk/integrations/google_genai/__init__.py +301 -0
  66. sentry_sdk/integrations/google_genai/consts.py +16 -0
  67. sentry_sdk/integrations/google_genai/streaming.py +155 -0
  68. sentry_sdk/integrations/google_genai/utils.py +576 -0
  69. sentry_sdk/integrations/gql.py +162 -0
  70. sentry_sdk/integrations/graphene.py +151 -0
  71. sentry_sdk/integrations/grpc/__init__.py +168 -0
  72. sentry_sdk/integrations/grpc/aio/__init__.py +7 -0
  73. sentry_sdk/integrations/grpc/aio/client.py +95 -0
  74. sentry_sdk/integrations/grpc/aio/server.py +100 -0
  75. sentry_sdk/integrations/grpc/client.py +91 -0
  76. sentry_sdk/integrations/grpc/consts.py +1 -0
  77. sentry_sdk/integrations/grpc/server.py +66 -0
  78. sentry_sdk/integrations/httpx.py +178 -0
  79. sentry_sdk/integrations/huey.py +174 -0
  80. sentry_sdk/integrations/huggingface_hub.py +378 -0
  81. sentry_sdk/integrations/langchain.py +1132 -0
  82. sentry_sdk/integrations/langgraph.py +337 -0
  83. sentry_sdk/integrations/launchdarkly.py +61 -0
  84. sentry_sdk/integrations/litellm.py +287 -0
  85. sentry_sdk/integrations/litestar.py +315 -0
  86. sentry_sdk/integrations/logging.py +261 -85
  87. sentry_sdk/integrations/loguru.py +213 -0
  88. sentry_sdk/integrations/mcp.py +566 -0
  89. sentry_sdk/integrations/modules.py +6 -33
  90. sentry_sdk/integrations/openai.py +725 -0
  91. sentry_sdk/integrations/openai_agents/__init__.py +61 -0
  92. sentry_sdk/integrations/openai_agents/consts.py +1 -0
  93. sentry_sdk/integrations/openai_agents/patches/__init__.py +5 -0
  94. sentry_sdk/integrations/openai_agents/patches/agent_run.py +140 -0
  95. sentry_sdk/integrations/openai_agents/patches/error_tracing.py +77 -0
  96. sentry_sdk/integrations/openai_agents/patches/models.py +50 -0
  97. sentry_sdk/integrations/openai_agents/patches/runner.py +45 -0
  98. sentry_sdk/integrations/openai_agents/patches/tools.py +77 -0
  99. sentry_sdk/integrations/openai_agents/spans/__init__.py +5 -0
  100. sentry_sdk/integrations/openai_agents/spans/agent_workflow.py +21 -0
  101. sentry_sdk/integrations/openai_agents/spans/ai_client.py +42 -0
  102. sentry_sdk/integrations/openai_agents/spans/execute_tool.py +48 -0
  103. sentry_sdk/integrations/openai_agents/spans/handoff.py +19 -0
  104. sentry_sdk/integrations/openai_agents/spans/invoke_agent.py +86 -0
  105. sentry_sdk/integrations/openai_agents/utils.py +199 -0
  106. sentry_sdk/integrations/openfeature.py +35 -0
  107. sentry_sdk/integrations/opentelemetry/__init__.py +7 -0
  108. sentry_sdk/integrations/opentelemetry/consts.py +5 -0
  109. sentry_sdk/integrations/opentelemetry/integration.py +58 -0
  110. sentry_sdk/integrations/opentelemetry/propagator.py +117 -0
  111. sentry_sdk/integrations/opentelemetry/span_processor.py +391 -0
  112. sentry_sdk/integrations/otlp.py +82 -0
  113. sentry_sdk/integrations/pure_eval.py +20 -11
  114. sentry_sdk/integrations/pydantic_ai/__init__.py +47 -0
  115. sentry_sdk/integrations/pydantic_ai/consts.py +1 -0
  116. sentry_sdk/integrations/pydantic_ai/patches/__init__.py +4 -0
  117. sentry_sdk/integrations/pydantic_ai/patches/agent_run.py +215 -0
  118. sentry_sdk/integrations/pydantic_ai/patches/graph_nodes.py +110 -0
  119. sentry_sdk/integrations/pydantic_ai/patches/model_request.py +40 -0
  120. sentry_sdk/integrations/pydantic_ai/patches/tools.py +98 -0
  121. sentry_sdk/integrations/pydantic_ai/spans/__init__.py +3 -0
  122. sentry_sdk/integrations/pydantic_ai/spans/ai_client.py +246 -0
  123. sentry_sdk/integrations/pydantic_ai/spans/execute_tool.py +49 -0
  124. sentry_sdk/integrations/pydantic_ai/spans/invoke_agent.py +112 -0
  125. sentry_sdk/integrations/pydantic_ai/utils.py +223 -0
  126. sentry_sdk/integrations/pymongo.py +214 -0
  127. sentry_sdk/integrations/pyramid.py +71 -60
  128. sentry_sdk/integrations/quart.py +237 -0
  129. sentry_sdk/integrations/ray.py +165 -0
  130. sentry_sdk/integrations/redis/__init__.py +48 -0
  131. sentry_sdk/integrations/redis/_async_common.py +116 -0
  132. sentry_sdk/integrations/redis/_sync_common.py +119 -0
  133. sentry_sdk/integrations/redis/consts.py +19 -0
  134. sentry_sdk/integrations/redis/modules/__init__.py +0 -0
  135. sentry_sdk/integrations/redis/modules/caches.py +118 -0
  136. sentry_sdk/integrations/redis/modules/queries.py +65 -0
  137. sentry_sdk/integrations/redis/rb.py +32 -0
  138. sentry_sdk/integrations/redis/redis.py +69 -0
  139. sentry_sdk/integrations/redis/redis_cluster.py +107 -0
  140. sentry_sdk/integrations/redis/redis_py_cluster_legacy.py +50 -0
  141. sentry_sdk/integrations/redis/utils.py +148 -0
  142. sentry_sdk/integrations/rq.py +62 -52
  143. sentry_sdk/integrations/rust_tracing.py +284 -0
  144. sentry_sdk/integrations/sanic.py +248 -114
  145. sentry_sdk/integrations/serverless.py +13 -22
  146. sentry_sdk/integrations/socket.py +96 -0
  147. sentry_sdk/integrations/spark/spark_driver.py +115 -62
  148. sentry_sdk/integrations/spark/spark_worker.py +42 -50
  149. sentry_sdk/integrations/sqlalchemy.py +82 -37
  150. sentry_sdk/integrations/starlette.py +737 -0
  151. sentry_sdk/integrations/starlite.py +292 -0
  152. sentry_sdk/integrations/statsig.py +37 -0
  153. sentry_sdk/integrations/stdlib.py +100 -58
  154. sentry_sdk/integrations/strawberry.py +394 -0
  155. sentry_sdk/integrations/sys_exit.py +70 -0
  156. sentry_sdk/integrations/threading.py +142 -38
  157. sentry_sdk/integrations/tornado.py +68 -53
  158. sentry_sdk/integrations/trytond.py +15 -20
  159. sentry_sdk/integrations/typer.py +60 -0
  160. sentry_sdk/integrations/unleash.py +33 -0
  161. sentry_sdk/integrations/unraisablehook.py +53 -0
  162. sentry_sdk/integrations/wsgi.py +126 -125
  163. sentry_sdk/logger.py +96 -0
  164. sentry_sdk/metrics.py +81 -0
  165. sentry_sdk/monitor.py +120 -0
  166. sentry_sdk/profiler/__init__.py +49 -0
  167. sentry_sdk/profiler/continuous_profiler.py +730 -0
  168. sentry_sdk/profiler/transaction_profiler.py +839 -0
  169. sentry_sdk/profiler/utils.py +195 -0
  170. sentry_sdk/scope.py +1542 -112
  171. sentry_sdk/scrubber.py +177 -0
  172. sentry_sdk/serializer.py +152 -210
  173. sentry_sdk/session.py +177 -0
  174. sentry_sdk/sessions.py +202 -179
  175. sentry_sdk/spotlight.py +242 -0
  176. sentry_sdk/tracing.py +1202 -294
  177. sentry_sdk/tracing_utils.py +1236 -0
  178. sentry_sdk/transport.py +693 -189
  179. sentry_sdk/types.py +52 -0
  180. sentry_sdk/utils.py +1395 -228
  181. sentry_sdk/worker.py +30 -17
  182. sentry_sdk-2.46.0.dist-info/METADATA +268 -0
  183. sentry_sdk-2.46.0.dist-info/RECORD +189 -0
  184. {sentry_sdk-0.18.0.dist-info → sentry_sdk-2.46.0.dist-info}/WHEEL +1 -1
  185. sentry_sdk-2.46.0.dist-info/entry_points.txt +2 -0
  186. sentry_sdk-2.46.0.dist-info/licenses/LICENSE +21 -0
  187. sentry_sdk/_functools.py +0 -66
  188. sentry_sdk/integrations/celery.py +0 -275
  189. sentry_sdk/integrations/redis.py +0 -103
  190. sentry_sdk-0.18.0.dist-info/LICENSE +0 -9
  191. sentry_sdk-0.18.0.dist-info/METADATA +0 -66
  192. sentry_sdk-0.18.0.dist-info/RECORD +0 -65
  193. {sentry_sdk-0.18.0.dist-info → sentry_sdk-2.46.0.dist-info}/top_level.txt +0 -0
sentry_sdk/_queue.py CHANGED
@@ -1,14 +1,74 @@
1
1
  """
2
- A fork of Python 3.6's stdlib queue with Lock swapped out for RLock to avoid a
3
- deadlock while garbage collecting.
2
+ A fork of Python 3.6's stdlib queue (found in Pythons 'cpython/Lib/queue.py')
3
+ with Lock swapped out for RLock to avoid a deadlock while garbage collecting.
4
4
 
5
- See
5
+ https://github.com/python/cpython/blob/v3.6.12/Lib/queue.py
6
+
7
+
8
+ See also
6
9
  https://codewithoutrules.com/2017/08/16/concurrency-python/
7
10
  https://bugs.python.org/issue14976
8
11
  https://github.com/sqlalchemy/sqlalchemy/blob/4eb747b61f0c1b1c25bdee3856d7195d10a0c227/lib/sqlalchemy/queue.py#L1
9
12
 
10
13
  We also vendor the code to evade eventlet's broken monkeypatching, see
11
14
  https://github.com/getsentry/sentry-python/pull/484
15
+
16
+
17
+ Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
18
+ 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Python Software Foundation;
19
+
20
+ All Rights Reserved
21
+
22
+
23
+ PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
24
+ --------------------------------------------
25
+
26
+ 1. This LICENSE AGREEMENT is between the Python Software Foundation
27
+ ("PSF"), and the Individual or Organization ("Licensee") accessing and
28
+ otherwise using this software ("Python") in source or binary form and
29
+ its associated documentation.
30
+
31
+ 2. Subject to the terms and conditions of this License Agreement, PSF hereby
32
+ grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
33
+ analyze, test, perform and/or display publicly, prepare derivative works,
34
+ distribute, and otherwise use Python alone or in any derivative version,
35
+ provided, however, that PSF's License Agreement and PSF's notice of copyright,
36
+ i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
37
+ 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Python Software Foundation;
38
+ All Rights Reserved" are retained in Python alone or in any derivative version
39
+ prepared by Licensee.
40
+
41
+ 3. In the event Licensee prepares a derivative work that is based on
42
+ or incorporates Python or any part thereof, and wants to make
43
+ the derivative work available to others as provided herein, then
44
+ Licensee hereby agrees to include in any such work a brief summary of
45
+ the changes made to Python.
46
+
47
+ 4. PSF is making Python available to Licensee on an "AS IS"
48
+ basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
49
+ IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
50
+ DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
51
+ FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
52
+ INFRINGE ANY THIRD PARTY RIGHTS.
53
+
54
+ 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
55
+ FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
56
+ A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
57
+ OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
58
+
59
+ 6. This License Agreement will automatically terminate upon a material
60
+ breach of its terms and conditions.
61
+
62
+ 7. Nothing in this License Agreement shall be deemed to create any
63
+ relationship of agency, partnership, or joint venture between PSF and
64
+ Licensee. This License Agreement does not grant permission to use PSF
65
+ trademarks or trade name in a trademark sense to endorse or promote
66
+ products or services of Licensee, or any third party.
67
+
68
+ 8. By copying, installing or otherwise using Python, Licensee
69
+ agrees to be bound by the terms and conditions of this License
70
+ Agreement.
71
+
12
72
  """
13
73
 
14
74
  import threading
@@ -16,25 +76,27 @@ import threading
16
76
  from collections import deque
17
77
  from time import time
18
78
 
19
- from sentry_sdk._types import MYPY
79
+ from typing import TYPE_CHECKING
20
80
 
21
- if MYPY:
81
+ if TYPE_CHECKING:
22
82
  from typing import Any
23
83
 
24
- __all__ = ["Empty", "Full", "Queue"]
84
+ __all__ = ["EmptyError", "FullError", "Queue"]
25
85
 
26
86
 
27
- class Empty(Exception):
87
+ class EmptyError(Exception):
28
88
  "Exception raised by Queue.get(block=0)/get_nowait()."
89
+
29
90
  pass
30
91
 
31
92
 
32
- class Full(Exception):
93
+ class FullError(Exception):
33
94
  "Exception raised by Queue.put(block=0)/put_nowait()."
95
+
34
96
  pass
35
97
 
36
98
 
37
- class Queue(object):
99
+ class Queue:
38
100
  """Create a queue object with a given maximum size.
39
101
 
40
102
  If maxsize is <= 0, the queue size is infinite.
@@ -134,16 +196,16 @@ class Queue(object):
134
196
  If optional args 'block' is true and 'timeout' is None (the default),
135
197
  block if necessary until a free slot is available. If 'timeout' is
136
198
  a non-negative number, it blocks at most 'timeout' seconds and raises
137
- the Full exception if no free slot was available within that time.
199
+ the FullError exception if no free slot was available within that time.
138
200
  Otherwise ('block' is false), put an item on the queue if a free slot
139
- is immediately available, else raise the Full exception ('timeout'
201
+ is immediately available, else raise the FullError exception ('timeout'
140
202
  is ignored in that case).
141
203
  """
142
204
  with self.not_full:
143
205
  if self.maxsize > 0:
144
206
  if not block:
145
207
  if self._qsize() >= self.maxsize:
146
- raise Full()
208
+ raise FullError()
147
209
  elif timeout is None:
148
210
  while self._qsize() >= self.maxsize:
149
211
  self.not_full.wait()
@@ -154,7 +216,7 @@ class Queue(object):
154
216
  while self._qsize() >= self.maxsize:
155
217
  remaining = endtime - time()
156
218
  if remaining <= 0.0:
157
- raise Full
219
+ raise FullError()
158
220
  self.not_full.wait(remaining)
159
221
  self._put(item)
160
222
  self.unfinished_tasks += 1
@@ -166,15 +228,15 @@ class Queue(object):
166
228
  If optional args 'block' is true and 'timeout' is None (the default),
167
229
  block if necessary until an item is available. If 'timeout' is
168
230
  a non-negative number, it blocks at most 'timeout' seconds and raises
169
- the Empty exception if no item was available within that time.
231
+ the EmptyError exception if no item was available within that time.
170
232
  Otherwise ('block' is false), return an item if one is immediately
171
- available, else raise the Empty exception ('timeout' is ignored
233
+ available, else raise the EmptyError exception ('timeout' is ignored
172
234
  in that case).
173
235
  """
174
236
  with self.not_empty:
175
237
  if not block:
176
238
  if not self._qsize():
177
- raise Empty()
239
+ raise EmptyError()
178
240
  elif timeout is None:
179
241
  while not self._qsize():
180
242
  self.not_empty.wait()
@@ -185,7 +247,7 @@ class Queue(object):
185
247
  while not self._qsize():
186
248
  remaining = endtime - time()
187
249
  if remaining <= 0.0:
188
- raise Empty()
250
+ raise EmptyError()
189
251
  self.not_empty.wait(remaining)
190
252
  item = self._get()
191
253
  self.not_full.notify()
@@ -195,7 +257,7 @@ class Queue(object):
195
257
  """Put an item into the queue without blocking.
196
258
 
197
259
  Only enqueue the item if a free slot is immediately available.
198
- Otherwise raise the Full exception.
260
+ Otherwise raise the FullError exception.
199
261
  """
200
262
  return self.put(item, block=False)
201
263
 
@@ -203,7 +265,7 @@ class Queue(object):
203
265
  """Remove and return an item from the queue without blocking.
204
266
 
205
267
  Only get an item if one is immediately available. Otherwise
206
- raise the Empty exception.
268
+ raise the EmptyError exception.
207
269
  """
208
270
  return self.get(block=False)
209
271
 
sentry_sdk/_types.py CHANGED
@@ -1,38 +1,338 @@
1
- try:
2
- from typing import TYPE_CHECKING as MYPY
3
- except ImportError:
4
- MYPY = False
1
+ from typing import TYPE_CHECKING, TypeVar, Union
5
2
 
6
3
 
7
- if MYPY:
4
+ # Re-exported for compat, since code out there in the wild might use this variable.
5
+ MYPY = TYPE_CHECKING
6
+
7
+
8
+ SENSITIVE_DATA_SUBSTITUTE = "[Filtered]"
9
+
10
+
11
+ class AnnotatedValue:
12
+ """
13
+ Meta information for a data field in the event payload.
14
+ This is to tell Relay that we have tampered with the fields value.
15
+ See:
16
+ https://github.com/getsentry/relay/blob/be12cd49a0f06ea932ed9b9f93a655de5d6ad6d1/relay-general/src/types/meta.rs#L407-L423
17
+ """
18
+
19
+ __slots__ = ("value", "metadata")
20
+
21
+ def __init__(self, value, metadata):
22
+ # type: (Optional[Any], Dict[str, Any]) -> None
23
+ self.value = value
24
+ self.metadata = metadata
25
+
26
+ def __eq__(self, other):
27
+ # type: (Any) -> bool
28
+ if not isinstance(other, AnnotatedValue):
29
+ return False
30
+
31
+ return self.value == other.value and self.metadata == other.metadata
32
+
33
+ def __str__(self):
34
+ # type: (AnnotatedValue) -> str
35
+ return str({"value": str(self.value), "metadata": str(self.metadata)})
36
+
37
+ def __len__(self):
38
+ # type: (AnnotatedValue) -> int
39
+ if self.value is not None:
40
+ return len(self.value)
41
+ else:
42
+ return 0
43
+
44
+ @classmethod
45
+ def removed_because_raw_data(cls):
46
+ # type: () -> AnnotatedValue
47
+ """The value was removed because it could not be parsed. This is done for request body values that are not json nor a form."""
48
+ return AnnotatedValue(
49
+ value="",
50
+ metadata={
51
+ "rem": [ # Remark
52
+ [
53
+ "!raw", # Unparsable raw data
54
+ "x", # The fields original value was removed
55
+ ]
56
+ ]
57
+ },
58
+ )
59
+
60
+ @classmethod
61
+ def removed_because_over_size_limit(cls, value=""):
62
+ # type: (Any) -> AnnotatedValue
63
+ """
64
+ The actual value was removed because the size of the field exceeded the configured maximum size,
65
+ for example specified with the max_request_body_size sdk option.
66
+ """
67
+ return AnnotatedValue(
68
+ value=value,
69
+ metadata={
70
+ "rem": [ # Remark
71
+ [
72
+ "!config", # Because of configured maximum size
73
+ "x", # The fields original value was removed
74
+ ]
75
+ ]
76
+ },
77
+ )
78
+
79
+ @classmethod
80
+ def substituted_because_contains_sensitive_data(cls):
81
+ # type: () -> AnnotatedValue
82
+ """The actual value was removed because it contained sensitive information."""
83
+ return AnnotatedValue(
84
+ value=SENSITIVE_DATA_SUBSTITUTE,
85
+ metadata={
86
+ "rem": [ # Remark
87
+ [
88
+ "!config", # Because of SDK configuration (in this case the config is the hard coded removal of certain django cookies)
89
+ "s", # The fields original value was substituted
90
+ ]
91
+ ]
92
+ },
93
+ )
94
+
95
+
96
+ T = TypeVar("T")
97
+ Annotated = Union[AnnotatedValue, T]
98
+
99
+
100
+ if TYPE_CHECKING:
101
+ from collections.abc import Container, MutableMapping, Sequence
102
+
103
+ from datetime import datetime
104
+
8
105
  from types import TracebackType
9
106
  from typing import Any
10
107
  from typing import Callable
11
108
  from typing import Dict
109
+ from typing import Mapping
110
+ from typing import NotRequired
12
111
  from typing import Optional
13
112
  from typing import Tuple
14
113
  from typing import Type
15
- from typing_extensions import Literal
114
+ from typing_extensions import Literal, TypedDict
115
+
116
+ class SDKInfo(TypedDict):
117
+ name: str
118
+ version: str
119
+ packages: Sequence[Mapping[str, str]]
120
+
121
+ # "critical" is an alias of "fatal" recognized by Relay
122
+ LogLevelStr = Literal["fatal", "critical", "error", "warning", "info", "debug"]
16
123
 
17
- ExcInfo = Tuple[
18
- Optional[Type[BaseException]], Optional[BaseException], Optional[TracebackType]
124
+ DurationUnit = Literal[
125
+ "nanosecond",
126
+ "microsecond",
127
+ "millisecond",
128
+ "second",
129
+ "minute",
130
+ "hour",
131
+ "day",
132
+ "week",
19
133
  ]
20
134
 
21
- Event = Dict[str, Any]
135
+ InformationUnit = Literal[
136
+ "bit",
137
+ "byte",
138
+ "kilobyte",
139
+ "kibibyte",
140
+ "megabyte",
141
+ "mebibyte",
142
+ "gigabyte",
143
+ "gibibyte",
144
+ "terabyte",
145
+ "tebibyte",
146
+ "petabyte",
147
+ "pebibyte",
148
+ "exabyte",
149
+ "exbibyte",
150
+ ]
151
+
152
+ FractionUnit = Literal["ratio", "percent"]
153
+ MeasurementUnit = Union[DurationUnit, InformationUnit, FractionUnit, str]
154
+
155
+ MeasurementValue = TypedDict(
156
+ "MeasurementValue",
157
+ {
158
+ "value": float,
159
+ "unit": NotRequired[Optional[MeasurementUnit]],
160
+ },
161
+ )
162
+
163
+ Event = TypedDict(
164
+ "Event",
165
+ {
166
+ "breadcrumbs": Annotated[
167
+ dict[Literal["values"], list[dict[str, Any]]]
168
+ ], # TODO: We can expand on this type
169
+ "check_in_id": str,
170
+ "contexts": dict[str, dict[str, object]],
171
+ "dist": str,
172
+ "duration": Optional[float],
173
+ "environment": Optional[str],
174
+ "errors": list[dict[str, Any]], # TODO: We can expand on this type
175
+ "event_id": str,
176
+ "exception": dict[
177
+ Literal["values"], list[dict[str, Any]]
178
+ ], # TODO: We can expand on this type
179
+ "extra": MutableMapping[str, object],
180
+ "fingerprint": list[str],
181
+ "level": LogLevelStr,
182
+ "logentry": Mapping[str, object],
183
+ "logger": str,
184
+ "measurements": dict[str, MeasurementValue],
185
+ "message": str,
186
+ "modules": dict[str, str],
187
+ "monitor_config": Mapping[str, object],
188
+ "monitor_slug": Optional[str],
189
+ "platform": Literal["python"],
190
+ "profile": object, # Should be sentry_sdk.profiler.Profile, but we can't import that here due to circular imports
191
+ "release": Optional[str],
192
+ "request": dict[str, object],
193
+ "sdk": Mapping[str, object],
194
+ "server_name": str,
195
+ "spans": Annotated[list[dict[str, object]]],
196
+ "stacktrace": dict[
197
+ str, object
198
+ ], # We access this key in the code, but I am unsure whether we ever set it
199
+ "start_timestamp": datetime,
200
+ "status": Optional[str],
201
+ "tags": MutableMapping[
202
+ str, str
203
+ ], # Tags must be less than 200 characters each
204
+ "threads": dict[
205
+ Literal["values"], list[dict[str, Any]]
206
+ ], # TODO: We can expand on this type
207
+ "timestamp": Optional[datetime], # Must be set before sending the event
208
+ "transaction": str,
209
+ "transaction_info": Mapping[str, Any], # TODO: We can expand on this type
210
+ "type": Literal["check_in", "transaction"],
211
+ "user": dict[str, object],
212
+ "_dropped_spans": int,
213
+ },
214
+ total=False,
215
+ )
216
+
217
+ ExcInfo = Union[
218
+ tuple[Type[BaseException], BaseException, Optional[TracebackType]],
219
+ tuple[None, None, None],
220
+ ]
221
+
222
+ # TODO: Make a proper type definition for this (PRs welcome!)
22
223
  Hint = Dict[str, Any]
23
224
 
225
+ Log = TypedDict(
226
+ "Log",
227
+ {
228
+ "severity_text": str,
229
+ "severity_number": int,
230
+ "body": str,
231
+ "attributes": dict[str, str | bool | float | int],
232
+ "time_unix_nano": int,
233
+ "trace_id": Optional[str],
234
+ },
235
+ )
236
+
237
+ MetricType = Literal["counter", "gauge", "distribution"]
238
+
239
+ MetricAttributeValue = TypedDict(
240
+ "MetricAttributeValue",
241
+ {
242
+ "value": Union[str, bool, float, int],
243
+ "type": Literal["string", "boolean", "double", "integer"],
244
+ },
245
+ )
246
+
247
+ Metric = TypedDict(
248
+ "Metric",
249
+ {
250
+ "timestamp": float,
251
+ "trace_id": Optional[str],
252
+ "span_id": Optional[str],
253
+ "name": str,
254
+ "type": MetricType,
255
+ "value": float,
256
+ "unit": Optional[str],
257
+ "attributes": dict[str, str | bool | float | int],
258
+ },
259
+ )
260
+
261
+ MetricProcessor = Callable[[Metric, Hint], Optional[Metric]]
262
+
263
+ # TODO: Make a proper type definition for this (PRs welcome!)
24
264
  Breadcrumb = Dict[str, Any]
265
+
266
+ # TODO: Make a proper type definition for this (PRs welcome!)
25
267
  BreadcrumbHint = Dict[str, Any]
26
268
 
269
+ # TODO: Make a proper type definition for this (PRs welcome!)
270
+ SamplingContext = Dict[str, Any]
271
+
27
272
  EventProcessor = Callable[[Event, Hint], Optional[Event]]
28
273
  ErrorProcessor = Callable[[Event, ExcInfo], Optional[Event]]
29
274
  BreadcrumbProcessor = Callable[[Breadcrumb, BreadcrumbHint], Optional[Breadcrumb]]
275
+ TransactionProcessor = Callable[[Event, Hint], Optional[Event]]
276
+ LogProcessor = Callable[[Log, Hint], Optional[Log]]
277
+
278
+ TracesSampler = Callable[[SamplingContext], Union[float, int, bool]]
30
279
 
31
280
  # https://github.com/python/mypy/issues/5710
32
281
  NotImplementedType = Any
33
282
 
34
283
  EventDataCategory = Literal[
35
- "default", "error", "crash", "transaction", "security", "attachment", "session"
284
+ "default",
285
+ "error",
286
+ "crash",
287
+ "transaction",
288
+ "security",
289
+ "attachment",
290
+ "session",
291
+ "internal",
292
+ "profile",
293
+ "profile_chunk",
294
+ "monitor",
295
+ "span",
296
+ "log_item",
297
+ "trace_metric",
36
298
  ]
37
299
  SessionStatus = Literal["ok", "exited", "crashed", "abnormal"]
38
- EndpointType = Literal["store", "envelope"]
300
+
301
+ ContinuousProfilerMode = Literal["thread", "gevent", "unknown"]
302
+ ProfilerMode = Union[ContinuousProfilerMode, Literal["sleep"]]
303
+
304
+ MonitorConfigScheduleType = Literal["crontab", "interval"]
305
+ MonitorConfigScheduleUnit = Literal[
306
+ "year",
307
+ "month",
308
+ "week",
309
+ "day",
310
+ "hour",
311
+ "minute",
312
+ "second", # not supported in Sentry and will result in a warning
313
+ ]
314
+
315
+ MonitorConfigSchedule = TypedDict(
316
+ "MonitorConfigSchedule",
317
+ {
318
+ "type": MonitorConfigScheduleType,
319
+ "value": Union[int, str],
320
+ "unit": MonitorConfigScheduleUnit,
321
+ },
322
+ total=False,
323
+ )
324
+
325
+ MonitorConfig = TypedDict(
326
+ "MonitorConfig",
327
+ {
328
+ "schedule": MonitorConfigSchedule,
329
+ "timezone": str,
330
+ "checkin_margin": int,
331
+ "max_runtime": int,
332
+ "failure_issue_threshold": int,
333
+ "recovery_threshold": int,
334
+ },
335
+ total=False,
336
+ )
337
+
338
+ HttpStatusCodeRange = Union[int, Container[int]]
@@ -0,0 +1,98 @@
1
+ """
2
+ Copyright (c) 2007 by the Pallets team.
3
+
4
+ Some rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are
8
+ met:
9
+
10
+ * Redistributions of source code must retain the above copyright notice,
11
+ this list of conditions and the following disclaimer.
12
+
13
+ * Redistributions in binary form must reproduce the above copyright
14
+ notice, this list of conditions and the following disclaimer in the
15
+ documentation and/or other materials provided with the distribution.
16
+
17
+ * Neither the name of the copyright holder nor the names of its
18
+ contributors may be used to endorse or promote products derived from
19
+ this software without specific prior written permission.
20
+
21
+ THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND
22
+ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
23
+ BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
24
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25
+ COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28
+ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
29
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31
+ THIS SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF
32
+ SUCH DAMAGE.
33
+ """
34
+
35
+ from typing import TYPE_CHECKING
36
+
37
+ if TYPE_CHECKING:
38
+ from typing import Dict
39
+ from typing import Iterator
40
+ from typing import Tuple
41
+
42
+
43
+ #
44
+ # `get_headers` comes from `werkzeug.datastructures.EnvironHeaders`
45
+ # https://github.com/pallets/werkzeug/blob/0.14.1/werkzeug/datastructures.py#L1361
46
+ #
47
+ # We need this function because Django does not give us a "pure" http header
48
+ # dict. So we might as well use it for all WSGI integrations.
49
+ #
50
+ def _get_headers(environ):
51
+ # type: (Dict[str, str]) -> Iterator[Tuple[str, str]]
52
+ """
53
+ Returns only proper HTTP headers.
54
+ """
55
+ for key, value in environ.items():
56
+ key = str(key)
57
+ if key.startswith("HTTP_") and key not in (
58
+ "HTTP_CONTENT_TYPE",
59
+ "HTTP_CONTENT_LENGTH",
60
+ ):
61
+ yield key[5:].replace("_", "-").title(), value
62
+ elif key in ("CONTENT_TYPE", "CONTENT_LENGTH"):
63
+ yield key.replace("_", "-").title(), value
64
+
65
+
66
+ #
67
+ # `get_host` comes from `werkzeug.wsgi.get_host`
68
+ # https://github.com/pallets/werkzeug/blob/1.0.1/src/werkzeug/wsgi.py#L145
69
+ #
70
+ def get_host(environ, use_x_forwarded_for=False):
71
+ # type: (Dict[str, str], bool) -> str
72
+ """
73
+ Return the host for the given WSGI environment.
74
+ """
75
+ if use_x_forwarded_for and "HTTP_X_FORWARDED_HOST" in environ:
76
+ rv = environ["HTTP_X_FORWARDED_HOST"]
77
+ if environ["wsgi.url_scheme"] == "http" and rv.endswith(":80"):
78
+ rv = rv[:-3]
79
+ elif environ["wsgi.url_scheme"] == "https" and rv.endswith(":443"):
80
+ rv = rv[:-4]
81
+ elif environ.get("HTTP_HOST"):
82
+ rv = environ["HTTP_HOST"]
83
+ if environ["wsgi.url_scheme"] == "http" and rv.endswith(":80"):
84
+ rv = rv[:-3]
85
+ elif environ["wsgi.url_scheme"] == "https" and rv.endswith(":443"):
86
+ rv = rv[:-4]
87
+ elif environ.get("SERVER_NAME"):
88
+ rv = environ["SERVER_NAME"]
89
+ if (environ["wsgi.url_scheme"], environ["SERVER_PORT"]) not in (
90
+ ("https", "443"),
91
+ ("http", "80"),
92
+ ):
93
+ rv += ":" + environ["SERVER_PORT"]
94
+ else:
95
+ # In spite of the WSGI spec, SERVER_NAME might not be present.
96
+ rv = "unknown"
97
+
98
+ return rv
@@ -0,0 +1,7 @@
1
+ from .utils import (
2
+ set_data_normalized,
3
+ GEN_AI_MESSAGE_ROLE_MAPPING,
4
+ GEN_AI_MESSAGE_ROLE_REVERSE_MAPPING,
5
+ normalize_message_role,
6
+ normalize_message_roles,
7
+ ) # noqa: F401