1# Copyright 2017, OpenCensus Authors 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15 16DEFAULT_SAMPLING_RATE = 1e-4 17 18 19class Sampler(object): 20 """Base class for opencensus trace request samplers. 21 22 Subclasses must override :meth:`should_sample`. 23 """ 24 25 def should_sample(self, span_context): 26 """Whether to sample this request. 27 28 :type span_context: :class:`opencensus.trace.span_context.SpanContext` 29 :param span_context: The span context. 30 31 :rtype: bool 32 :returns: Whether to sample the request according to the context. 33 """ 34 raise NotImplementedError 35 36 37class AlwaysOnSampler(Sampler): 38 """Sampler that samples every request, regardless of trace options.""" 39 40 def should_sample(self, span_context): 41 return True 42 43 44class AlwaysOffSampler(Sampler): 45 """Sampler that doesn't sample any request, regardless of trace options.""" 46 47 def should_sample(self, span_context): 48 return False 49 50 51class ProbabilitySampler(Sampler): 52 """Sample a request at a fixed rate. 53 54 :type rate: float 55 :param rate: The rate of sampling. 56 """ 57 def __init__(self, rate=None): 58 if rate is None: 59 rate = DEFAULT_SAMPLING_RATE 60 61 if not 0 <= rate <= 1: 62 raise ValueError('Rate must between 0 and 1.') 63 64 self.rate = rate 65 66 def should_sample(self, span_context): 67 """Make the sampling decision based on the lower 8 bytes of the trace 68 ID. If the value is less than the bound, return True, else False. 69 70 :type span_context: :class:`opencensus.trace.span_context.SpanContext` 71 :param span_context: The span context. 72 73 :rtype: bool 74 :returns: Whether to sample the request according to the context. 75 """ 76 if span_context.trace_options.get_enabled(): 77 return True 78 79 lower_long = get_lower_long_from_trace_id(span_context.trace_id) 80 bound = self.rate * 0xffffffffffffffff 81 return lower_long <= bound 82 83 84def get_lower_long_from_trace_id(trace_id): 85 """Returns the lower 8 bytes of the trace ID as a long value, assuming 86 little endian order. 87 88 :rtype: long 89 :returns: Lower 8 bytes of trace ID 90 """ 91 lower_bytes = trace_id[16:] 92 lower_long = int(lower_bytes, 16) 93 94 return lower_long 95