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
sentry_sdk/scope.py CHANGED
@@ -11,27 +11,23 @@ from itertools import chain
11
11
 
12
12
  from sentry_sdk._types import AnnotatedValue
13
13
  from sentry_sdk.attachments import Attachment
14
- from sentry_sdk.consts import DEFAULT_MAX_BREADCRUMBS, FALSE_VALUES, INSTRUMENTER
15
- from sentry_sdk.feature_flags import FlagBuffer, DEFAULT_FLAG_CAPACITY
16
- from sentry_sdk.profiler.continuous_profiler import (
17
- get_profiler_id,
18
- try_autostart_continuous_profiler,
19
- try_profile_lifecycle_trace_start,
14
+ from sentry_sdk.consts import (
15
+ DEFAULT_MAX_BREADCRUMBS,
16
+ FALSE_VALUES,
17
+ BAGGAGE_HEADER_NAME,
18
+ SENTRY_TRACE_HEADER_NAME,
20
19
  )
20
+ from sentry_sdk.feature_flags import FlagBuffer, DEFAULT_FLAG_CAPACITY
21
21
  from sentry_sdk.profiler.transaction_profiler import Profile
22
22
  from sentry_sdk.session import Session
23
23
  from sentry_sdk.tracing_utils import (
24
24
  Baggage,
25
25
  has_tracing_enabled,
26
- normalize_incoming_data,
27
26
  PropagationContext,
28
27
  )
29
28
  from sentry_sdk.tracing import (
30
- BAGGAGE_HEADER_NAME,
31
- SENTRY_TRACE_HEADER_NAME,
32
29
  NoOpSpan,
33
30
  Span,
34
- Transaction,
35
31
  )
36
32
  from sentry_sdk.utils import (
37
33
  capture_internal_exception,
@@ -44,7 +40,6 @@ from sentry_sdk.utils import (
44
40
  logger,
45
41
  )
46
42
 
47
- import typing
48
43
  from typing import TYPE_CHECKING
49
44
 
50
45
  if TYPE_CHECKING:
@@ -62,8 +57,7 @@ if TYPE_CHECKING:
62
57
  from typing import Tuple
63
58
  from typing import TypeVar
64
59
  from typing import Union
65
-
66
- from typing_extensions import Unpack
60
+ from typing import Self
67
61
 
68
62
  from sentry_sdk._types import (
69
63
  Breadcrumb,
@@ -74,12 +68,9 @@ if TYPE_CHECKING:
74
68
  ExcInfo,
75
69
  Hint,
76
70
  LogLevelStr,
77
- SamplingContext,
78
71
  Type,
79
72
  )
80
73
 
81
- from sentry_sdk.tracing import TransactionKwargs
82
-
83
74
  import sentry_sdk
84
75
 
85
76
  P = ParamSpec("P")
@@ -115,28 +106,6 @@ class ScopeType(Enum):
115
106
  MERGED = "merged"
116
107
 
117
108
 
118
- class _ScopeManager:
119
- def __init__(self, hub=None):
120
- # type: (Optional[Any]) -> None
121
- self._old_scopes = [] # type: List[Scope]
122
-
123
- def __enter__(self):
124
- # type: () -> Scope
125
- isolation_scope = Scope.get_isolation_scope()
126
-
127
- self._old_scopes.append(isolation_scope)
128
-
129
- forked_scope = isolation_scope.fork()
130
- _isolation_scope.set(forked_scope)
131
-
132
- return forked_scope
133
-
134
- def __exit__(self, exc_type, exc_value, tb):
135
- # type: (Any, Any, Any) -> None
136
- old_scope = self._old_scopes.pop()
137
- _isolation_scope.set(old_scope)
138
-
139
-
140
109
  def add_global_event_processor(processor):
141
110
  # type: (EventProcessor) -> None
142
111
  global_event_processors.append(processor)
@@ -225,12 +194,12 @@ class Scope:
225
194
  self.generate_propagation_context(incoming_data=incoming_trace_information)
226
195
 
227
196
  def __copy__(self):
228
- # type: () -> Scope
197
+ # type: () -> Self
229
198
  """
230
199
  Returns a copy of this scope.
231
200
  This also creates a copy of all referenced data structures.
232
201
  """
233
- rv = object.__new__(self.__class__) # type: Scope
202
+ rv = object.__new__(self.__class__) # type: Self
234
203
 
235
204
  rv._type = self._type
236
205
  rv.client = self.client
@@ -273,13 +242,21 @@ class Scope:
273
242
 
274
243
  Returns the current scope.
275
244
  """
276
- current_scope = _current_scope.get()
245
+ current_scope = cls._get_current_scope()
277
246
  if current_scope is None:
278
247
  current_scope = Scope(ty=ScopeType.CURRENT)
279
248
  _current_scope.set(current_scope)
280
249
 
281
250
  return current_scope
282
251
 
252
+ @classmethod
253
+ def _get_current_scope(cls):
254
+ # type: () -> Optional[Scope]
255
+ """
256
+ Returns the current scope without creating a new one. Internal use only.
257
+ """
258
+ return _current_scope.get()
259
+
283
260
  @classmethod
284
261
  def set_current_scope(cls, new_current_scope):
285
262
  # type: (Scope) -> None
@@ -299,13 +276,21 @@ class Scope:
299
276
 
300
277
  Returns the isolation scope.
301
278
  """
302
- isolation_scope = _isolation_scope.get()
279
+ isolation_scope = cls._get_isolation_scope()
303
280
  if isolation_scope is None:
304
281
  isolation_scope = Scope(ty=ScopeType.ISOLATION)
305
282
  _isolation_scope.set(isolation_scope)
306
283
 
307
284
  return isolation_scope
308
285
 
286
+ @classmethod
287
+ def _get_isolation_scope(cls):
288
+ # type: () -> Optional[Scope]
289
+ """
290
+ Returns the isolation scope without creating a new one. Internal use only.
291
+ """
292
+ return _isolation_scope.get()
293
+
309
294
  @classmethod
310
295
  def set_isolation_scope(cls, new_isolation_scope):
311
296
  # type: (Scope) -> None
@@ -349,7 +334,7 @@ class Scope:
349
334
  return cls.get_isolation_scope()._last_event_id
350
335
 
351
336
  def _merge_scopes(self, additional_scope=None, additional_scope_kwargs=None):
352
- # type: (Optional[Scope], Optional[Dict[str, Any]]) -> Scope
337
+ # type: (Optional[Scope], Optional[Dict[str, Any]]) -> Self
353
338
  """
354
339
  Merges global, isolation and current scope into a new scope and
355
340
  adds the given additional scope or additional scope kwargs to it.
@@ -357,16 +342,17 @@ class Scope:
357
342
  if additional_scope and additional_scope_kwargs:
358
343
  raise TypeError("cannot provide scope and kwargs")
359
344
 
360
- final_scope = copy(_global_scope) if _global_scope is not None else Scope()
345
+ final_scope = self.__class__()
361
346
  final_scope._type = ScopeType.MERGED
362
347
 
363
- isolation_scope = _isolation_scope.get()
364
- if isolation_scope is not None:
365
- final_scope.update_from_scope(isolation_scope)
348
+ global_scope = self.get_global_scope()
349
+ final_scope.update_from_scope(global_scope)
366
350
 
367
- current_scope = _current_scope.get()
368
- if current_scope is not None:
369
- final_scope.update_from_scope(current_scope)
351
+ isolation_scope = self.get_isolation_scope()
352
+ final_scope.update_from_scope(self.get_isolation_scope())
353
+
354
+ current_scope = self.get_current_scope()
355
+ final_scope.update_from_scope(current_scope)
370
356
 
371
357
  if self != current_scope and self != isolation_scope:
372
358
  final_scope.update_from_scope(self)
@@ -392,7 +378,7 @@ class Scope:
392
378
  This checks the current scope, the isolation scope and the global scope for a client.
393
379
  If no client is available a :py:class:`sentry_sdk.client.NonRecordingClient` is returned.
394
380
  """
395
- current_scope = _current_scope.get()
381
+ current_scope = cls.get_current_scope()
396
382
  try:
397
383
  client = current_scope.client
398
384
  except AttributeError:
@@ -401,7 +387,7 @@ class Scope:
401
387
  if client is not None and client.is_active():
402
388
  return client
403
389
 
404
- isolation_scope = _isolation_scope.get()
390
+ isolation_scope = cls.get_isolation_scope()
405
391
  try:
406
392
  client = isolation_scope.client
407
393
  except AttributeError:
@@ -434,7 +420,7 @@ class Scope:
434
420
  self.client = client if client is not None else NonRecordingClient()
435
421
 
436
422
  def fork(self):
437
- # type: () -> Scope
423
+ # type: () -> Self
438
424
  """
439
425
  .. versionadded:: 2.0.0
440
426
 
@@ -496,19 +482,10 @@ class Scope:
496
482
  def get_dynamic_sampling_context(self):
497
483
  # type: () -> Optional[Dict[str, str]]
498
484
  """
499
- Returns the Dynamic Sampling Context from the Propagation Context.
500
- If not existing, creates a new one.
485
+ Returns the Dynamic Sampling Context from the baggage or populates one.
501
486
  """
502
- if self._propagation_context is None:
503
- return None
504
-
505
487
  baggage = self.get_baggage()
506
- if baggage is not None:
507
- self._propagation_context.dynamic_sampling_context = (
508
- baggage.dynamic_sampling_context()
509
- )
510
-
511
- return self._propagation_context.dynamic_sampling_context
488
+ return baggage.dynamic_sampling_context() if baggage else None
512
489
 
513
490
  def get_traceparent(self, *args, **kwargs):
514
491
  # type: (Any, Any) -> Optional[str]
@@ -519,16 +496,16 @@ class Scope:
519
496
  client = self.get_client()
520
497
 
521
498
  # If we have an active span, return traceparent from there
522
- if has_tracing_enabled(client.options) and self.span is not None:
499
+ if (
500
+ has_tracing_enabled(client.options)
501
+ and self.span is not None
502
+ and self.span.is_valid
503
+ ):
523
504
  return self.span.to_traceparent()
524
505
 
525
506
  # If this scope has a propagation context, return traceparent from there
526
507
  if self._propagation_context is not None:
527
- traceparent = "%s-%s" % (
528
- self._propagation_context.trace_id,
529
- self._propagation_context.span_id,
530
- )
531
- return traceparent
508
+ return self._propagation_context.to_traceparent()
532
509
 
533
510
  # Fall back to isolation scope's traceparent. It always has one
534
511
  return self.get_isolation_scope().get_traceparent()
@@ -538,22 +515,24 @@ class Scope:
538
515
  """
539
516
  Returns the Sentry "baggage" header containing trace information from the
540
517
  currently active span or the scopes Propagation Context.
518
+ If not existing, creates a new one.
541
519
  """
542
520
  client = self.get_client()
543
521
 
544
522
  # If we have an active span, return baggage from there
545
- if has_tracing_enabled(client.options) and self.span is not None:
523
+ if (
524
+ has_tracing_enabled(client.options)
525
+ and self.span is not None
526
+ and self.span.is_valid
527
+ ):
546
528
  return self.span.to_baggage()
547
529
 
548
530
  # If this scope has a propagation context, return baggage from there
531
+ # populate a fresh one if it doesn't exist
549
532
  if self._propagation_context is not None:
550
- dynamic_sampling_context = (
551
- self._propagation_context.dynamic_sampling_context
552
- )
553
- if dynamic_sampling_context is None:
554
- return Baggage.from_options(self)
555
- else:
556
- return Baggage(dynamic_sampling_context)
533
+ if self._propagation_context.baggage is None:
534
+ self._propagation_context.baggage = Baggage.from_options(self)
535
+ return self._propagation_context.baggage
557
536
 
558
537
  # Fall back to isolation scope's baggage. It always has one
559
538
  return self.get_isolation_scope().get_baggage()
@@ -581,12 +560,6 @@ class Scope:
581
560
  Return meta tags which should be injected into HTML templates
582
561
  to allow propagation of trace information.
583
562
  """
584
- span = kwargs.pop("span", None)
585
- if span is not None:
586
- logger.warning(
587
- "The parameter `span` in trace_propagation_meta() is deprecated and will be removed in the future."
588
- )
589
-
590
563
  meta = ""
591
564
 
592
565
  sentry_trace = self.get_traceparent()
@@ -615,10 +588,9 @@ class Scope:
615
588
  if traceparent is not None:
616
589
  yield SENTRY_TRACE_HEADER_NAME, traceparent
617
590
 
618
- dsc = self.get_dynamic_sampling_context()
619
- if dsc is not None:
620
- baggage = Baggage(dsc).serialize()
621
- yield BAGGAGE_HEADER_NAME, baggage
591
+ baggage = self.get_baggage()
592
+ if baggage is not None:
593
+ yield BAGGAGE_HEADER_NAME, baggage.serialize()
622
594
 
623
595
  def iter_trace_propagation_headers(self, *args, **kwargs):
624
596
  # type: (Any, Any) -> Generator[Tuple[str, str], None, None]
@@ -629,18 +601,11 @@ class Scope:
629
601
  If no span is given, the trace data is taken from the scope.
630
602
  """
631
603
  client = self.get_client()
632
- if not client.options.get("propagate_traces"):
633
- warnings.warn(
634
- "The `propagate_traces` parameter is deprecated. Please use `trace_propagation_targets` instead.",
635
- DeprecationWarning,
636
- stacklevel=2,
637
- )
638
- return
639
604
 
640
605
  span = kwargs.pop("span", None)
641
606
  span = span or self.span
642
607
 
643
- if has_tracing_enabled(client.options) and span is not None:
608
+ if has_tracing_enabled(client.options) and span is not None and span.is_valid:
644
609
  for header in span.iter_headers():
645
610
  yield header
646
611
  else:
@@ -706,23 +671,6 @@ class Scope:
706
671
  self._last_event_id = None # type: Optional[str]
707
672
  self._flags = None # type: Optional[FlagBuffer]
708
673
 
709
- @_attr_setter
710
- def level(self, value):
711
- # type: (LogLevelStr) -> None
712
- """
713
- When set this overrides the level.
714
-
715
- .. deprecated:: 1.0.0
716
- Use :func:`set_level` instead.
717
-
718
- :param value: The level to set.
719
- """
720
- logger.warning(
721
- "Deprecated: use .set_level() instead. This will be removed in the future."
722
- )
723
-
724
- self._level = value
725
-
726
674
  def set_level(self, value):
727
675
  # type: (LogLevelStr) -> None
728
676
  """
@@ -739,71 +687,36 @@ class Scope:
739
687
  self._fingerprint = value
740
688
 
741
689
  @property
742
- def transaction(self):
743
- # type: () -> Any
744
- # would be type: () -> Optional[Transaction], see https://github.com/python/mypy/issues/3004
745
- """Return the transaction (root span) in the scope, if any."""
746
-
747
- # there is no span/transaction on the scope
690
+ def root_span(self):
691
+ # type: () -> Optional[Span]
692
+ """Return the root span in the scope, if any."""
748
693
  if self._span is None:
749
694
  return None
750
695
 
751
- # there is an orphan span on the scope
752
- if self._span.containing_transaction is None:
753
- return None
754
-
755
- # there is either a transaction (which is its own containing
756
- # transaction) or a non-orphan span on the scope
757
- return self._span.containing_transaction
758
-
759
- @transaction.setter
760
- def transaction(self, value):
761
- # type: (Any) -> None
762
- # would be type: (Optional[str]) -> None, see https://github.com/python/mypy/issues/3004
763
- """When set this forces a specific transaction name to be set.
764
-
765
- Deprecated: use set_transaction_name instead."""
766
-
767
- # XXX: the docstring above is misleading. The implementation of
768
- # apply_to_event prefers an existing value of event.transaction over
769
- # anything set in the scope.
770
- # XXX: note that with the introduction of the Scope.transaction getter,
771
- # there is a semantic and type mismatch between getter and setter. The
772
- # getter returns a Transaction, the setter sets a transaction name.
773
- # Without breaking version compatibility, we could make the setter set a
774
- # transaction name or transaction (self._span) depending on the type of
775
- # the value argument.
776
-
777
- logger.warning(
778
- "Assigning to scope.transaction directly is deprecated: use scope.set_transaction_name() instead."
779
- )
780
- self._transaction = value
781
- if self._span and self._span.containing_transaction:
782
- self._span.containing_transaction.name = value
696
+ return self._span.root_span
783
697
 
784
698
  def set_transaction_name(self, name, source=None):
785
699
  # type: (str, Optional[str]) -> None
786
700
  """Set the transaction name and optionally the transaction source."""
787
701
  self._transaction = name
788
702
 
789
- if self._span and self._span.containing_transaction:
790
- self._span.containing_transaction.name = name
703
+ if self._span and self._span.root_span:
704
+ self._span.root_span.name = name
791
705
  if source:
792
- self._span.containing_transaction.source = source
706
+ self._span.root_span.source = source
793
707
 
794
708
  if source:
795
709
  self._transaction_info["source"] = source
796
710
 
797
- @_attr_setter
798
- def user(self, value):
799
- # type: (Optional[Dict[str, Any]]) -> None
800
- """When set a specific user is bound to the scope. Deprecated in favor of set_user."""
801
- warnings.warn(
802
- "The `Scope.user` setter is deprecated in favor of `Scope.set_user()`.",
803
- DeprecationWarning,
804
- stacklevel=2,
805
- )
806
- self.set_user(value)
711
+ @property
712
+ def transaction_name(self):
713
+ # type: () -> Optional[str]
714
+ return self._transaction
715
+
716
+ @property
717
+ def transaction_source(self):
718
+ # type: () -> Optional[str]
719
+ return self._transaction_info.get("source")
807
720
 
808
721
  def set_user(self, value):
809
722
  # type: (Optional[Dict[str, Any]]) -> None
@@ -816,21 +729,14 @@ class Scope:
816
729
  @property
817
730
  def span(self):
818
731
  # type: () -> Optional[Span]
819
- """Get/set current tracing span or transaction."""
732
+ """Get current tracing span."""
820
733
  return self._span
821
734
 
822
735
  @span.setter
823
736
  def span(self, span):
824
737
  # type: (Optional[Span]) -> None
738
+ """Set current tracing span."""
825
739
  self._span = span
826
- # XXX: this differs from the implementation in JS, there Scope.setSpan
827
- # does not set Scope._transactionName.
828
- if isinstance(span, Transaction):
829
- transaction = span
830
- if transaction.name:
831
- self._transaction = transaction.name
832
- if transaction.source:
833
- self._transaction_info["source"] = transaction.source
834
740
 
835
741
  @property
836
742
  def profile(self):
@@ -990,195 +896,41 @@ class Scope:
990
896
  self._breadcrumbs.popleft()
991
897
  self._n_breadcrumbs_truncated += 1
992
898
 
993
- def start_transaction(
994
- self,
995
- transaction=None,
996
- instrumenter=INSTRUMENTER.SENTRY,
997
- custom_sampling_context=None,
998
- **kwargs,
999
- ):
1000
- # type: (Optional[Transaction], str, Optional[SamplingContext], Unpack[TransactionKwargs]) -> Union[Transaction, NoOpSpan]
899
+ def start_transaction(self, **kwargs):
900
+ # type: (Any) -> Union[NoOpSpan, Span]
1001
901
  """
1002
- Start and return a transaction.
1003
-
1004
- Start an existing transaction if given, otherwise create and start a new
1005
- transaction with kwargs.
1006
-
1007
- This is the entry point to manual tracing instrumentation.
1008
-
1009
- A tree structure can be built by adding child spans to the transaction,
1010
- and child spans to other spans. To start a new child span within the
1011
- transaction or any span, call the respective `.start_child()` method.
1012
-
1013
- Every child span must be finished before the transaction is finished,
1014
- otherwise the unfinished spans are discarded.
1015
-
1016
- When used as context managers, spans and transactions are automatically
1017
- finished at the end of the `with` block. If not using context managers,
1018
- call the `.finish()` method.
1019
-
1020
- When the transaction is finished, it will be sent to Sentry with all its
1021
- finished child spans.
1022
-
1023
- :param transaction: The transaction to start. If omitted, we create and
1024
- start a new transaction.
1025
- :param instrumenter: This parameter is meant for internal use only. It
1026
- will be removed in the next major version.
1027
- :param custom_sampling_context: The transaction's custom sampling context.
1028
- :param kwargs: Optional keyword arguments to be passed to the Transaction
1029
- constructor. See :py:class:`sentry_sdk.tracing.Transaction` for
1030
- available arguments.
902
+ .. deprecated:: 3.0.0
903
+ This function is deprecated and will be removed in a future release.
904
+ Use :py:meth:`sentry_sdk.start_span` instead.
1031
905
  """
1032
- kwargs.setdefault("scope", self)
1033
-
1034
- client = self.get_client()
1035
-
1036
- configuration_instrumenter = client.options["instrumenter"]
1037
-
1038
- if instrumenter != configuration_instrumenter:
1039
- return NoOpSpan()
1040
-
1041
- try_autostart_continuous_profiler()
1042
-
1043
- custom_sampling_context = custom_sampling_context or {}
1044
-
1045
- # kwargs at this point has type TransactionKwargs, since we have removed
1046
- # the client and custom_sampling_context from it.
1047
- transaction_kwargs = kwargs # type: TransactionKwargs
1048
-
1049
- # if we haven't been given a transaction, make one
1050
- if transaction is None:
1051
- transaction = Transaction(**transaction_kwargs)
1052
-
1053
- # use traces_sample_rate, traces_sampler, and/or inheritance to make a
1054
- # sampling decision
1055
- sampling_context = {
1056
- "transaction_context": transaction.to_json(),
1057
- "parent_sampled": transaction.parent_sampled,
1058
- }
1059
- sampling_context.update(custom_sampling_context)
1060
- transaction._set_initial_sampling_decision(sampling_context=sampling_context)
1061
-
1062
- # update the sample rate in the dsc
1063
- if transaction.sample_rate is not None:
1064
- propagation_context = self.get_active_propagation_context()
1065
- if propagation_context:
1066
- dsc = propagation_context.dynamic_sampling_context
1067
- if dsc is not None:
1068
- dsc["sample_rate"] = str(transaction.sample_rate)
1069
- if transaction._baggage:
1070
- transaction._baggage.sentry_items["sample_rate"] = str(
1071
- transaction.sample_rate
1072
- )
1073
-
1074
- if transaction.sampled:
1075
- profile = Profile(
1076
- transaction.sampled, transaction._start_timestamp_monotonic_ns
1077
- )
1078
- profile._set_initial_sampling_decision(sampling_context=sampling_context)
1079
-
1080
- transaction._profile = profile
1081
-
1082
- transaction._continuous_profile = try_profile_lifecycle_trace_start()
1083
-
1084
- # Typically, the profiler is set when the transaction is created. But when
1085
- # using the auto lifecycle, the profiler isn't running when the first
1086
- # transaction is started. So make sure we update the profiler id on it.
1087
- if transaction._continuous_profile is not None:
1088
- transaction.set_profiler_id(get_profiler_id())
1089
-
1090
- # we don't bother to keep spans if we already know we're not going to
1091
- # send the transaction
1092
- max_spans = (client.options["_experiments"].get("max_spans")) or 1000
1093
- transaction.init_span_recorder(maxlen=max_spans)
1094
-
1095
- return transaction
906
+ warnings.warn(
907
+ "The `start_transaction` method is deprecated, please use `sentry_sdk.start_span instead.`",
908
+ DeprecationWarning,
909
+ stacklevel=2,
910
+ )
911
+ return NoOpSpan(**kwargs)
1096
912
 
1097
- def start_span(self, instrumenter=INSTRUMENTER.SENTRY, **kwargs):
1098
- # type: (str, Any) -> Span
913
+ def start_span(self, **kwargs):
914
+ # type: (Any) -> Union[NoOpSpan, Span]
1099
915
  """
1100
- Start a span whose parent is the currently active span or transaction, if any.
916
+ Start a span whose parent is the currently active span, if any.
1101
917
 
1102
918
  The return value is a :py:class:`sentry_sdk.tracing.Span` instance,
1103
919
  typically used as a context manager to start and stop timing in a `with`
1104
920
  block.
1105
921
 
1106
- Only spans contained in a transaction are sent to Sentry. Most
1107
- integrations start a transaction at the appropriate time, for example
1108
- for every incoming HTTP request. Use
1109
- :py:meth:`sentry_sdk.start_transaction` to start a new transaction when
1110
- one is not already in progress.
1111
-
1112
922
  For supported `**kwargs` see :py:class:`sentry_sdk.tracing.Span`.
1113
-
1114
- The instrumenter parameter is deprecated for user code, and it will
1115
- be removed in the next major version. Going forward, it should only
1116
- be used by the SDK itself.
1117
923
  """
1118
- if kwargs.get("description") is not None:
1119
- warnings.warn(
1120
- "The `description` parameter is deprecated. Please use `name` instead.",
1121
- DeprecationWarning,
1122
- stacklevel=2,
1123
- )
1124
-
1125
- with new_scope():
1126
- kwargs.setdefault("scope", self)
1127
-
1128
- client = self.get_client()
1129
-
1130
- configuration_instrumenter = client.options["instrumenter"]
1131
-
1132
- if instrumenter != configuration_instrumenter:
1133
- return NoOpSpan()
1134
-
1135
- # get current span or transaction
1136
- span = self.span or self.get_isolation_scope().span
1137
-
1138
- if span is None:
1139
- # New spans get the `trace_id` from the scope
1140
- if "trace_id" not in kwargs:
1141
- propagation_context = self.get_active_propagation_context()
1142
- if propagation_context is not None:
1143
- kwargs["trace_id"] = propagation_context.trace_id
924
+ return NoOpSpan(**kwargs)
1144
925
 
1145
- span = Span(**kwargs)
1146
- else:
1147
- # Children take `trace_id`` from the parent span.
1148
- span = span.start_child(**kwargs)
1149
-
1150
- return span
1151
-
1152
- def continue_trace(
1153
- self, environ_or_headers, op=None, name=None, source=None, origin="manual"
1154
- ):
1155
- # type: (Dict[str, Any], Optional[str], Optional[str], Optional[str], str) -> Transaction
926
+ @contextmanager
927
+ def continue_trace(self, environ_or_headers):
928
+ # type: (Dict[str, Any]) -> Generator[None, None, None]
1156
929
  """
1157
- Sets the propagation context from environment or headers and returns a transaction.
930
+ Sets the propagation context from environment or headers to continue an incoming trace.
1158
931
  """
1159
932
  self.generate_propagation_context(environ_or_headers)
1160
-
1161
- # When we generate the propagation context, the sample_rand value is set
1162
- # if missing or invalid (we use the original value if it's valid).
1163
- # We want the transaction to use the same sample_rand value. Due to duplicated
1164
- # propagation logic in the transaction, we pass it in to avoid recomputing it
1165
- # in the transaction.
1166
- # TYPE SAFETY: self.generate_propagation_context() ensures that self._propagation_context
1167
- # is not None.
1168
- sample_rand = typing.cast(
1169
- PropagationContext, self._propagation_context
1170
- )._sample_rand()
1171
-
1172
- transaction = Transaction.continue_from_headers(
1173
- normalize_incoming_data(environ_or_headers),
1174
- _sample_rand=sample_rand,
1175
- op=op,
1176
- origin=origin,
1177
- name=name,
1178
- source=source,
1179
- )
1180
-
1181
- return transaction
933
+ yield
1182
934
 
1183
935
  def capture_event(self, event, hint=None, scope=None, **scope_kwargs):
1184
936
  # type: (Event, Optional[Hint], Optional[Scope], Any) -> Optional[str]
@@ -1432,7 +1184,11 @@ class Scope:
1432
1184
 
1433
1185
  # Add "trace" context
1434
1186
  if contexts.get("trace") is None:
1435
- if has_tracing_enabled(options) and self._span is not None:
1187
+ if (
1188
+ has_tracing_enabled(options)
1189
+ and self._span is not None
1190
+ and self._span.is_valid
1191
+ ):
1436
1192
  contexts["trace"] = self._span.get_trace_context()
1437
1193
  else:
1438
1194
  contexts["trace"] = self.get_trace_context()
@@ -1482,8 +1238,8 @@ class Scope:
1482
1238
 
1483
1239
  if not is_check_in:
1484
1240
  # Get scopes without creating them to prevent infinite recursion
1485
- isolation_scope = _isolation_scope.get()
1486
- current_scope = _current_scope.get()
1241
+ isolation_scope = self._get_isolation_scope()
1242
+ current_scope = self._get_current_scope()
1487
1243
 
1488
1244
  event_processors = chain(
1489
1245
  global_event_processors,
@@ -1493,7 +1249,7 @@ class Scope:
1493
1249
  )
1494
1250
 
1495
1251
  for event_processor in event_processors:
1496
- new_event = event
1252
+ new_event = event # type: Optional[Event]
1497
1253
  with capture_internal_exceptions():
1498
1254
  new_event = event_processor(event, hint)
1499
1255
  if new_event is None: