Class: Datadog::Tracing::Sampling::RuleSampler

Inherits:
Object
  • Object
show all
Defined in:
lib/datadog/tracing/sampling/rule_sampler.rb

Overview

Span Sampler that applies a set of Rules to decide on sampling outcome. Then, a rate limiter is applied.

If a trace does not conform to any rules, a default sampling strategy is applied.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(rules = [], rate_limit: Datadog.configuration.tracing.sampling.rate_limit, rate_limiter: nil, default_sample_rate: Datadog.configuration.tracing.sampling.default_rate, default_sampler: nil) ⇒ RuleSampler

Returns a new instance of RuleSampler.

Parameters:

  • rules (Array<Rule>) (defaults to: [])

    ordered list of rules to be applied to a trace

  • rate_limit (Float) (defaults to: Datadog.configuration.tracing.sampling.rate_limit)

    number of traces per second, defaults to +100+

  • rate_limiter (RateLimiter) (defaults to: nil)

    limiter applied after rule matching

  • default_sample_rate (Float) (defaults to: Datadog.configuration.tracing.sampling.default_rate)

    fallback sample rate when no rules apply to a trace, between +[0,1]+, defaults to +1+

  • default_sampler (Sample) (defaults to: nil)

    fallback strategy when no rules apply to a trace



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
# File 'lib/datadog/tracing/sampling/rule_sampler.rb', line 23

def initialize(
  rules = [],
  rate_limit: Datadog.configuration.tracing.sampling.rate_limit,
  rate_limiter: nil,
  default_sample_rate: Datadog.configuration.tracing.sampling.default_rate,
  default_sampler: nil
)
  @rules = rules
  @rate_limiter = if rate_limiter
                    rate_limiter
                  elsif rate_limit
                    TokenBucket.new(rate_limit)
                  else
                    UnlimitedLimiter.new
                  end

  @default_sampler = if default_sampler
                       default_sampler
                     elsif default_sample_rate
                       # Add to the end of the rule list a rule always matches any trace
                       @rules << SimpleRule.new(sample_rate: default_sample_rate)
                       nil
                     else
                       # TODO: Simplify .tags access, as `Tracer#tags` can't be arbitrarily changed anymore
                       RateByServiceSampler.new(1.0, env: -> { Tracing.send(:tracer).tags['env'] })
                     end
end

Instance Attribute Details

#default_samplerObject (readonly)

Returns the value of attribute default_sampler.



15
16
17
# File 'lib/datadog/tracing/sampling/rule_sampler.rb', line 15

def default_sampler
  @default_sampler
end

#rate_limiterObject (readonly)

Returns the value of attribute rate_limiter.



15
16
17
# File 'lib/datadog/tracing/sampling/rule_sampler.rb', line 15

def rate_limiter
  @rate_limiter
end

#rulesObject (readonly)

Returns the value of attribute rules.



15
16
17
# File 'lib/datadog/tracing/sampling/rule_sampler.rb', line 15

def rules
  @rules
end

Class Method Details

.parse(rules, rate_limit, default_sample_rate) ⇒ Object



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
# File 'lib/datadog/tracing/sampling/rule_sampler.rb', line 51

def self.parse(rules, rate_limit, default_sample_rate)
  parsed_rules = JSON.parse(rules).map do |rule|
    sample_rate = rule['sample_rate']

    begin
      sample_rate = Float(sample_rate)
    rescue
      raise "Rule '#{rule.inspect}' does not contain a float property `sample_rate`"
    end

    kwargs = {
      name: rule['name'],
      service: rule['service'],
      sample_rate: sample_rate,
    }

    Core::BackportFrom24.hash_compact!(kwargs)

    SimpleRule.new(**kwargs)
  end

  new(parsed_rules, rate_limit: rate_limit, default_sample_rate: default_sample_rate)
rescue => e
  Datadog.logger.error do
    "Could not parse trace sampling rules '#{rules}': #{e.class.name} #{e.message} at #{Array(e.backtrace).first}"
  end
  nil
end

Instance Method Details

#sample!(trace) ⇒ Object



90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/datadog/tracing/sampling/rule_sampler.rb', line 90

def sample!(trace)
  sampled = sample_trace(trace) do |t|
    @default_sampler.sample!(t).tap do
      # We want to make sure the trace is tagged with the agent-derived
      # service rate. Retrieve this from the rate by service sampler.
      # Only do this if it was set by a RateByServiceSampler.
      trace.agent_sample_rate = @default_sampler.sample_rate(trace) if @default_sampler.is_a?(RateByServiceSampler)
    end
  end

  trace.sampled = sampled
end

#sample?(_trace) ⇒ Object

/RuleSampler's components (it's rate limiter, for example) are not be guaranteed to be size-effect free. It is not possible to guarantee that a call to #sample? will return the same result as a successive call to #sample! with the same trace.

Use #sample! instead



86
87
88
# File 'lib/datadog/tracing/sampling/rule_sampler.rb', line 86

def sample?(_trace)
  raise 'RuleSampler cannot be evaluated without side-effects'
end