Skip to content

Commit 7fc6911

Browse files
committed
ref: Add experiment to generate span IDs without UUID
1 parent 5daed20 commit 7fc6911

4 files changed

Lines changed: 37 additions & 6 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ venv
1919
.vscode/tags
2020
.pytest_cache
2121
.hypothesis
22+
.benchmarks
2223
relay
2324
pip-wheel-metadata
2425
.mypy_cache

sentry_sdk/hub.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -506,12 +506,14 @@ def start_transaction(
506506
When the transaction is finished, it will be sent to Sentry with all its
507507
finished child spans.
508508
"""
509+
510+
client, scope = self._stack[-1]
511+
509512
if transaction is None:
510513
kwargs.setdefault("hub", self)
514+
kwargs['_fast_span_ids'] = client and client.options['_experiments'].get("fast_span_ids")
511515
transaction = Transaction(**kwargs)
512516

513-
client, scope = self._stack[-1]
514-
515517
if transaction.sampled is None:
516518
sample_rate = client and client.options["traces_sample_rate"] or 0
517519
transaction.sampled = random.random() < sample_rate

sentry_sdk/tracing.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
import uuid
33
import contextlib
44
import time
5+
import itertools
6+
import platform
57

68
from datetime import datetime, timedelta
79

@@ -25,6 +27,7 @@
2527
from typing import Dict
2628
from typing import List
2729
from typing import Tuple
30+
from typing import Iterator
2831

2932
_traceparent_header_format_re = re.compile(
3033
"^[ \t]*" # whitespace
@@ -34,6 +37,8 @@
3437
"[ \t]*$" # whitespace
3538
)
3639

40+
_ITERTOOLS_COUNT_IS_ATOMIC = platform.python_implementation() in ("CPython", "PyPy")
41+
3742

3843
class EnvironHeaders(Mapping): # type: ignore
3944
def __init__(
@@ -107,6 +112,7 @@ class Span(object):
107112
"_span_recorder",
108113
"hub",
109114
"_context_manager_state",
115+
"_span_id_generator",
110116
)
111117

112118
def __new__(cls, **kwargs):
@@ -130,10 +136,20 @@ def __init__(
130136
hub=None, # type: Optional[sentry_sdk.Hub]
131137
status=None, # type: Optional[str]
132138
transaction=None, # type: Optional[str] # deprecated
139+
_span_id_generator=None, # type: Optional[Iterator[str]]
133140
):
134141
# type: (...) -> None
135142
self.trace_id = trace_id or uuid.uuid4().hex
136-
self.span_id = span_id or uuid.uuid4().hex[16:]
143+
144+
if not span_id and _span_id_generator:
145+
span_id = next(_span_id_generator)
146+
147+
if not span_id:
148+
span_id = uuid.uuid4().hex[16:]
149+
150+
self.span_id = span_id
151+
self._span_id_generator = _span_id_generator
152+
137153
self.parent_span_id = parent_span_id
138154
self.same_process_as_parent = same_process_as_parent
139155
self.sampled = sampled
@@ -206,7 +222,9 @@ def start_child(self, **kwargs):
206222
kwargs.setdefault("sampled", self.sampled)
207223

208224
rv = Span(
209-
trace_id=self.trace_id, span_id=None, parent_span_id=self.span_id, **kwargs
225+
trace_id=self.trace_id, span_id=None, parent_span_id=self.span_id,
226+
_span_id_generator=self._span_id_generator,
227+
**kwargs
210228
)
211229

212230
rv._span_recorder = recorder = self._span_recorder
@@ -435,6 +453,15 @@ def __init__(
435453
"instead of Span(transaction=...)."
436454
)
437455
name = kwargs.pop("transaction")
456+
457+
if "_span_id_generator" in kwargs:
458+
raise TypeError("Argument _span_id_generator can only be provided to Spans")
459+
460+
# next() on itertools.count() is a way to get-and-increment an integer
461+
# "atomically" on Python runtimes with a GIL
462+
if _ITERTOOLS_COUNT_IS_ATOMIC and kwargs.pop("_fast_span_ids", None):
463+
kwargs['_span_id_generator'] = ("{:016x}".format(i) for i in itertools.count())
464+
438465
Span.__init__(self, **kwargs)
439466
self.name = name
440467

tests/test_tracing.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@
1515

1616
@pytest.mark.parametrize("sample_rate", [0.0, 1.0])
1717
@pytest.mark.parametrize("num_spans", [1, 900])
18-
def test_basic(sentry_init, capture_events, sample_rate, num_spans, benchmark):
19-
sentry_init(traces_sample_rate=sample_rate)
18+
@pytest.mark.parametrize("fast_span_ids", [True, False])
19+
def test_basic(sentry_init, capture_events, sample_rate, num_spans, benchmark, fast_span_ids):
20+
sentry_init(traces_sample_rate=sample_rate, _experiments={"fast_span_ids": fast_span_ids})
2021
events = capture_events()
2122

2223
@benchmark

0 commit comments

Comments
 (0)