forked from DataDog/dd-trace-py
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsampler.py
100 lines (70 loc) · 3.03 KB
/
sampler.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
"""Samplers manage the client-side trace sampling
Any `sampled = False` trace won't be written, and can be ignored by the instrumentation.
"""
import logging
from threading import Lock
from .compat import iteritems
log = logging.getLogger(__name__)
MAX_TRACE_ID = 2 ** 64
# Has to be the same factor and key as the Agent to allow chained sampling
KNUTH_FACTOR = 1111111111111111111
class AllSampler(object):
"""Sampler sampling all the traces"""
def sample(self, span):
return True
class RateSampler(object):
"""Sampler based on a rate
Keep (100 * `sample_rate`)% of the traces.
It samples randomly, its main purpose is to reduce the instrumentation footprint.
"""
def __init__(self, sample_rate=1):
if sample_rate <= 0:
log.error("sample_rate is negative or null, disable the Sampler")
sample_rate = 1
elif sample_rate > 1:
sample_rate = 1
self.set_sample_rate(sample_rate)
log.info("initialized RateSampler, sample %s%% of traces", 100 * sample_rate)
def set_sample_rate(self, sample_rate):
self.sample_rate = sample_rate
self.sampling_id_threshold = sample_rate * MAX_TRACE_ID
def sample(self, span):
sampled = ((span.trace_id * KNUTH_FACTOR) % MAX_TRACE_ID) <= self.sampling_id_threshold
return sampled
def _key(service=None, env=None):
service = service or ""
env = env or ""
return "service:" + service + ",env:" + env
_default_key = _key()
class RateByServiceSampler(object):
"""Sampler based on a rate, by service
Keep (100 * `sample_rate`)% of the traces.
The sample rate is kept independently for each service/env tuple.
"""
def __init__(self, sample_rate=1):
self._lock = Lock()
self._by_service_samplers = {}
self._by_service_samplers[_default_key] = RateSampler(sample_rate)
def _set_sample_rate_by_key(self, sample_rate, key):
with self._lock:
if key in self._by_service_samplers:
self._by_service_samplers[key].set_sample_rate(sample_rate)
else:
self._by_service_samplers[key] = RateSampler(sample_rate)
def set_sample_rate(self, sample_rate, service="", env=""):
self._set_sample_rate_by_key(sample_rate, _key(service, env))
def sample(self, span):
tags = span.tracer().tags
env = tags['env'] if 'env' in tags else None
key = _key(span.service, env)
with self._lock:
if key in self._by_service_samplers:
return self._by_service_samplers[key].sample(span)
return self._by_service_samplers[_default_key].sample(span)
def set_sample_rate_by_service(self, rate_by_service):
for key, sample_rate in iteritems(rate_by_service):
self._set_sample_rate_by_key(sample_rate, key)
with self._lock:
for key in list(self._by_service_samplers):
if key not in rate_by_service and key != _default_key:
del self._by_service_samplers[key]