|
6 | 6 |
|
7 | 7 | from sentry_sdk.attachments import Attachment
|
8 | 8 | from sentry_sdk._compat import datetime_utcnow
|
9 |
| -from sentry_sdk.consts import FALSE_VALUES |
| 9 | +from sentry_sdk.consts import FALSE_VALUES, INSTRUMENTER |
10 | 10 | from sentry_sdk._functools import wraps
|
| 11 | +from sentry_sdk.profiler import Profile |
11 | 12 | from sentry_sdk.session import Session
|
12 | 13 | from sentry_sdk.tracing_utils import (
|
13 | 14 | Baggage,
|
|
18 | 19 | from sentry_sdk.tracing import (
|
19 | 20 | BAGGAGE_HEADER_NAME,
|
20 | 21 | SENTRY_TRACE_HEADER_NAME,
|
| 22 | + NoOpSpan, |
| 23 | + Span, |
21 | 24 | Transaction,
|
22 | 25 | )
|
23 | 26 | from sentry_sdk._types import TYPE_CHECKING
|
|
34 | 37 | from typing import Optional
|
35 | 38 | from typing import Tuple
|
36 | 39 | from typing import TypeVar
|
| 40 | + from typing import Union |
37 | 41 |
|
38 | 42 | from sentry_sdk._types import (
|
39 | 43 | Breadcrumb,
|
|
46 | 50 | Type,
|
47 | 51 | )
|
48 | 52 |
|
49 |
| - from sentry_sdk.profiler import Profile |
50 |
| - from sentry_sdk.tracing import Span |
51 |
| - |
52 | 53 | F = TypeVar("F", bound=Callable[..., Any])
|
53 | 54 | T = TypeVar("T")
|
54 | 55 |
|
@@ -636,6 +637,155 @@ def add_breadcrumb(self, crumb=None, hint=None, **kwargs):
|
636 | 637 | while len(self._breadcrumbs) > max_breadcrumbs:
|
637 | 638 | self._breadcrumbs.popleft()
|
638 | 639 |
|
| 640 | + def start_transaction( |
| 641 | + self, transaction=None, instrumenter=INSTRUMENTER.SENTRY, **kwargs |
| 642 | + ): |
| 643 | + # type: (Optional[Transaction], str, Any) -> Union[Transaction, NoOpSpan] |
| 644 | + """ |
| 645 | + Start and return a transaction. |
| 646 | +
|
| 647 | + Start an existing transaction if given, otherwise create and start a new |
| 648 | + transaction with kwargs. |
| 649 | +
|
| 650 | + This is the entry point to manual tracing instrumentation. |
| 651 | +
|
| 652 | + A tree structure can be built by adding child spans to the transaction, |
| 653 | + and child spans to other spans. To start a new child span within the |
| 654 | + transaction or any span, call the respective `.start_child()` method. |
| 655 | +
|
| 656 | + Every child span must be finished before the transaction is finished, |
| 657 | + otherwise the unfinished spans are discarded. |
| 658 | +
|
| 659 | + When used as context managers, spans and transactions are automatically |
| 660 | + finished at the end of the `with` block. If not using context managers, |
| 661 | + call the `.finish()` method. |
| 662 | +
|
| 663 | + When the transaction is finished, it will be sent to Sentry with all its |
| 664 | + finished child spans. |
| 665 | +
|
| 666 | + For supported `**kwargs` see :py:class:`sentry_sdk.tracing.Transaction`. |
| 667 | + """ |
| 668 | + hub = kwargs.pop("hub", None) |
| 669 | + client = kwargs.pop("client", None) |
| 670 | + |
| 671 | + configuration_instrumenter = client and client.options["instrumenter"] |
| 672 | + |
| 673 | + if instrumenter != configuration_instrumenter: |
| 674 | + return NoOpSpan() |
| 675 | + |
| 676 | + custom_sampling_context = kwargs.pop("custom_sampling_context", {}) |
| 677 | + |
| 678 | + # if we haven't been given a transaction, make one |
| 679 | + if transaction is None: |
| 680 | + kwargs.setdefault("hub", hub) |
| 681 | + transaction = Transaction(**kwargs) |
| 682 | + |
| 683 | + # use traces_sample_rate, traces_sampler, and/or inheritance to make a |
| 684 | + # sampling decision |
| 685 | + sampling_context = { |
| 686 | + "transaction_context": transaction.to_json(), |
| 687 | + "parent_sampled": transaction.parent_sampled, |
| 688 | + } |
| 689 | + sampling_context.update(custom_sampling_context) |
| 690 | + transaction._set_initial_sampling_decision(sampling_context=sampling_context) |
| 691 | + |
| 692 | + profile = Profile(transaction, hub=hub) |
| 693 | + profile._set_initial_sampling_decision(sampling_context=sampling_context) |
| 694 | + |
| 695 | + # we don't bother to keep spans if we already know we're not going to |
| 696 | + # send the transaction |
| 697 | + if transaction.sampled: |
| 698 | + max_spans = ( |
| 699 | + client and client.options["_experiments"].get("max_spans") |
| 700 | + ) or 1000 |
| 701 | + transaction.init_span_recorder(maxlen=max_spans) |
| 702 | + |
| 703 | + return transaction |
| 704 | + |
| 705 | + def start_span(self, span=None, instrumenter=INSTRUMENTER.SENTRY, **kwargs): |
| 706 | + # type: (Optional[Span], str, Any) -> Span |
| 707 | + """ |
| 708 | + Start a span whose parent is the currently active span or transaction, if any. |
| 709 | +
|
| 710 | + The return value is a :py:class:`sentry_sdk.tracing.Span` instance, |
| 711 | + typically used as a context manager to start and stop timing in a `with` |
| 712 | + block. |
| 713 | +
|
| 714 | + Only spans contained in a transaction are sent to Sentry. Most |
| 715 | + integrations start a transaction at the appropriate time, for example |
| 716 | + for every incoming HTTP request. Use |
| 717 | + :py:meth:`sentry_sdk.start_transaction` to start a new transaction when |
| 718 | + one is not already in progress. |
| 719 | +
|
| 720 | + For supported `**kwargs` see :py:class:`sentry_sdk.tracing.Span`. |
| 721 | + """ |
| 722 | + client = kwargs.get("client", None) |
| 723 | + |
| 724 | + configuration_instrumenter = client and client.options["instrumenter"] |
| 725 | + |
| 726 | + if instrumenter != configuration_instrumenter: |
| 727 | + return NoOpSpan() |
| 728 | + |
| 729 | + # THIS BLOCK IS DEPRECATED |
| 730 | + # TODO: consider removing this in a future release. |
| 731 | + # This is for backwards compatibility with releases before |
| 732 | + # start_transaction existed, to allow for a smoother transition. |
| 733 | + if isinstance(span, Transaction) or "transaction" in kwargs: |
| 734 | + deprecation_msg = ( |
| 735 | + "Deprecated: use start_transaction to start transactions and " |
| 736 | + "Transaction.start_child to start spans." |
| 737 | + ) |
| 738 | + |
| 739 | + if isinstance(span, Transaction): |
| 740 | + logger.warning(deprecation_msg) |
| 741 | + return self.start_transaction(span, **kwargs) |
| 742 | + |
| 743 | + if "transaction" in kwargs: |
| 744 | + logger.warning(deprecation_msg) |
| 745 | + name = kwargs.pop("transaction") |
| 746 | + return self.start_transaction(name=name, **kwargs) |
| 747 | + |
| 748 | + # THIS BLOCK IS DEPRECATED |
| 749 | + # We do not pass a span into start_span in our code base, so I deprecate this. |
| 750 | + if span is not None: |
| 751 | + deprecation_msg = "Deprecated: passing a span into `start_span` is deprecated and will be removed in the future." |
| 752 | + logger.warning(deprecation_msg) |
| 753 | + return span |
| 754 | + |
| 755 | + kwargs.pop("client") |
| 756 | + |
| 757 | + active_span = self.span |
| 758 | + if active_span is not None: |
| 759 | + new_child_span = active_span.start_child(**kwargs) |
| 760 | + return new_child_span |
| 761 | + |
| 762 | + # If there is already a trace_id in the propagation context, use it. |
| 763 | + # This does not need to be done for `start_child` above because it takes |
| 764 | + # the trace_id from the parent span. |
| 765 | + if "trace_id" not in kwargs: |
| 766 | + traceparent = self.get_traceparent() |
| 767 | + trace_id = traceparent.split("-")[0] if traceparent else None |
| 768 | + if trace_id is not None: |
| 769 | + kwargs["trace_id"] = trace_id |
| 770 | + |
| 771 | + return Span(**kwargs) |
| 772 | + |
| 773 | + def continue_trace(self, environ_or_headers, op=None, name=None, source=None): |
| 774 | + # type: (Dict[str, Any], Optional[str], Optional[str], Optional[str]) -> Transaction |
| 775 | + """ |
| 776 | + Sets the propagation context from environment or headers and returns a transaction. |
| 777 | + """ |
| 778 | + self.generate_propagation_context(environ_or_headers) |
| 779 | + |
| 780 | + transaction = Transaction.continue_from_headers( |
| 781 | + normalize_incoming_data(environ_or_headers), |
| 782 | + op=op, |
| 783 | + name=name, |
| 784 | + source=source, |
| 785 | + ) |
| 786 | + |
| 787 | + return transaction |
| 788 | + |
639 | 789 | def start_session(self, *args, **kwargs):
|
640 | 790 | # type: (*Any, **Any) -> None
|
641 | 791 | """Starts a new session."""
|
|
0 commit comments