diff --git a/sentry_sdk/tracing.py b/sentry_sdk/tracing.py index 5b9fbdfd0d..94c5837e43 100644 --- a/sentry_sdk/tracing.py +++ b/sentry_sdk/tracing.py @@ -126,6 +126,7 @@ def __init__( status=None, # type: Optional[str] transaction=None, # type: Optional[str] # deprecated containing_transaction=None, # type: Optional[Transaction] + start_timestamp=None, # type: Optional[datetime] instrumenter=None, # type: Optional[str] ): # type: (...) -> None @@ -141,7 +142,7 @@ def __init__( self._tags = {} # type: Dict[str, str] self._data = {} # type: Dict[str, Any] self._containing_transaction = containing_transaction - self.start_timestamp = datetime.utcnow() + self.start_timestamp = start_timestamp or datetime.utcnow() try: # TODO: For Python 3.7+, we could use a clock with ns resolution: # self._start_timestamp_monotonic = time.perf_counter_ns() @@ -472,8 +473,8 @@ def is_success(self): # type: () -> bool return self.status == "ok" - def finish(self, hub=None): - # type: (Optional[sentry_sdk.Hub]) -> Optional[str] + 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 # to incompatible return types for Span.finish and Transaction.finish. if self.timestamp is not None: @@ -483,8 +484,13 @@ def finish(self, hub=None): hub = hub or self.hub or sentry_sdk.Hub.current try: - duration_seconds = time.perf_counter() - self._start_timestamp_monotonic - self.timestamp = self.start_timestamp + timedelta(seconds=duration_seconds) + if end_timestamp: + self.timestamp = end_timestamp + else: + duration_seconds = time.perf_counter() - self._start_timestamp_monotonic + self.timestamp = self.start_timestamp + timedelta( + seconds=duration_seconds + ) except AttributeError: self.timestamp = datetime.utcnow() @@ -630,8 +636,8 @@ def containing_transaction(self): # reference. return self - def finish(self, hub=None): - # type: (Optional[sentry_sdk.Hub]) -> Optional[str] + def finish(self, hub=None, end_timestamp=None): + # type: (Optional[sentry_sdk.Hub], Optional[datetime]) -> Optional[str] if self.timestamp is not None: # This transaction is already finished, ignore. return None @@ -663,7 +669,7 @@ def finish(self, hub=None): ) self.name = "" - Span.finish(self, hub) + Span.finish(self, hub, end_timestamp) if not self.sampled: # At this point a `sampled = None` should have already been resolved @@ -876,8 +882,8 @@ def set_http_status(self, http_status): # type: (Any) -> Any pass - def finish(self, hub=None, **kwargs): - # type: (Any, **Any) -> Any + def finish(self, hub=None, end_timestamp=None): + # type: (Any, Any) -> Any pass