From 90364c196be345de383fccc401295a48d16070a2 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Thu, 7 Sep 2023 16:39:00 +0200 Subject: [PATCH 01/10] Adding some docstrings and some smaller cleanup --- sentry_sdk/hub.py | 16 +++++- sentry_sdk/tracing.py | 110 ++++++++++++++++++++++++++++++------ sentry_sdk/tracing_utils.py | 4 ++ 3 files changed, 109 insertions(+), 21 deletions(-) diff --git a/sentry_sdk/hub.py b/sentry_sdk/hub.py index ac77fb42fc..3d53fc1c77 100644 --- a/sentry_sdk/hub.py +++ b/sentry_sdk/hub.py @@ -479,6 +479,7 @@ def start_span(self, span=None, instrumenter=INSTRUMENTER.SENTRY, **kwargs): if instrumenter != configuration_instrumenter: return NoOpSpan() + # THIS BLOCK IS DEPRECATED # TODO: consider removing this in a future release. # This is for backwards compatibility with releases before # start_transaction existed, to allow for a smoother transition. @@ -487,24 +488,33 @@ def start_span(self, span=None, instrumenter=INSTRUMENTER.SENTRY, **kwargs): "Deprecated: use start_transaction to start transactions and " "Transaction.start_child to start spans." ) + if isinstance(span, Transaction): logger.warning(deprecation_msg) return self.start_transaction(span) + if "transaction" in kwargs: logger.warning(deprecation_msg) name = kwargs.pop("transaction") return self.start_transaction(name=name, **kwargs) + # THIS BLOCK IS DEPRECATED + # We do not pass a span into start_span in our code base, so I deprecate this. if span is not None: + deprecation_msg = "Deprecated: passing a span into `start_span` is deprecated and will be removed in the future. " + logger.warning(deprecation_msg) return span kwargs.setdefault("hub", self) - span = self.scope.span - if span is not None: - return span.start_child(**kwargs) + active_span = self.scope.span + if active_span is not None: + new_child_span = active_span.start_child(**kwargs) + return new_child_span # If there is already a trace_id in the propagation context, use it. + # This does not need to be done for `start_child` above because it takes + # the trace_id from the parent span. if "trace_id" not in kwargs: traceparent = self.get_traceparent() trace_id = traceparent.split("-")[0] if traceparent else None diff --git a/sentry_sdk/tracing.py b/sentry_sdk/tracing.py index 6967e95411..c017b72760 100644 --- a/sentry_sdk/tracing.py +++ b/sentry_sdk/tracing.py @@ -80,6 +80,9 @@ def add(self, span): class Span(object): + """A span holds timing information of a block of code. + Spans can have multiple child spans thus forming a span tree.""" + __slots__ = ( "trace_id", "span_id", @@ -201,6 +204,9 @@ def __exit__(self, ty, value, tb): @property def containing_transaction(self): # type: () -> Optional[Transaction] + """The ``Transaction`` that this span belongs to. + The ``Transaction`` is the root of the span tree, + so one could also think of this ``Transaction`` as the "root span".""" # this is a getter rather than a regular attribute so that transactions # can return `self` here instead (as a way to prevent them circularly @@ -237,12 +243,15 @@ def start_child(self, instrumenter=INSTRUMENTER.SENTRY, **kwargs): ) if span_recorder: span_recorder.add(child) + return child def new_span(self, **kwargs): # type: (**Any) -> Span - """Deprecated: use :py:meth:`sentry_sdk.tracing.Span.start_child` instead.""" - logger.warning("Deprecated: use Span.start_child instead of Span.new_span.") + """DEPRECATED: use :py:meth:`sentry_sdk.tracing.Span.start_child` instead.""" + logger.warning( + "Deprecated: use Span.start_child instead of Span.new_span. This will be removed in the future." + ) return self.start_child(**kwargs) @classmethod @@ -254,12 +263,15 @@ def continue_from_environ( # type: (...) -> Transaction """ Create a Transaction with the given params, then add in data pulled from - the 'sentry-trace' and 'baggage' headers from the environ (if any) + the ``sentry-trace`` and ``baggage`` headers from the environ (if any) before returning the Transaction. - This is different from `continue_from_headers` in that it assumes header - names in the form "HTTP_HEADER_NAME" - such as you would get from a wsgi - environ - rather than the form "header-name". + This is different from :py:meth:`~sentry_sdk.tracing.Span.continue_from_headers` + in that it assumes header names in the form ``HTTP_HEADER_NAME`` - + such as you would get from a WSGI/ASGI environ - + rather than the form ``header-name``. + + :param envrion: The ASGI/WSGI environ to pull information from. """ if cls is Span: logger.warning( @@ -277,7 +289,9 @@ def continue_from_headers( # type: (...) -> Transaction """ Create a transaction with the given params (including any data pulled from - the 'sentry-trace' and 'baggage' headers). + the ``sentry-trace`` and ``baggage`` headers). + + :param headers: The dictionary with the HTTP headers to pull information from. """ # TODO move this to the Transaction class if cls is Span: @@ -311,8 +325,8 @@ def continue_from_headers( def iter_headers(self): # type: () -> Iterator[Tuple[str, str]] """ - Creates a generator which returns the span's `sentry-trace` and `baggage` headers. - If the span's containing transaction doesn't yet have a `baggage` value, + Creates a generator which returns the span's ``sentry-trace`` and ``baggage`` headers. + If the span's containing transaction doesn't yet have a ``baggage`` value, this will cause one to be generated and stored. """ yield SENTRY_TRACE_HEADER_NAME, self.to_traceparent() @@ -330,10 +344,10 @@ def from_traceparent( ): # type: (...) -> Optional[Transaction] """ - DEPRECATED: Use :py:meth:`sentry_sdk.tracing.Transaction.continue_from_headers`. + DEPRECATED: Use :py:meth:`sentry_sdk.tracing.Span.continue_from_headers`. - Create a `Transaction` with the given params, then add in data pulled from - the given 'sentry-trace' header value before returning the `Transaction`. + Create a ``Transaction`` with the given params, then add in data pulled from + the given ``sentry-trace`` header value before returning the ``Transaction``. """ logger.warning( "Deprecated: Use Transaction.continue_from_headers(headers, **kwargs) " @@ -364,6 +378,8 @@ def to_traceparent(self): def to_baggage(self): # type: () -> Optional[Baggage] + """Returns the :py:class:`~sentry_sdk.tracing_utils.Baggage` + associated with this ``Span``, if any. (Taken from the root of the span tree.)""" if self.containing_transaction: return self.containing_transaction.get_baggage() return None @@ -422,8 +438,21 @@ def is_success(self): def finish(self, hub=None, end_timestamp=None): # type: (Optional[sentry_sdk.Hub], Optional[datetime]) -> Optional[str] - # XXX: would be type: (Optional[sentry_sdk.Hub]) -> None, but that leads + # Note: would be type: (Optional[sentry_sdk.Hub]) -> None, but that leads # to incompatible return types for Span.finish and Transaction.finish. + """Sets the end timestamp of the span. + Additionally it also creates a breadcrumb from the span, + if the span represents a database or http request. + + :param hub: The hub to use for this transaction. + If not provided, the current hub will be used. + :param end_timestamp: Optional timestamp that should + be used as timestamp instead of the current time. + + :return: Always ``None``. The type is ``Optional[str]`` to match + the return value of :py:meth:`sentry_sdk.tracing.Transaction.finish`. + """ + if self.timestamp is not None: # This span is already finished, ignore. return None @@ -446,6 +475,8 @@ def finish(self, hub=None, end_timestamp=None): def to_json(self): # type: () -> Dict[str, Any] + """Returns a JSON-compatible representation of the span.""" + rv = { "trace_id": self.trace_id, "span_id": self.span_id, @@ -491,6 +522,9 @@ def get_trace_context(self): class Transaction(Span): + """The Transaction is the root element that holds all the spans + for the Sentry performance instrumentation.""" + __slots__ = ( "name", "source", @@ -512,6 +546,19 @@ def __init__( **kwargs # type: Any ): # type: (...) -> None + """Constructs a new Transaction. + + :param name: Identifier of the transaction. + Will show up in the Sentry UI. + :param parent_sampled: Whether the parent transaction was sampled. + If True this transaction will be kept, if False it will be discarded. + :param baggage: The W3C baggage header value. + (see https://www.w3.org/TR/baggage/) + :param source: A string describing the source of the transactions name. + This will be used to determine the transaction's type. + See https://develop.sentry.dev/sdk/event-payloads/transaction/#transaction-annotations + for more information. Default "custom". + """ # TODO: consider removing this in a future release. # This is for backwards compatibility with releases before Transaction # existed, to allow for a smoother transition. @@ -522,7 +569,7 @@ def __init__( ) name = kwargs.pop("transaction") - Span.__init__(self, **kwargs) + super(Transaction, self).__init__(**kwargs) self.name = name self.source = source @@ -568,6 +615,9 @@ def __exit__(self, ty, value, tb): @property def containing_transaction(self): # type: () -> Transaction + """The root element of the span tree. + In the case of the transaction, it is the transaction itself. + """ # Transactions (as spans) belong to themselves (as transactions). This # is a getter rather than a regular attribute to avoid having a circular @@ -576,6 +626,17 @@ def containing_transaction(self): def finish(self, hub=None, end_timestamp=None): # type: (Optional[sentry_sdk.Hub], Optional[datetime]) -> Optional[str] + """Finishes the transaction and sends it to Sentry. + All finished spans in the transaction will also be sent to Sentry. + + :param hub: The hub to use for this transaction. + If not provided, the current hub will be used. + :param end_timestamp: Optional timestamp that should + be used as timestamp instead of the current time. + + :return: The event ID if the transaction was sent to Sentry, + otherwise None. + """ if self.timestamp is not None: # This transaction is already finished, ignore. return None @@ -610,7 +671,7 @@ def finish(self, hub=None, end_timestamp=None): ) self.name = "" - Span.finish(self, hub, end_timestamp) + super(Transaction, self).finish(hub, end_timestamp) if not self.sampled: # At this point a `sampled = None` should have already been resolved @@ -661,15 +722,26 @@ def set_measurement(self, name, value, unit=""): def set_context(self, key, value): # type: (str, Any) -> None + """Sets a context. Transactions can have multiple contexts + and they should follow the format described in the "Contexts Interface" + documentation. + + :param key: The name of the context. + :param value: The information about the context. + """ self._contexts[key] = value def set_http_status(self, http_status): # type: (int) -> None + """Sets the status of the Transaction according to the given HTTP status. + + :param http_status: The HTTP status code.""" super(Transaction, self).set_http_status(http_status) self.set_context("response", {"status_code": http_status}) def to_json(self): # type: () -> Dict[str, Any] + """Returns a JSON-compatible representation of the transaction.""" rv = super(Transaction, self).to_json() rv["name"] = self.name @@ -680,10 +752,12 @@ def to_json(self): def get_baggage(self): # type: () -> Baggage - """ + """Returns the :py:class:`~sentry_sdk.tracing_utils.Baggage` + associated with the Transaction. + The first time a new baggage with sentry items is made, - it will be frozen. - """ + it will be frozen.""" + if not self._baggage or self._baggage.mutable: self._baggage = Baggage.populate_from_transaction(self) diff --git a/sentry_sdk/tracing_utils.py b/sentry_sdk/tracing_utils.py index fca416028b..13f5e6ae66 100644 --- a/sentry_sdk/tracing_utils.py +++ b/sentry_sdk/tracing_utils.py @@ -212,6 +212,10 @@ def _format_sql(cursor, sql): class Baggage(object): + """ + The W3C Baggage header information. (see https://www.w3.org/TR/baggage/) + """ + __slots__ = ("sentry_items", "third_party_items", "mutable") SENTRY_PREFIX = "sentry-" From 21bb4ef7c2c99217e1ea0effa2f8b6d7577d47e5 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Thu, 7 Sep 2023 17:04:03 +0200 Subject: [PATCH 02/10] Update sentry_sdk/hub.py Co-authored-by: Ivana Kellyerova --- sentry_sdk/hub.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry_sdk/hub.py b/sentry_sdk/hub.py index 3d53fc1c77..ba869f955e 100644 --- a/sentry_sdk/hub.py +++ b/sentry_sdk/hub.py @@ -501,7 +501,7 @@ def start_span(self, span=None, instrumenter=INSTRUMENTER.SENTRY, **kwargs): # THIS BLOCK IS DEPRECATED # We do not pass a span into start_span in our code base, so I deprecate this. if span is not None: - deprecation_msg = "Deprecated: passing a span into `start_span` is deprecated and will be removed in the future. " + deprecation_msg = "Deprecated: passing a span into `start_span` is deprecated and will be removed in the future." logger.warning(deprecation_msg) return span From 065a879d53e0dae8fedba2fc2da85c5226a185ec Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Thu, 7 Sep 2023 17:04:11 +0200 Subject: [PATCH 03/10] Update sentry_sdk/tracing.py Co-authored-by: Ivana Kellyerova --- sentry_sdk/tracing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry_sdk/tracing.py b/sentry_sdk/tracing.py index c017b72760..9d80a6eb5e 100644 --- a/sentry_sdk/tracing.py +++ b/sentry_sdk/tracing.py @@ -271,7 +271,7 @@ def continue_from_environ( such as you would get from a WSGI/ASGI environ - rather than the form ``header-name``. - :param envrion: The ASGI/WSGI environ to pull information from. + :param environ: The ASGI/WSGI environ to pull information from. """ if cls is Span: logger.warning( From 8c8684ad35050743f348e51a99fbf479fc2ab7d0 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Thu, 7 Sep 2023 17:04:24 +0200 Subject: [PATCH 04/10] Update sentry_sdk/tracing.py Co-authored-by: Ivana Kellyerova --- sentry_sdk/tracing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry_sdk/tracing.py b/sentry_sdk/tracing.py index 9d80a6eb5e..55289f214d 100644 --- a/sentry_sdk/tracing.py +++ b/sentry_sdk/tracing.py @@ -523,7 +523,7 @@ def get_trace_context(self): class Transaction(Span): """The Transaction is the root element that holds all the spans - for the Sentry performance instrumentation.""" + for Sentry performance instrumentation.""" __slots__ = ( "name", From 014ab33c8d8d6c1431dbb643a6fed91d568f80ea Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Thu, 7 Sep 2023 17:04:32 +0200 Subject: [PATCH 05/10] Update sentry_sdk/tracing.py Co-authored-by: Ivana Kellyerova --- sentry_sdk/tracing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry_sdk/tracing.py b/sentry_sdk/tracing.py index 55289f214d..6f86ab1237 100644 --- a/sentry_sdk/tracing.py +++ b/sentry_sdk/tracing.py @@ -554,7 +554,7 @@ def __init__( If True this transaction will be kept, if False it will be discarded. :param baggage: The W3C baggage header value. (see https://www.w3.org/TR/baggage/) - :param source: A string describing the source of the transactions name. + :param source: A string describing the source of the transaction name. This will be used to determine the transaction's type. See https://develop.sentry.dev/sdk/event-payloads/transaction/#transaction-annotations for more information. Default "custom". From 7f6753d65cc2a65496dd84bcdb16cb1ee68f59db Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Thu, 7 Sep 2023 17:04:45 +0200 Subject: [PATCH 06/10] Update sentry_sdk/tracing.py Co-authored-by: Ivana Kellyerova --- sentry_sdk/tracing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry_sdk/tracing.py b/sentry_sdk/tracing.py index 6f86ab1237..5d501fce36 100644 --- a/sentry_sdk/tracing.py +++ b/sentry_sdk/tracing.py @@ -616,7 +616,7 @@ def __exit__(self, ty, value, tb): def containing_transaction(self): # type: () -> Transaction """The root element of the span tree. - In the case of the transaction, it is the transaction itself. + In the case of a transaction it is the transaction itself. """ # Transactions (as spans) belong to themselves (as transactions). This From 7210fe89c40d2cdd8727916e019673de64de09bf Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Thu, 7 Sep 2023 17:04:57 +0200 Subject: [PATCH 07/10] Update sentry_sdk/tracing.py Co-authored-by: Ivana Kellyerova --- sentry_sdk/tracing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry_sdk/tracing.py b/sentry_sdk/tracing.py index 5d501fce36..7170656c24 100644 --- a/sentry_sdk/tracing.py +++ b/sentry_sdk/tracing.py @@ -755,7 +755,7 @@ def get_baggage(self): """Returns the :py:class:`~sentry_sdk.tracing_utils.Baggage` associated with the Transaction. - The first time a new baggage with sentry items is made, + The first time a new baggage with Sentry items is made, it will be frozen.""" if not self._baggage or self._baggage.mutable: From ef50049554a840e018f3087be032b73577e874d4 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Thu, 7 Sep 2023 17:05:07 +0200 Subject: [PATCH 08/10] Update sentry_sdk/tracing_utils.py Co-authored-by: Ivana Kellyerova --- sentry_sdk/tracing_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry_sdk/tracing_utils.py b/sentry_sdk/tracing_utils.py index 13f5e6ae66..4682c640c0 100644 --- a/sentry_sdk/tracing_utils.py +++ b/sentry_sdk/tracing_utils.py @@ -213,7 +213,7 @@ def _format_sql(cursor, sql): class Baggage(object): """ - The W3C Baggage header information. (see https://www.w3.org/TR/baggage/) + The W3C Baggage header information (see https://www.w3.org/TR/baggage/). """ __slots__ = ("sentry_items", "third_party_items", "mutable") From 13b788a913bfb07df23148251b20443c494d41da Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Thu, 7 Sep 2023 17:05:12 +0200 Subject: [PATCH 09/10] Update sentry_sdk/tracing.py Co-authored-by: Ivana Kellyerova --- sentry_sdk/tracing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry_sdk/tracing.py b/sentry_sdk/tracing.py index 7170656c24..5ded3c6b18 100644 --- a/sentry_sdk/tracing.py +++ b/sentry_sdk/tracing.py @@ -442,7 +442,7 @@ def finish(self, hub=None, end_timestamp=None): # to incompatible return types for Span.finish and Transaction.finish. """Sets the end timestamp of the span. Additionally it also creates a breadcrumb from the span, - if the span represents a database or http request. + if the span represents a database or HTTP request. :param hub: The hub to use for this transaction. If not provided, the current hub will be used. From 0fa19168d41060fb0509fe136a780d420d8e58dd Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Mon, 11 Sep 2023 15:36:30 +0200 Subject: [PATCH 10/10] Formatting --- sentry_sdk/tracing.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sentry_sdk/tracing.py b/sentry_sdk/tracing.py index 5ded3c6b18..38f83acb2a 100644 --- a/sentry_sdk/tracing.py +++ b/sentry_sdk/tracing.py @@ -379,7 +379,8 @@ def to_traceparent(self): def to_baggage(self): # type: () -> Optional[Baggage] """Returns the :py:class:`~sentry_sdk.tracing_utils.Baggage` - associated with this ``Span``, if any. (Taken from the root of the span tree.)""" + associated with this ``Span``, if any. (Taken from the root of the span tree.) + """ if self.containing_transaction: return self.containing_transaction.get_baggage() return None