Skip to content

Commit ea7f625

Browse files
ufootEmanuele Palazzetti
authored andcommitted
[dual sampling] support -1 as a priority sampling value (#391)
* [dual sampling] updated tests to make sure -1 and 2 are handled * [dual sampling] updated doc to mention rules about -1 and 2 sampling priority values * [dual sampling] introduced constants for sampling priorities
1 parent 62be630 commit ea7f625

File tree

5 files changed

+80
-27
lines changed

5 files changed

+80
-27
lines changed

ddtrace/ext/priority.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
"""
2+
Priority is a hint given to the backend so that it knows which traces to reject or kept.
3+
In a distributed context, it should be set before any context propagation (fork, RPC calls) to be effective.
4+
5+
For example:
6+
7+
from ddtrace.ext.priority import USER_REJECT, USER_KEEP
8+
9+
context = tracer.context_provider.active()
10+
# Indicate to not keep the trace
11+
context.sampling_priority = USER_REJECT
12+
13+
# Indicate to keep the trace
14+
span.context.sampling_priority = USER_KEEP
15+
"""
16+
17+
# Use this to explicitely inform the backend that a trace should be rejected and not stored.
18+
USER_REJECT = -1
19+
# Used by the builtin sampler to inform the backend that a trace should be rejected and not stored.
20+
AUTO_REJECT = 0
21+
# Used by the builtin sampler to inform the backend that a trace should be kept and stored.
22+
AUTO_KEEP = 1
23+
# Use this to explicitely inform the backend that a trace should be kept and stored.
24+
USER_KEEP = 2

ddtrace/tracer.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from .span import Span
1111
from .constants import FILTERS_KEY, SAMPLE_RATE_METRIC_KEY
1212
from . import compat
13+
from .ext.priority import AUTO_REJECT, AUTO_KEEP
1314

1415

1516
log = logging.getLogger(__name__)
@@ -219,9 +220,9 @@ def start_span(self, name, child_of=None, service=None, resource=None, span_type
219220
# priority sampler will use the default sampling rate, which might
220221
# lead to oversampling (that is, dropping too many traces).
221222
if self.priority_sampler.sample(span):
222-
context.sampling_priority = 1
223+
context.sampling_priority = AUTO_KEEP
223224
else:
224-
context.sampling_priority = 0
225+
context.sampling_priority = AUTO_REJECT
225226
else:
226227
if self.priority_sampler:
227228
# If dropped by the local sampler, distributed instrumentation can drop it too.

docs/index.rst

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -358,9 +358,10 @@ Priority sampling
358358
Priority sampling consists in deciding if a trace will be kept by using a `priority` attribute that will be propagated
359359
for distributed traces. Its value gives indication to the Agent and to the backend on how important the trace is.
360360

361-
- 0: Don't keep the trace.
362-
- 1: The sampler automatically decided to keep the trace.
363-
- 2: The user asked the keep the trace.
361+
The sampler can set the priority to the following values::
362+
363+
- `AUTO_REJECT`: the sampler automatically decided to reject the trace
364+
- `AUTO_KEEP`: the sampler automatically decided to keep the trace
364365

365366
For now, priority sampling is disabled by default. Enabling it ensures that your sampled distributed traces will be complete.
366367
To enable the priority sampling::
@@ -370,15 +371,29 @@ To enable the priority sampling::
370371
Once enabled, the sampler will automatically assign a priority of 0 or 1 to traces, depending on their service and volume.
371372

372373
You can also set this priority manually to either drop a non-interesting trace or to keep an important one.
373-
For that, set the `context.sampling_priority` to 0 or 2. It has to be done before any context propagation (fork, RPC calls)
374-
to be effective::
374+
For that, set the `context.sampling_priority` to -1 or 2.
375+
376+
- `USER_REJECT`: the user asked to reject the trace
377+
- `USER_KEEP`: the user asked to keep the trace
378+
379+
When not using distributed tracing, you may change the priority at any time,
380+
as long as the trace is not finished yet.
381+
But it has to be done before any context propagation (fork, RPC calls) to be effective in a distributed context.
382+
Changing the priority after context has been propagated causes different parts of a distributed trace
383+
to use different priorities. Some parts might be kept, some parts might be rejected,
384+
and this can cause the trace to be partially stored and remain incomplete.
385+
386+
If you change the priority, we recommend you do it as soon as possible, when the root span has just been created.
387+
388+
389+
from ddtrace.ext.priority import USER_REJECT, USER_KEEP
375390

376391
context = tracer.context_provider.active()
377392
# Indicate to not keep the trace
378-
context.sampling_priority = 0
393+
context.sampling_priority = USER_REJECT
379394

380395
# Indicate to keep the trace
381-
span.context.sampling_priority = 2
396+
span.context.sampling_priority = USER_KEEP
382397

383398

384399
Pre-sampling
@@ -586,4 +601,3 @@ Indices and tables
586601
* :ref:`genindex`
587602
* :ref:`modindex`
588603
* :ref:`search`
589-

tests/test_context.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
from ddtrace.span import Span
99
from ddtrace.context import Context, ThreadLocalContext
10+
from ddtrace.ext.priority import USER_REJECT, AUTO_REJECT, AUTO_KEEP, USER_KEEP
1011

1112

1213
class TestTracingContext(TestCase):
@@ -31,6 +32,20 @@ def test_context_sampled(self):
3132
ok_(ctx._sampled is True)
3233
ok_(ctx.sampling_priority is None)
3334

35+
def test_context_priority(self):
36+
# a context is sampled if the spans are sampled
37+
ctx = Context()
38+
for priority in [USER_REJECT, AUTO_REJECT, AUTO_KEEP, USER_KEEP, None, 999]:
39+
ctx.sampling_priority = priority
40+
span = Span(tracer=None, name=('fake_span_%s' % repr(priority)))
41+
ctx.add_span(span)
42+
# It's "normal" to have sampled be true even when priority sampling is
43+
# set to 0 or -1. It would stay false even even with priority set to 2.
44+
# The only criteria to send (or not) the spans to the agent should be
45+
# this "sampled" attribute, as it's tightly related to the trace weight.
46+
ok_(ctx._sampled is True, 'priority has no impact on sampled status')
47+
eq_(priority, ctx.sampling_priority)
48+
3449
def test_current_span(self):
3550
# it should return the current active span
3651
ctx = Context()

tests/test_span.py

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -216,23 +216,22 @@ def test_span_boolean_err():
216216
eq_(d["error"], 1)
217217
eq_(type(d["error"]), int)
218218

219-
def test_span_to_dict_priority():
220-
for i in range(10):
221-
s = Span(tracer=None, name="test.span", service="s", resource="r")
222-
s.span_type = "foo"
223-
s.set_tag("a", "1")
224-
s.set_meta("b", "2")
225-
s.finish()
226-
227-
d = s.to_dict()
228-
assert d
229-
eq_(d["span_id"], s.span_id)
230-
eq_(d["trace_id"], s.trace_id)
231-
eq_(d["parent_id"], s.parent_id)
232-
eq_(d["meta"], {"a": "1", "b": "2"})
233-
eq_(d["type"], "foo")
234-
eq_(d["error"], 0)
235-
eq_(type(d["error"]), int)
219+
def test_span_to_dict():
220+
s = Span(tracer=None, name="test.span", service="s", resource="r")
221+
s.span_type = "foo"
222+
s.set_tag("a", "1")
223+
s.set_meta("b", "2")
224+
s.finish()
225+
226+
d = s.to_dict()
227+
assert d
228+
eq_(d["span_id"], s.span_id)
229+
eq_(d["trace_id"], s.trace_id)
230+
eq_(d["parent_id"], s.parent_id)
231+
eq_(d["meta"], {"a": "1", "b": "2"})
232+
eq_(d["type"], "foo")
233+
eq_(d["error"], 0)
234+
eq_(type(d["error"]), int)
236235

237236
class DummyTracer(object):
238237
def __init__(self):

0 commit comments

Comments
 (0)