sentry-sdk 2.26.1__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 (114) 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 +8 -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 +5 -1
  14. sentry_sdk/integrations/__init__.py +5 -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 +103 -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/launchdarkly.py +3 -3
  51. sentry_sdk/integrations/litestar.py +4 -2
  52. sentry_sdk/integrations/logging.py +12 -3
  53. sentry_sdk/integrations/openai.py +2 -0
  54. sentry_sdk/integrations/openfeature.py +3 -5
  55. sentry_sdk/integrations/pymongo.py +18 -25
  56. sentry_sdk/integrations/pyramid.py +1 -1
  57. sentry_sdk/integrations/quart.py +3 -3
  58. sentry_sdk/integrations/ray.py +23 -17
  59. sentry_sdk/integrations/redis/_async_common.py +30 -18
  60. sentry_sdk/integrations/redis/_sync_common.py +28 -18
  61. sentry_sdk/integrations/redis/modules/caches.py +13 -10
  62. sentry_sdk/integrations/redis/modules/queries.py +14 -11
  63. sentry_sdk/integrations/redis/rb.py +4 -4
  64. sentry_sdk/integrations/redis/redis.py +6 -6
  65. sentry_sdk/integrations/redis/redis_cluster.py +18 -16
  66. sentry_sdk/integrations/redis/redis_py_cluster_legacy.py +4 -4
  67. sentry_sdk/integrations/redis/utils.py +63 -19
  68. sentry_sdk/integrations/rq.py +68 -23
  69. sentry_sdk/integrations/rust_tracing.py +28 -43
  70. sentry_sdk/integrations/sanic.py +23 -13
  71. sentry_sdk/integrations/socket.py +9 -5
  72. sentry_sdk/integrations/sqlalchemy.py +8 -8
  73. sentry_sdk/integrations/starlette.py +11 -31
  74. sentry_sdk/integrations/starlite.py +4 -2
  75. sentry_sdk/integrations/stdlib.py +56 -9
  76. sentry_sdk/integrations/strawberry.py +40 -59
  77. sentry_sdk/integrations/threading.py +10 -26
  78. sentry_sdk/integrations/tornado.py +57 -18
  79. sentry_sdk/integrations/trytond.py +4 -1
  80. sentry_sdk/integrations/unleash.py +2 -3
  81. sentry_sdk/integrations/wsgi.py +84 -38
  82. sentry_sdk/opentelemetry/__init__.py +9 -0
  83. sentry_sdk/opentelemetry/consts.py +33 -0
  84. sentry_sdk/opentelemetry/contextvars_context.py +73 -0
  85. sentry_sdk/{integrations/opentelemetry → opentelemetry}/propagator.py +19 -28
  86. sentry_sdk/opentelemetry/sampler.py +326 -0
  87. sentry_sdk/opentelemetry/scope.py +218 -0
  88. sentry_sdk/opentelemetry/span_processor.py +329 -0
  89. sentry_sdk/opentelemetry/tracing.py +35 -0
  90. sentry_sdk/opentelemetry/utils.py +476 -0
  91. sentry_sdk/profiler/__init__.py +0 -40
  92. sentry_sdk/profiler/continuous_profiler.py +1 -30
  93. sentry_sdk/profiler/transaction_profiler.py +5 -56
  94. sentry_sdk/scope.py +107 -351
  95. sentry_sdk/sessions.py +0 -87
  96. sentry_sdk/tracing.py +418 -1134
  97. sentry_sdk/tracing_utils.py +134 -169
  98. sentry_sdk/transport.py +4 -104
  99. sentry_sdk/types.py +26 -2
  100. sentry_sdk/utils.py +169 -152
  101. {sentry_sdk-2.26.1.dist-info → sentry_sdk-3.0.0a1.dist-info}/METADATA +3 -5
  102. sentry_sdk-3.0.0a1.dist-info/RECORD +154 -0
  103. {sentry_sdk-2.26.1.dist-info → sentry_sdk-3.0.0a1.dist-info}/WHEEL +1 -1
  104. sentry_sdk-3.0.0a1.dist-info/entry_points.txt +2 -0
  105. sentry_sdk/hub.py +0 -739
  106. sentry_sdk/integrations/opentelemetry/__init__.py +0 -7
  107. sentry_sdk/integrations/opentelemetry/consts.py +0 -5
  108. sentry_sdk/integrations/opentelemetry/integration.py +0 -58
  109. sentry_sdk/integrations/opentelemetry/span_processor.py +0 -391
  110. sentry_sdk/metrics.py +0 -965
  111. sentry_sdk-2.26.1.dist-info/RECORD +0 -152
  112. sentry_sdk-2.26.1.dist-info/entry_points.txt +0 -2
  113. {sentry_sdk-2.26.1.dist-info → sentry_sdk-3.0.0a1.dist-info}/licenses/LICENSE +0 -0
  114. {sentry_sdk-2.26.1.dist-info → sentry_sdk-3.0.0a1.dist-info}/top_level.txt +0 -0
@@ -1,18 +1,25 @@
1
1
  import contextlib
2
+ import decimal
2
3
  import inspect
3
4
  import os
4
5
  import re
5
6
  import sys
7
+ import uuid
6
8
  from collections.abc import Mapping
7
- from datetime import timedelta
8
- from decimal import ROUND_DOWN, Context, Decimal
9
+ from datetime import datetime, timedelta, timezone
10
+ from decimal import ROUND_DOWN, Decimal, DefaultContext, localcontext
9
11
  from functools import wraps
10
12
  from random import Random
11
13
  from urllib.parse import quote, unquote
12
- import uuid
13
14
 
14
15
  import sentry_sdk
15
- from sentry_sdk.consts import OP, SPANDATA
16
+ from sentry_sdk.consts import (
17
+ OP,
18
+ SPANDATA,
19
+ SPANSTATUS,
20
+ BAGGAGE_HEADER_NAME,
21
+ SENTRY_TRACE_HEADER_NAME,
22
+ )
16
23
  from sentry_sdk.utils import (
17
24
  capture_internal_exceptions,
18
25
  filename_for_module,
@@ -21,7 +28,6 @@ from sentry_sdk.utils import (
21
28
  match_regex_list,
22
29
  qualname_from_function,
23
30
  to_string,
24
- try_convert,
25
31
  is_sentry_url,
26
32
  _is_external_source,
27
33
  _is_in_project_root,
@@ -36,7 +42,6 @@ if TYPE_CHECKING:
36
42
  from typing import Generator
37
43
  from typing import Optional
38
44
  from typing import Union
39
-
40
45
  from types import FrameType
41
46
 
42
47
 
@@ -96,17 +101,14 @@ def has_tracing_enabled(options):
96
101
  # type: (Optional[Dict[str, Any]]) -> bool
97
102
  """
98
103
  Returns True if either traces_sample_rate or traces_sampler is
99
- defined and enable_tracing is set and not false.
104
+ defined.
100
105
  """
101
106
  if options is None:
102
107
  return False
103
108
 
104
109
  return bool(
105
- options.get("enable_tracing") is not False
106
- and (
107
- options.get("traces_sample_rate") is not None
108
- or options.get("traces_sampler") is not None
109
- )
110
+ options.get("traces_sample_rate") is not None
111
+ or options.get("traces_sampler") is not None
110
112
  )
111
113
 
112
114
 
@@ -118,7 +120,7 @@ def record_sql_queries(
118
120
  paramstyle, # type: Optional[str]
119
121
  executemany, # type: bool
120
122
  record_cursor_repr=False, # type: bool
121
- span_origin="manual", # type: str
123
+ span_origin=None, # type: Optional[str]
122
124
  ):
123
125
  # type: (...) -> Generator[sentry_sdk.tracing.Span, None, None]
124
126
 
@@ -152,44 +154,13 @@ def record_sql_queries(
152
154
  op=OP.DB,
153
155
  name=query,
154
156
  origin=span_origin,
157
+ only_if_parent=True,
155
158
  ) as span:
156
159
  for k, v in data.items():
157
- span.set_data(k, v)
160
+ span.set_attribute(k, v)
158
161
  yield span
159
162
 
160
163
 
161
- def maybe_create_breadcrumbs_from_span(scope, span):
162
- # type: (sentry_sdk.Scope, sentry_sdk.tracing.Span) -> None
163
- if span.op == OP.DB_REDIS:
164
- scope.add_breadcrumb(
165
- message=span.description, type="redis", category="redis", data=span._tags
166
- )
167
-
168
- elif span.op == OP.HTTP_CLIENT:
169
- level = None
170
- status_code = span._data.get(SPANDATA.HTTP_STATUS_CODE)
171
- if status_code:
172
- if 500 <= status_code <= 599:
173
- level = "error"
174
- elif 400 <= status_code <= 499:
175
- level = "warning"
176
-
177
- if level:
178
- scope.add_breadcrumb(
179
- type="http", category="httplib", data=span._data, level=level
180
- )
181
- else:
182
- scope.add_breadcrumb(type="http", category="httplib", data=span._data)
183
-
184
- elif span.op == "subprocess":
185
- scope.add_breadcrumb(
186
- type="subprocess",
187
- category="subprocess",
188
- message=span.description,
189
- data=span._data,
190
- )
191
-
192
-
193
164
  def _get_frame_module_abs_path(frame):
194
165
  # type: (FrameType) -> Optional[str]
195
166
  try:
@@ -227,14 +198,17 @@ def add_query_source(span):
227
198
  if not client.is_active():
228
199
  return
229
200
 
230
- if span.timestamp is None or span.start_timestamp is None:
201
+ if span.start_timestamp is None:
231
202
  return
232
203
 
233
204
  should_add_query_source = client.options.get("enable_db_query_source", True)
234
205
  if not should_add_query_source:
235
206
  return
236
207
 
237
- duration = span.timestamp - span.start_timestamp
208
+ # We assume here that the query is just ending now. We can't use
209
+ # the actual end timestamp of the span because in OTel the span
210
+ # can't be finished in order to set any attributes on it.
211
+ duration = datetime.now(tz=timezone.utc) - span.start_timestamp
238
212
  threshold = client.options.get("db_query_source_threshold_ms", 0)
239
213
  slow_query = duration / timedelta(milliseconds=1) > threshold
240
214
 
@@ -281,14 +255,14 @@ def add_query_source(span):
281
255
  except Exception:
282
256
  lineno = None
283
257
  if lineno is not None:
284
- span.set_data(SPANDATA.CODE_LINENO, frame.f_lineno)
258
+ span.set_attribute(SPANDATA.CODE_LINENO, frame.f_lineno)
285
259
 
286
260
  try:
287
261
  namespace = frame.f_globals.get("__name__")
288
262
  except Exception:
289
263
  namespace = None
290
264
  if namespace is not None:
291
- span.set_data(SPANDATA.CODE_NAMESPACE, namespace)
265
+ span.set_attribute(SPANDATA.CODE_NAMESPACE, namespace)
292
266
 
293
267
  filepath = _get_frame_module_abs_path(frame)
294
268
  if filepath is not None:
@@ -298,7 +272,7 @@ def add_query_source(span):
298
272
  in_app_path = filepath.replace(project_root, "").lstrip(os.sep)
299
273
  else:
300
274
  in_app_path = filepath
301
- span.set_data(SPANDATA.CODE_FILEPATH, in_app_path)
275
+ span.set_attribute(SPANDATA.CODE_FILEPATH, in_app_path)
302
276
 
303
277
  try:
304
278
  code_function = frame.f_code.co_name
@@ -306,7 +280,7 @@ def add_query_source(span):
306
280
  code_function = None
307
281
 
308
282
  if code_function is not None:
309
- span.set_data(SPANDATA.CODE_FUNCTION, frame.f_code.co_name)
283
+ span.set_attribute(SPANDATA.CODE_FUNCTION, frame.f_code.co_name)
310
284
 
311
285
 
312
286
  def extract_sentrytrace_data(header):
@@ -371,7 +345,7 @@ class PropagationContext:
371
345
  "_span_id",
372
346
  "parent_span_id",
373
347
  "parent_sampled",
374
- "dynamic_sampling_context",
348
+ "baggage",
375
349
  )
376
350
 
377
351
  def __init__(
@@ -380,7 +354,7 @@ class PropagationContext:
380
354
  span_id=None, # type: Optional[str]
381
355
  parent_span_id=None, # type: Optional[str]
382
356
  parent_sampled=None, # type: Optional[bool]
383
- dynamic_sampling_context=None, # type: Optional[Dict[str, str]]
357
+ baggage=None, # type: Optional[Baggage]
384
358
  ):
385
359
  # type: (...) -> None
386
360
  self._trace_id = trace_id
@@ -398,8 +372,13 @@ class PropagationContext:
398
372
  Important when the parent span originated in an upstream service,
399
373
  because we want to sample the whole trace, or nothing from the trace."""
400
374
 
401
- self.dynamic_sampling_context = dynamic_sampling_context
402
- """Data that is used for dynamic sampling decisions."""
375
+ self.baggage = baggage
376
+ """Baggage object used for dynamic sampling decisions."""
377
+
378
+ @property
379
+ def dynamic_sampling_context(self):
380
+ # type: () -> Optional[Dict[str, str]]
381
+ return self.baggage.dynamic_sampling_context() if self.baggage else None
403
382
 
404
383
  @classmethod
405
384
  def from_incoming_data(cls, incoming_data):
@@ -410,9 +389,7 @@ class PropagationContext:
410
389
  baggage_header = normalized_data.get(BAGGAGE_HEADER_NAME)
411
390
  if baggage_header:
412
391
  propagation_context = PropagationContext()
413
- propagation_context.dynamic_sampling_context = Baggage.from_incoming_header(
414
- baggage_header
415
- ).dynamic_sampling_context()
392
+ propagation_context.baggage = Baggage.from_incoming_header(baggage_header)
416
393
 
417
394
  sentry_trace_header = normalized_data.get(SENTRY_TRACE_HEADER_NAME)
418
395
  if sentry_trace_header:
@@ -432,7 +409,6 @@ class PropagationContext:
432
409
  # type: () -> str
433
410
  """The trace id of the Sentry trace."""
434
411
  if not self._trace_id:
435
- # New trace, don't fill in sample_rand
436
412
  self._trace_id = uuid.uuid4().hex
437
413
 
438
414
  return self._trace_id
@@ -456,6 +432,21 @@ class PropagationContext:
456
432
  # type: (str) -> None
457
433
  self._span_id = value
458
434
 
435
+ def to_traceparent(self):
436
+ # type: () -> str
437
+ if self.parent_sampled is True:
438
+ sampled = "1"
439
+ elif self.parent_sampled is False:
440
+ sampled = "0"
441
+ else:
442
+ sampled = None
443
+
444
+ traceparent = "%s-%s" % (self.trace_id, self.span_id)
445
+ if sampled is not None:
446
+ traceparent += "-%s" % (sampled,)
447
+
448
+ return traceparent
449
+
459
450
  def update(self, other_dict):
460
451
  # type: (Dict[str, Any]) -> None
461
452
  """
@@ -467,22 +458,12 @@ class PropagationContext:
467
458
  except AttributeError:
468
459
  pass
469
460
 
470
- def __repr__(self):
471
- # type: (...) -> str
472
- return "<PropagationContext _trace_id={} _span_id={} parent_span_id={} parent_sampled={} dynamic_sampling_context={}>".format(
473
- self._trace_id,
474
- self._span_id,
475
- self.parent_span_id,
476
- self.parent_sampled,
477
- self.dynamic_sampling_context,
478
- )
479
-
480
461
  def _fill_sample_rand(self):
481
462
  # type: () -> None
482
463
  """
483
- Ensure that there is a valid sample_rand value in the dynamic_sampling_context.
464
+ Ensure that there is a valid sample_rand value in the baggage.
484
465
 
485
- If there is a valid sample_rand value in the dynamic_sampling_context, we keep it.
466
+ If there is a valid sample_rand value in the baggage, we keep it.
486
467
  Otherwise, we generate a sample_rand value according to the following:
487
468
 
488
469
  - If we have a parent_sampled value and a sample_rate in the DSC, we compute
@@ -497,21 +478,33 @@ class PropagationContext:
497
478
 
498
479
  This function does nothing if there is no dynamic_sampling_context.
499
480
  """
500
- if self.dynamic_sampling_context is None:
481
+ if self.dynamic_sampling_context is None or self.baggage is None:
501
482
  return
502
483
 
503
- sample_rand = try_convert(
504
- Decimal, self.dynamic_sampling_context.get("sample_rand")
505
- )
484
+ sentry_baggage = self.baggage.sentry_items
485
+
486
+ sample_rand = None
487
+ if sentry_baggage.get("sample_rand"):
488
+ try:
489
+ sample_rand = Decimal(sentry_baggage["sample_rand"])
490
+ except Exception:
491
+ logger.debug(
492
+ f"Failed to convert incoming sample_rand to Decimal: {sample_rand}"
493
+ )
494
+
506
495
  if sample_rand is not None and 0 <= sample_rand < 1:
507
496
  # sample_rand is present and valid, so don't overwrite it
508
497
  return
509
498
 
510
- # Get the sample rate and compute the transformation that will map the random value
511
- # to the desired range: [0, 1), [0, sample_rate), or [sample_rate, 1).
512
- sample_rate = try_convert(
513
- float, self.dynamic_sampling_context.get("sample_rate")
514
- )
499
+ sample_rate = None
500
+ if sentry_baggage.get("sample_rate"):
501
+ try:
502
+ sample_rate = float(sentry_baggage["sample_rate"])
503
+ except Exception:
504
+ logger.debug(
505
+ f"Failed to convert incoming sample_rate to float: {sample_rate}"
506
+ )
507
+
515
508
  lower, upper = _sample_rand_range(self.parent_sampled, sample_rate)
516
509
 
517
510
  try:
@@ -527,17 +520,26 @@ class PropagationContext:
527
520
  )
528
521
  return
529
522
 
530
- self.dynamic_sampling_context["sample_rand"] = (
531
- f"{sample_rand:.6f}" # noqa: E231
532
- )
523
+ self.baggage.sentry_items["sample_rand"] = f"{sample_rand:.6f}" # noqa: E231
533
524
 
534
525
  def _sample_rand(self):
535
526
  # type: () -> Optional[str]
536
- """Convenience method to get the sample_rand value from the dynamic_sampling_context."""
537
- if self.dynamic_sampling_context is None:
527
+ """Convenience method to get the sample_rand value from the baggage."""
528
+ if self.baggage is None:
538
529
  return None
539
530
 
540
- return self.dynamic_sampling_context.get("sample_rand")
531
+ return self.baggage.sentry_items.get("sample_rand")
532
+
533
+ def __repr__(self):
534
+ # type: (...) -> str
535
+ return "<PropagationContext _trace_id={} _span_id={} parent_span_id={} parent_sampled={} baggage={} dynamic_sampling_context={}>".format(
536
+ self._trace_id,
537
+ self._span_id,
538
+ self.parent_span_id,
539
+ self.parent_sampled,
540
+ self.baggage,
541
+ self.dynamic_sampling_context,
542
+ )
541
543
 
542
544
 
543
545
  class Baggage:
@@ -568,8 +570,6 @@ class Baggage:
568
570
  def from_incoming_header(
569
571
  cls,
570
572
  header, # type: Optional[str]
571
- *,
572
- _sample_rand=None, # type: Optional[str]
573
573
  ):
574
574
  # type: (...) -> Baggage
575
575
  """
@@ -594,10 +594,6 @@ class Baggage:
594
594
  else:
595
595
  third_party_items += ("," if third_party_items else "") + item
596
596
 
597
- if _sample_rand is not None:
598
- sentry_items["sample_rand"] = str(_sample_rand)
599
- mutable = False
600
-
601
597
  return Baggage(sentry_items, third_party_items, mutable)
602
598
 
603
599
  @classmethod
@@ -633,53 +629,6 @@ class Baggage:
633
629
 
634
630
  return Baggage(sentry_items, third_party_items, mutable)
635
631
 
636
- @classmethod
637
- def populate_from_transaction(cls, transaction):
638
- # type: (sentry_sdk.tracing.Transaction) -> Baggage
639
- """
640
- Populate fresh baggage entry with sentry_items and make it immutable
641
- if this is the head SDK which originates traces.
642
- """
643
- client = sentry_sdk.get_client()
644
- sentry_items = {} # type: Dict[str, str]
645
-
646
- if not client.is_active():
647
- return Baggage(sentry_items)
648
-
649
- options = client.options or {}
650
-
651
- sentry_items["trace_id"] = transaction.trace_id
652
- sentry_items["sample_rand"] = str(transaction._sample_rand)
653
-
654
- if options.get("environment"):
655
- sentry_items["environment"] = options["environment"]
656
-
657
- if options.get("release"):
658
- sentry_items["release"] = options["release"]
659
-
660
- if options.get("dsn"):
661
- sentry_items["public_key"] = Dsn(options["dsn"]).public_key
662
-
663
- if (
664
- transaction.name
665
- and transaction.source not in LOW_QUALITY_TRANSACTION_SOURCES
666
- ):
667
- sentry_items["transaction"] = transaction.name
668
-
669
- if transaction.sample_rate is not None:
670
- sentry_items["sample_rate"] = str(transaction.sample_rate)
671
-
672
- if transaction.sampled is not None:
673
- sentry_items["sampled"] = "true" if transaction.sampled else "false"
674
-
675
- # there's an existing baggage but it was mutable,
676
- # which is why we are creating this new baggage.
677
- # However, if by chance the user put some sentry items in there, give them precedence.
678
- if transaction._baggage and transaction._baggage.sentry_items:
679
- sentry_items.update(transaction._baggage.sentry_items)
680
-
681
- return Baggage(sentry_items, mutable=False)
682
-
683
632
  def freeze(self):
684
633
  # type: () -> None
685
634
  self.mutable = False
@@ -722,20 +671,6 @@ class Baggage:
722
671
  )
723
672
  )
724
673
 
725
- def _sample_rand(self):
726
- # type: () -> Optional[Decimal]
727
- """Convenience method to get the sample_rand value from the sentry_items.
728
-
729
- We validate the value and parse it as a Decimal before returning it. The value is considered
730
- valid if it is a Decimal in the range [0, 1).
731
- """
732
- sample_rand = try_convert(Decimal, self.sentry_items.get("sample_rand"))
733
-
734
- if sample_rand is not None and Decimal(0) <= sample_rand < Decimal(1):
735
- return sample_rand
736
-
737
- return None
738
-
739
674
  def __repr__(self):
740
675
  # type: () -> str
741
676
  return f'<Baggage "{self.serialize(include_third_party=True)}", mutable={self.mutable}>'
@@ -837,7 +772,7 @@ def start_child_span_decorator(func):
837
772
 
838
773
 
839
774
  def get_current_span(scope=None):
840
- # type: (Optional[sentry_sdk.Scope]) -> Optional[Span]
775
+ # type: (Optional[sentry_sdk.Scope]) -> Optional[sentry_sdk.tracing.Span]
841
776
  """
842
777
  Returns the currently active span if there is one running, otherwise `None`
843
778
  """
@@ -848,10 +783,9 @@ def get_current_span(scope=None):
848
783
 
849
784
  def _generate_sample_rand(
850
785
  trace_id, # type: Optional[str]
851
- *,
852
786
  interval=(0.0, 1.0), # type: tuple[float, float]
853
787
  ):
854
- # type: (...) -> Decimal
788
+ # type: (...) -> Optional[decimal.Decimal]
855
789
  """Generate a sample_rand value from a trace ID.
856
790
 
857
791
  The generated value will be pseudorandomly chosen from the provided
@@ -872,10 +806,13 @@ def _generate_sample_rand(
872
806
 
873
807
  # Round down to exactly six decimal-digit precision.
874
808
  # Setting the context is needed to avoid an InvalidOperation exception
875
- # in case the user has changed the default precision.
876
- return Decimal(sample_rand).quantize(
877
- Decimal("0.000001"), rounding=ROUND_DOWN, context=Context(prec=6)
878
- )
809
+ # in case the user has changed the default precision or set traps.
810
+ with localcontext(DefaultContext) as ctx:
811
+ ctx.prec = 6
812
+ return Decimal(sample_rand).quantize(
813
+ Decimal("0.000001"),
814
+ rounding=ROUND_DOWN,
815
+ )
879
816
 
880
817
 
881
818
  def _sample_rand_range(parent_sampled, sample_rate):
@@ -893,12 +830,40 @@ def _sample_rand_range(parent_sampled, sample_rate):
893
830
  return sample_rate, 1.0
894
831
 
895
832
 
896
- # Circular imports
897
- from sentry_sdk.tracing import (
898
- BAGGAGE_HEADER_NAME,
899
- LOW_QUALITY_TRANSACTION_SOURCES,
900
- SENTRY_TRACE_HEADER_NAME,
901
- )
833
+ def get_span_status_from_http_code(http_status_code):
834
+ # type: (int) -> str
835
+ """
836
+ Returns the Sentry status corresponding to the given HTTP status code.
902
837
 
903
- if TYPE_CHECKING:
904
- from sentry_sdk.tracing import Span
838
+ See: https://develop.sentry.dev/sdk/event-payloads/contexts/#trace-context
839
+ """
840
+ if http_status_code < 400:
841
+ return SPANSTATUS.OK
842
+
843
+ elif 400 <= http_status_code < 500:
844
+ if http_status_code == 403:
845
+ return SPANSTATUS.PERMISSION_DENIED
846
+ elif http_status_code == 404:
847
+ return SPANSTATUS.NOT_FOUND
848
+ elif http_status_code == 429:
849
+ return SPANSTATUS.RESOURCE_EXHAUSTED
850
+ elif http_status_code == 413:
851
+ return SPANSTATUS.FAILED_PRECONDITION
852
+ elif http_status_code == 401:
853
+ return SPANSTATUS.UNAUTHENTICATED
854
+ elif http_status_code == 409:
855
+ return SPANSTATUS.ALREADY_EXISTS
856
+ else:
857
+ return SPANSTATUS.INVALID_ARGUMENT
858
+
859
+ elif 500 <= http_status_code < 600:
860
+ if http_status_code == 504:
861
+ return SPANSTATUS.DEADLINE_EXCEEDED
862
+ elif http_status_code == 501:
863
+ return SPANSTATUS.UNIMPLEMENTED
864
+ elif http_status_code == 503:
865
+ return SPANSTATUS.UNAVAILABLE
866
+ else:
867
+ return SPANSTATUS.INTERNAL_ERROR
868
+
869
+ return SPANSTATUS.UNKNOWN_ERROR