Skip to content

Commit d31e805

Browse files
fix: Use monotonic clock to compute durations (getsentry#631)
* fix: Use monotonic clock to compute durations In summary, care must be taken when computing durations. Monotonic clocks are not subject to system clock adjustments or system clock skew. The difference between any two chronologically recorded time values is guaranteed to never be negative. The same guarantee above does not exist for the difference between two calls to datetime.now() and friends. More details and rationale see PEP 418. Resources: PEP 418 -- Add monotonic time, performance counter, and process time functions https://www.python.org/dev/peps/pep-0418/ PEP 564 -- Add new time functions with nanosecond resolution https://www.python.org/dev/peps/pep-0564/ * fix: Remove camelCasing Co-authored-by: Markus Unterwaditzer <markus@unterwaditzer.net>
1 parent e1ce025 commit d31e805

File tree

1 file changed

+16
-2
lines changed

1 file changed

+16
-2
lines changed

sentry_sdk/tracing.py

+16-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import re
22
import uuid
33
import contextlib
4+
import time
45

5-
from datetime import datetime
6+
from datetime import datetime, timedelta
67

78
import sentry_sdk
89

@@ -101,6 +102,7 @@ class Span(object):
101102
"op",
102103
"description",
103104
"start_timestamp",
105+
"_start_timestamp_monotonic",
104106
"timestamp",
105107
"_tags",
106108
"_data",
@@ -134,6 +136,14 @@ def __init__(
134136
self._tags = {} # type: Dict[str, str]
135137
self._data = {} # type: Dict[str, Any]
136138
self.start_timestamp = datetime.utcnow()
139+
try:
140+
# TODO: For Python 3.7+, we could use a clock with ns resolution:
141+
# self._start_timestamp_monotonic = time.perf_counter_ns()
142+
143+
# Python 3.3+
144+
self._start_timestamp_monotonic = time.perf_counter()
145+
except AttributeError:
146+
pass
137147

138148
#: End timestamp of span
139149
self.timestamp = None # type: Optional[datetime]
@@ -309,7 +319,11 @@ def finish(self, hub=None):
309319
# This transaction is already finished, so we should not flush it again.
310320
return None
311321

312-
self.timestamp = datetime.utcnow()
322+
try:
323+
duration_seconds = time.perf_counter() - self._start_timestamp_monotonic
324+
self.timestamp = self.start_timestamp + timedelta(seconds=duration_seconds)
325+
except AttributeError:
326+
self.timestamp = datetime.utcnow()
313327

314328
_maybe_create_breadcrumbs_from_span(hub, self)
315329

0 commit comments

Comments
 (0)