Skip to content

Commit 44ba734

Browse files
Documenting Spans and Transactions (#2358)
Added some docstrings and also did some minor cleanup for better readability of the code. --------- Co-authored-by: Ivana Kellyerova <[email protected]>
1 parent 34232eb commit 44ba734

File tree

3 files changed

+111
-22
lines changed

3 files changed

+111
-22
lines changed

sentry_sdk/hub.py

+13-3
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,7 @@ def start_span(self, span=None, instrumenter=INSTRUMENTER.SENTRY, **kwargs):
479479
if instrumenter != configuration_instrumenter:
480480
return NoOpSpan()
481481

482+
# THIS BLOCK IS DEPRECATED
482483
# TODO: consider removing this in a future release.
483484
# This is for backwards compatibility with releases before
484485
# start_transaction existed, to allow for a smoother transition.
@@ -487,24 +488,33 @@ def start_span(self, span=None, instrumenter=INSTRUMENTER.SENTRY, **kwargs):
487488
"Deprecated: use start_transaction to start transactions and "
488489
"Transaction.start_child to start spans."
489490
)
491+
490492
if isinstance(span, Transaction):
491493
logger.warning(deprecation_msg)
492494
return self.start_transaction(span)
495+
493496
if "transaction" in kwargs:
494497
logger.warning(deprecation_msg)
495498
name = kwargs.pop("transaction")
496499
return self.start_transaction(name=name, **kwargs)
497500

501+
# THIS BLOCK IS DEPRECATED
502+
# We do not pass a span into start_span in our code base, so I deprecate this.
498503
if span is not None:
504+
deprecation_msg = "Deprecated: passing a span into `start_span` is deprecated and will be removed in the future."
505+
logger.warning(deprecation_msg)
499506
return span
500507

501508
kwargs.setdefault("hub", self)
502509

503-
span = self.scope.span
504-
if span is not None:
505-
return span.start_child(**kwargs)
510+
active_span = self.scope.span
511+
if active_span is not None:
512+
new_child_span = active_span.start_child(**kwargs)
513+
return new_child_span
506514

507515
# If there is already a trace_id in the propagation context, use it.
516+
# This does not need to be done for `start_child` above because it takes
517+
# the trace_id from the parent span.
508518
if "trace_id" not in kwargs:
509519
traceparent = self.get_traceparent()
510520
trace_id = traceparent.split("-")[0] if traceparent else None

sentry_sdk/tracing.py

+94-19
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ def add(self, span):
8080

8181

8282
class Span(object):
83+
"""A span holds timing information of a block of code.
84+
Spans can have multiple child spans thus forming a span tree."""
85+
8386
__slots__ = (
8487
"trace_id",
8588
"span_id",
@@ -201,6 +204,9 @@ def __exit__(self, ty, value, tb):
201204
@property
202205
def containing_transaction(self):
203206
# type: () -> Optional[Transaction]
207+
"""The ``Transaction`` that this span belongs to.
208+
The ``Transaction`` is the root of the span tree,
209+
so one could also think of this ``Transaction`` as the "root span"."""
204210

205211
# this is a getter rather than a regular attribute so that transactions
206212
# can return `self` here instead (as a way to prevent them circularly
@@ -237,12 +243,15 @@ def start_child(self, instrumenter=INSTRUMENTER.SENTRY, **kwargs):
237243
)
238244
if span_recorder:
239245
span_recorder.add(child)
246+
240247
return child
241248

242249
def new_span(self, **kwargs):
243250
# type: (**Any) -> Span
244-
"""Deprecated: use :py:meth:`sentry_sdk.tracing.Span.start_child` instead."""
245-
logger.warning("Deprecated: use Span.start_child instead of Span.new_span.")
251+
"""DEPRECATED: use :py:meth:`sentry_sdk.tracing.Span.start_child` instead."""
252+
logger.warning(
253+
"Deprecated: use Span.start_child instead of Span.new_span. This will be removed in the future."
254+
)
246255
return self.start_child(**kwargs)
247256

248257
@classmethod
@@ -254,12 +263,15 @@ def continue_from_environ(
254263
# type: (...) -> Transaction
255264
"""
256265
Create a Transaction with the given params, then add in data pulled from
257-
the 'sentry-trace' and 'baggage' headers from the environ (if any)
266+
the ``sentry-trace`` and ``baggage`` headers from the environ (if any)
258267
before returning the Transaction.
259268
260-
This is different from `continue_from_headers` in that it assumes header
261-
names in the form "HTTP_HEADER_NAME" - such as you would get from a wsgi
262-
environ - rather than the form "header-name".
269+
This is different from :py:meth:`~sentry_sdk.tracing.Span.continue_from_headers`
270+
in that it assumes header names in the form ``HTTP_HEADER_NAME`` -
271+
such as you would get from a WSGI/ASGI environ -
272+
rather than the form ``header-name``.
273+
274+
:param environ: The ASGI/WSGI environ to pull information from.
263275
"""
264276
if cls is Span:
265277
logger.warning(
@@ -277,7 +289,9 @@ def continue_from_headers(
277289
# type: (...) -> Transaction
278290
"""
279291
Create a transaction with the given params (including any data pulled from
280-
the 'sentry-trace' and 'baggage' headers).
292+
the ``sentry-trace`` and ``baggage`` headers).
293+
294+
:param headers: The dictionary with the HTTP headers to pull information from.
281295
"""
282296
# TODO move this to the Transaction class
283297
if cls is Span:
@@ -311,8 +325,8 @@ def continue_from_headers(
311325
def iter_headers(self):
312326
# type: () -> Iterator[Tuple[str, str]]
313327
"""
314-
Creates a generator which returns the span's `sentry-trace` and `baggage` headers.
315-
If the span's containing transaction doesn't yet have a `baggage` value,
328+
Creates a generator which returns the span's ``sentry-trace`` and ``baggage`` headers.
329+
If the span's containing transaction doesn't yet have a ``baggage`` value,
316330
this will cause one to be generated and stored.
317331
"""
318332
yield SENTRY_TRACE_HEADER_NAME, self.to_traceparent()
@@ -330,10 +344,10 @@ def from_traceparent(
330344
):
331345
# type: (...) -> Optional[Transaction]
332346
"""
333-
DEPRECATED: Use :py:meth:`sentry_sdk.tracing.Transaction.continue_from_headers`.
347+
DEPRECATED: Use :py:meth:`sentry_sdk.tracing.Span.continue_from_headers`.
334348
335-
Create a `Transaction` with the given params, then add in data pulled from
336-
the given 'sentry-trace' header value before returning the `Transaction`.
349+
Create a ``Transaction`` with the given params, then add in data pulled from
350+
the given ``sentry-trace`` header value before returning the ``Transaction``.
337351
"""
338352
logger.warning(
339353
"Deprecated: Use Transaction.continue_from_headers(headers, **kwargs) "
@@ -364,6 +378,9 @@ def to_traceparent(self):
364378

365379
def to_baggage(self):
366380
# type: () -> Optional[Baggage]
381+
"""Returns the :py:class:`~sentry_sdk.tracing_utils.Baggage`
382+
associated with this ``Span``, if any. (Taken from the root of the span tree.)
383+
"""
367384
if self.containing_transaction:
368385
return self.containing_transaction.get_baggage()
369386
return None
@@ -422,8 +439,21 @@ def is_success(self):
422439

423440
def finish(self, hub=None, end_timestamp=None):
424441
# type: (Optional[sentry_sdk.Hub], Optional[datetime]) -> Optional[str]
425-
# XXX: would be type: (Optional[sentry_sdk.Hub]) -> None, but that leads
442+
# Note: would be type: (Optional[sentry_sdk.Hub]) -> None, but that leads
426443
# to incompatible return types for Span.finish and Transaction.finish.
444+
"""Sets the end timestamp of the span.
445+
Additionally it also creates a breadcrumb from the span,
446+
if the span represents a database or HTTP request.
447+
448+
:param hub: The hub to use for this transaction.
449+
If not provided, the current hub will be used.
450+
:param end_timestamp: Optional timestamp that should
451+
be used as timestamp instead of the current time.
452+
453+
:return: Always ``None``. The type is ``Optional[str]`` to match
454+
the return value of :py:meth:`sentry_sdk.tracing.Transaction.finish`.
455+
"""
456+
427457
if self.timestamp is not None:
428458
# This span is already finished, ignore.
429459
return None
@@ -446,6 +476,8 @@ def finish(self, hub=None, end_timestamp=None):
446476

447477
def to_json(self):
448478
# type: () -> Dict[str, Any]
479+
"""Returns a JSON-compatible representation of the span."""
480+
449481
rv = {
450482
"trace_id": self.trace_id,
451483
"span_id": self.span_id,
@@ -491,6 +523,9 @@ def get_trace_context(self):
491523

492524

493525
class Transaction(Span):
526+
"""The Transaction is the root element that holds all the spans
527+
for Sentry performance instrumentation."""
528+
494529
__slots__ = (
495530
"name",
496531
"source",
@@ -512,6 +547,19 @@ def __init__(
512547
**kwargs # type: Any
513548
):
514549
# type: (...) -> None
550+
"""Constructs a new Transaction.
551+
552+
:param name: Identifier of the transaction.
553+
Will show up in the Sentry UI.
554+
:param parent_sampled: Whether the parent transaction was sampled.
555+
If True this transaction will be kept, if False it will be discarded.
556+
:param baggage: The W3C baggage header value.
557+
(see https://www.w3.org/TR/baggage/)
558+
:param source: A string describing the source of the transaction name.
559+
This will be used to determine the transaction's type.
560+
See https://develop.sentry.dev/sdk/event-payloads/transaction/#transaction-annotations
561+
for more information. Default "custom".
562+
"""
515563
# TODO: consider removing this in a future release.
516564
# This is for backwards compatibility with releases before Transaction
517565
# existed, to allow for a smoother transition.
@@ -522,7 +570,7 @@ def __init__(
522570
)
523571
name = kwargs.pop("transaction")
524572

525-
Span.__init__(self, **kwargs)
573+
super(Transaction, self).__init__(**kwargs)
526574

527575
self.name = name
528576
self.source = source
@@ -568,6 +616,9 @@ def __exit__(self, ty, value, tb):
568616
@property
569617
def containing_transaction(self):
570618
# type: () -> Transaction
619+
"""The root element of the span tree.
620+
In the case of a transaction it is the transaction itself.
621+
"""
571622

572623
# Transactions (as spans) belong to themselves (as transactions). This
573624
# is a getter rather than a regular attribute to avoid having a circular
@@ -576,6 +627,17 @@ def containing_transaction(self):
576627

577628
def finish(self, hub=None, end_timestamp=None):
578629
# type: (Optional[sentry_sdk.Hub], Optional[datetime]) -> Optional[str]
630+
"""Finishes the transaction and sends it to Sentry.
631+
All finished spans in the transaction will also be sent to Sentry.
632+
633+
:param hub: The hub to use for this transaction.
634+
If not provided, the current hub will be used.
635+
:param end_timestamp: Optional timestamp that should
636+
be used as timestamp instead of the current time.
637+
638+
:return: The event ID if the transaction was sent to Sentry,
639+
otherwise None.
640+
"""
579641
if self.timestamp is not None:
580642
# This transaction is already finished, ignore.
581643
return None
@@ -610,7 +672,7 @@ def finish(self, hub=None, end_timestamp=None):
610672
)
611673
self.name = "<unlabeled transaction>"
612674

613-
Span.finish(self, hub, end_timestamp)
675+
super(Transaction, self).finish(hub, end_timestamp)
614676

615677
if not self.sampled:
616678
# At this point a `sampled = None` should have already been resolved
@@ -661,15 +723,26 @@ def set_measurement(self, name, value, unit=""):
661723

662724
def set_context(self, key, value):
663725
# type: (str, Any) -> None
726+
"""Sets a context. Transactions can have multiple contexts
727+
and they should follow the format described in the "Contexts Interface"
728+
documentation.
729+
730+
:param key: The name of the context.
731+
:param value: The information about the context.
732+
"""
664733
self._contexts[key] = value
665734

666735
def set_http_status(self, http_status):
667736
# type: (int) -> None
737+
"""Sets the status of the Transaction according to the given HTTP status.
738+
739+
:param http_status: The HTTP status code."""
668740
super(Transaction, self).set_http_status(http_status)
669741
self.set_context("response", {"status_code": http_status})
670742

671743
def to_json(self):
672744
# type: () -> Dict[str, Any]
745+
"""Returns a JSON-compatible representation of the transaction."""
673746
rv = super(Transaction, self).to_json()
674747

675748
rv["name"] = self.name
@@ -680,10 +753,12 @@ def to_json(self):
680753

681754
def get_baggage(self):
682755
# type: () -> Baggage
683-
"""
684-
The first time a new baggage with sentry items is made,
685-
it will be frozen.
686-
"""
756+
"""Returns the :py:class:`~sentry_sdk.tracing_utils.Baggage`
757+
associated with the Transaction.
758+
759+
The first time a new baggage with Sentry items is made,
760+
it will be frozen."""
761+
687762
if not self._baggage or self._baggage.mutable:
688763
self._baggage = Baggage.populate_from_transaction(self)
689764

sentry_sdk/tracing_utils.py

+4
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,10 @@ def _format_sql(cursor, sql):
215215

216216

217217
class Baggage(object):
218+
"""
219+
The W3C Baggage header information (see https://www.w3.org/TR/baggage/).
220+
"""
221+
218222
__slots__ = ("sentry_items", "third_party_items", "mutable")
219223

220224
SENTRY_PREFIX = "sentry-"

0 commit comments

Comments
 (0)