ddtrace 0.29.1 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.rubocop.yml +4 -0
- data/CHANGELOG.md +18 -1
- data/lib/ddtrace/context.rb +26 -10
- data/lib/ddtrace/contrib/action_pack/action_controller/patcher.rb +3 -15
- data/lib/ddtrace/contrib/action_pack/patcher.rb +3 -9
- data/lib/ddtrace/contrib/action_view/event.rb +39 -0
- data/lib/ddtrace/contrib/action_view/events.rb +30 -0
- data/lib/ddtrace/contrib/action_view/events/render_partial.rb +40 -0
- data/lib/ddtrace/contrib/action_view/events/render_template.rb +43 -0
- data/lib/ddtrace/contrib/action_view/instrumentation/partial_renderer.rb +4 -12
- data/lib/ddtrace/contrib/action_view/instrumentation/template_renderer.rb +6 -14
- data/lib/ddtrace/contrib/action_view/patcher.rb +19 -25
- data/lib/ddtrace/contrib/active_model_serializers/patcher.rb +3 -10
- data/lib/ddtrace/contrib/active_record/patcher.rb +3 -9
- data/lib/ddtrace/contrib/active_support/cache/patcher.rb +10 -24
- data/lib/ddtrace/contrib/active_support/patcher.rb +3 -9
- data/lib/ddtrace/contrib/aws/patcher.rb +7 -13
- data/lib/ddtrace/contrib/concurrent_ruby/patcher.rb +4 -11
- data/lib/ddtrace/contrib/dalli/patcher.rb +4 -10
- data/lib/ddtrace/contrib/delayed_job/patcher.rb +4 -10
- data/lib/ddtrace/contrib/elasticsearch/patcher.rb +8 -14
- data/lib/ddtrace/contrib/ethon/patcher.rb +7 -9
- data/lib/ddtrace/contrib/excon/patcher.rb +4 -11
- data/lib/ddtrace/contrib/faraday/patcher.rb +6 -12
- data/lib/ddtrace/contrib/grape/patcher.rb +7 -13
- data/lib/ddtrace/contrib/graphql/patcher.rb +5 -11
- data/lib/ddtrace/contrib/grpc/patcher.rb +7 -13
- data/lib/ddtrace/contrib/http/patcher.rb +3 -9
- data/lib/ddtrace/contrib/mongodb/patcher.rb +5 -11
- data/lib/ddtrace/contrib/mysql2/patcher.rb +3 -9
- data/lib/ddtrace/contrib/patcher.rb +38 -10
- data/lib/ddtrace/contrib/racecar/patcher.rb +4 -10
- data/lib/ddtrace/contrib/rack/patcher.rb +56 -21
- data/lib/ddtrace/contrib/rails/patcher.rb +4 -8
- data/lib/ddtrace/contrib/rake/patcher.rb +4 -10
- data/lib/ddtrace/contrib/redis/patcher.rb +8 -14
- data/lib/ddtrace/contrib/resque/patcher.rb +4 -10
- data/lib/ddtrace/contrib/rest_client/patcher.rb +5 -7
- data/lib/ddtrace/contrib/sequel/patcher.rb +4 -10
- data/lib/ddtrace/contrib/shoryuken/patcher.rb +4 -10
- data/lib/ddtrace/contrib/sidekiq/patcher.rb +12 -18
- data/lib/ddtrace/contrib/sinatra/patcher.rb +4 -10
- data/lib/ddtrace/contrib/sucker_punch/patcher.rb +7 -13
- data/lib/ddtrace/diagnostics/health.rb +9 -2
- data/lib/ddtrace/ext/diagnostics.rb +6 -0
- data/lib/ddtrace/ext/sampling.rb +13 -0
- data/lib/ddtrace/sampler.rb +49 -8
- data/lib/ddtrace/sampling.rb +2 -0
- data/lib/ddtrace/sampling/matcher.rb +57 -0
- data/lib/ddtrace/sampling/rate_limiter.rb +127 -0
- data/lib/ddtrace/sampling/rule.rb +61 -0
- data/lib/ddtrace/sampling/rule_sampler.rb +111 -0
- data/lib/ddtrace/span.rb +12 -0
- data/lib/ddtrace/tracer.rb +1 -0
- data/lib/ddtrace/version.rb +2 -2
- metadata +27 -4
@@ -9,19 +9,13 @@ module Datadog
|
|
9
9
|
|
10
10
|
module_function
|
11
11
|
|
12
|
-
def
|
13
|
-
|
12
|
+
def target_version
|
13
|
+
Integration.version
|
14
14
|
end
|
15
15
|
|
16
16
|
def patch
|
17
|
-
|
18
|
-
|
19
|
-
require 'ddtrace/contrib/sinatra/tracer'
|
20
|
-
register_tracer
|
21
|
-
rescue StandardError => e
|
22
|
-
Datadog::Tracer.log.error("Unable to apply Sinatra integration: #{e}")
|
23
|
-
end
|
24
|
-
end
|
17
|
+
require 'ddtrace/contrib/sinatra/tracer'
|
18
|
+
register_tracer
|
25
19
|
end
|
26
20
|
|
27
21
|
def register_tracer
|
@@ -11,23 +11,17 @@ module Datadog
|
|
11
11
|
|
12
12
|
module_function
|
13
13
|
|
14
|
-
def
|
15
|
-
|
14
|
+
def target_version
|
15
|
+
Integration.version
|
16
16
|
end
|
17
17
|
|
18
18
|
def patch
|
19
|
-
|
20
|
-
|
21
|
-
require 'ddtrace/contrib/sucker_punch/exception_handler'
|
22
|
-
require 'ddtrace/contrib/sucker_punch/instrumentation'
|
19
|
+
require 'ddtrace/contrib/sucker_punch/exception_handler'
|
20
|
+
require 'ddtrace/contrib/sucker_punch/instrumentation'
|
23
21
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
rescue StandardError => e
|
28
|
-
Datadog::Tracer.log.error("Unable to apply SuckerPunch integration: #{e}")
|
29
|
-
end
|
30
|
-
end
|
22
|
+
add_pin!
|
23
|
+
ExceptionHandler.patch!
|
24
|
+
Instrumentation.patch!
|
31
25
|
end
|
32
26
|
|
33
27
|
def add_pin!
|
@@ -10,14 +10,21 @@ module Datadog
|
|
10
10
|
count :api_errors, Ext::Diagnostics::Health::Metrics::METRIC_API_ERRORS
|
11
11
|
count :api_requests, Ext::Diagnostics::Health::Metrics::METRIC_API_REQUESTS
|
12
12
|
count :api_responses, Ext::Diagnostics::Health::Metrics::METRIC_API_RESPONSES
|
13
|
+
count :error_context_overflow, Ext::Diagnostics::Health::Metrics::METRIC_ERROR_CONTEXT_OVERFLOW
|
14
|
+
count :error_instrumentation_patch, Ext::Diagnostics::Health::Metrics::METRIC_ERROR_INSTRUMENTATION_PATCH
|
15
|
+
count :error_span_finish, Ext::Diagnostics::Health::Metrics::METRIC_ERROR_SPAN_FINISH
|
16
|
+
count :error_unfinished_spans, Ext::Diagnostics::Health::Metrics::METRIC_ERROR_UNFINISHED_SPANS
|
17
|
+
count :instrumentation_patched, Ext::Diagnostics::Health::Metrics::METRIC_INSTRUMENTATION_PATCHED
|
13
18
|
count :queue_accepted, Ext::Diagnostics::Health::Metrics::METRIC_QUEUE_ACCEPTED
|
14
19
|
count :queue_accepted_lengths, Ext::Diagnostics::Health::Metrics::METRIC_QUEUE_ACCEPTED_LENGTHS
|
15
20
|
count :queue_dropped, Ext::Diagnostics::Health::Metrics::METRIC_QUEUE_DROPPED
|
21
|
+
count :traces_filtered, Ext::Diagnostics::Health::Metrics::METRIC_TRACES_FILTERED
|
22
|
+
count :writer_cpu_time, Ext::Diagnostics::Health::Metrics::METRIC_WRITER_CPU_TIME
|
23
|
+
|
16
24
|
gauge :queue_length, Ext::Diagnostics::Health::Metrics::METRIC_QUEUE_LENGTH
|
17
25
|
gauge :queue_max_length, Ext::Diagnostics::Health::Metrics::METRIC_QUEUE_MAX_LENGTH
|
18
26
|
gauge :queue_spans, Ext::Diagnostics::Health::Metrics::METRIC_QUEUE_SPANS
|
19
|
-
|
20
|
-
count :writer_cpu_time, Ext::Diagnostics::Health::Metrics::METRIC_WRITER_CPU_TIME
|
27
|
+
gauge :sampling_service_cache_length, Ext::Diagnostics::Health::Metrics::METRIC_SAMPLING_SERVICE_CACHE_LENGTH
|
21
28
|
end
|
22
29
|
|
23
30
|
module_function
|
@@ -10,12 +10,18 @@ module Datadog
|
|
10
10
|
METRIC_API_ERRORS = 'datadog.tracer.api.errors'.freeze
|
11
11
|
METRIC_API_REQUESTS = 'datadog.tracer.api.requests'.freeze
|
12
12
|
METRIC_API_RESPONSES = 'datadog.tracer.api.responses'.freeze
|
13
|
+
METRIC_ERROR_CONTEXT_OVERFLOW = 'datadog.tracer.error.context_overflow'.freeze
|
14
|
+
METRIC_ERROR_INSTRUMENTATION_PATCH = 'datadog.tracer.error.instrumentation_patch'.freeze
|
15
|
+
METRIC_ERROR_SPAN_FINISH = 'datadog.tracer.error.span_finish'.freeze
|
16
|
+
METRIC_ERROR_UNFINISHED_SPANS = 'datadog.tracer.error.unfinished_spans'.freeze
|
17
|
+
METRIC_INSTRUMENTATION_PATCHED = 'datadog.tracer.instrumentation_patched'.freeze
|
13
18
|
METRIC_QUEUE_ACCEPTED = 'datadog.tracer.queue.accepted'.freeze
|
14
19
|
METRIC_QUEUE_ACCEPTED_LENGTHS = 'datadog.tracer.queue.accepted_lengths'.freeze
|
15
20
|
METRIC_QUEUE_DROPPED = 'datadog.tracer.queue.dropped'.freeze
|
16
21
|
METRIC_QUEUE_LENGTH = 'datadog.tracer.queue.length'.freeze
|
17
22
|
METRIC_QUEUE_MAX_LENGTH = 'datadog.tracer.queue.max_length'.freeze
|
18
23
|
METRIC_QUEUE_SPANS = 'datadog.tracer.queue.spans'.freeze
|
24
|
+
METRIC_SAMPLING_SERVICE_CACHE_LENGTH = 'datadog.tracer.sampling.service_cache_length'.freeze
|
19
25
|
METRIC_TRACES_FILTERED = 'datadog.tracer.traces.filtered'.freeze
|
20
26
|
METRIC_WRITER_CPU_TIME = 'datadog.tracer.writer.cpu_time'.freeze
|
21
27
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Datadog
|
2
|
+
module Ext
|
3
|
+
module Sampling
|
4
|
+
# If rule sampling is applied to a span, set this metric the sample rate configured for that rule.
|
5
|
+
# This should be done regardless of sampling outcome.
|
6
|
+
RULE_SAMPLE_RATE = '_dd.rule_psr'.freeze
|
7
|
+
|
8
|
+
# If rate limiting is checked on a span, set this metric the effective rate limiting rate applied.
|
9
|
+
# This should be done regardless of rate limiting outcome.
|
10
|
+
RATE_LIMITER_RATE = '_dd.limit_psr'.freeze
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/ddtrace/sampler.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'forwardable'
|
2
2
|
|
3
3
|
require 'ddtrace/ext/priority'
|
4
|
+
require 'ddtrace/diagnostics/health'
|
4
5
|
|
5
6
|
module Datadog
|
6
7
|
# \Sampler performs client-side trace sampling.
|
@@ -12,6 +13,10 @@ module Datadog
|
|
12
13
|
def sample!(_span)
|
13
14
|
raise NotImplementedError, 'Samplers must implement the #sample! method'
|
14
15
|
end
|
16
|
+
|
17
|
+
def sample_rate(span)
|
18
|
+
raise NotImplementedError, 'Samplers must implement the #sample_rate method'
|
19
|
+
end
|
15
20
|
end
|
16
21
|
|
17
22
|
# \AllSampler samples all the traces.
|
@@ -23,6 +28,10 @@ module Datadog
|
|
23
28
|
def sample!(span)
|
24
29
|
span.sampled = true
|
25
30
|
end
|
31
|
+
|
32
|
+
def sample_rate(*_)
|
33
|
+
1.0
|
34
|
+
end
|
26
35
|
end
|
27
36
|
|
28
37
|
# \RateSampler is based on a sample rate.
|
@@ -30,8 +39,6 @@ module Datadog
|
|
30
39
|
KNUTH_FACTOR = 1111111111111111111
|
31
40
|
SAMPLE_RATE_METRIC_KEY = '_sample_rate'.freeze
|
32
41
|
|
33
|
-
attr_reader :sample_rate
|
34
|
-
|
35
42
|
# Initialize a \RateSampler.
|
36
43
|
# This sampler keeps a random subset of the traces. Its main purpose is to
|
37
44
|
# reduce the instrumentation footprint.
|
@@ -48,6 +55,10 @@ module Datadog
|
|
48
55
|
self.sample_rate = sample_rate
|
49
56
|
end
|
50
57
|
|
58
|
+
def sample_rate(*_)
|
59
|
+
@sample_rate
|
60
|
+
end
|
61
|
+
|
51
62
|
def sample_rate=(sample_rate)
|
52
63
|
@sample_rate = sample_rate
|
53
64
|
@sampling_id_threshold = sample_rate * Span::MAX_ID
|
@@ -136,6 +147,10 @@ module Datadog
|
|
136
147
|
end
|
137
148
|
end
|
138
149
|
|
150
|
+
def length
|
151
|
+
@samplers.length
|
152
|
+
end
|
153
|
+
|
139
154
|
private
|
140
155
|
|
141
156
|
def set_rate(key, rate)
|
@@ -159,6 +174,9 @@ module Datadog
|
|
159
174
|
|
160
175
|
# Update each service rate
|
161
176
|
update_all(rate_by_service)
|
177
|
+
|
178
|
+
# Emit metric for service cache size
|
179
|
+
Diagnostics::Health.metrics.sampling_service_cache_length(length)
|
162
180
|
end
|
163
181
|
|
164
182
|
private
|
@@ -195,10 +213,8 @@ module Datadog
|
|
195
213
|
# If priority sampling has already been applied upstream, use that, otherwise...
|
196
214
|
unless priority_assigned_upstream?(span)
|
197
215
|
# Roll the dice and determine whether how we set the priority.
|
198
|
-
|
199
|
-
|
200
|
-
# agent will have an incomplete dataset.
|
201
|
-
priority = priority_sample(span) ? Datadog::Ext::Priority::AUTO_KEEP : Datadog::Ext::Priority::AUTO_REJECT
|
216
|
+
priority = priority_sample!(span) ? Datadog::Ext::Priority::AUTO_KEEP : Datadog::Ext::Priority::AUTO_REJECT
|
217
|
+
|
202
218
|
assign_priority!(span, priority)
|
203
219
|
end
|
204
220
|
else
|
@@ -229,8 +245,33 @@ module Datadog
|
|
229
245
|
span.context && !span.context.sampling_priority.nil?
|
230
246
|
end
|
231
247
|
|
232
|
-
def priority_sample(span)
|
233
|
-
|
248
|
+
def priority_sample!(span)
|
249
|
+
preserving_sampling(span) do
|
250
|
+
@priority_sampler.sample!(span)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
# Ensures the span is always propagated to the writer and that
|
255
|
+
# the sample rate metric represents the true client-side sampling.
|
256
|
+
def preserving_sampling(span)
|
257
|
+
pre_sample_rate_metric = span.get_metric(SAMPLE_RATE_METRIC_KEY)
|
258
|
+
|
259
|
+
yield.tap do
|
260
|
+
# NOTE: We'll want to leave `span.sampled = true` here; all spans for priority sampling must
|
261
|
+
# be sent to the agent. Otherwise metrics for traces will not be accurate, since the
|
262
|
+
# agent will have an incomplete dataset.
|
263
|
+
#
|
264
|
+
# We also ensure that the agent knows we that our `post_sampler` is not performing true sampling,
|
265
|
+
# to avoid erroneous metric upscaling.
|
266
|
+
span.sampled = true
|
267
|
+
if pre_sample_rate_metric
|
268
|
+
# Restore true sampling metric, as only the @pre_sampler can reject traces
|
269
|
+
span.set_metric(SAMPLE_RATE_METRIC_KEY, pre_sample_rate_metric)
|
270
|
+
else
|
271
|
+
# If @pre_sampler is not enable, sending this metric would be misleading
|
272
|
+
span.clear_metric(SAMPLE_RATE_METRIC_KEY)
|
273
|
+
end
|
274
|
+
end
|
234
275
|
end
|
235
276
|
|
236
277
|
def assign_priority!(span, priority)
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Datadog
|
2
|
+
module Sampling
|
3
|
+
# Checks if a span conforms to a matching criteria.
|
4
|
+
class Matcher
|
5
|
+
# Returns `true` if the span should conforms to this rule, `false` otherwise
|
6
|
+
#
|
7
|
+
# @abstract
|
8
|
+
# @param [Span] span
|
9
|
+
# @return [Boolean]
|
10
|
+
def match?(span)
|
11
|
+
raise NotImplementedError
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# A \Matcher that supports matching a span by
|
16
|
+
# operation name and/or service name.
|
17
|
+
class SimpleMatcher < Matcher
|
18
|
+
# Returns `true` for case equality (===) with any object
|
19
|
+
MATCH_ALL = Class.new do
|
20
|
+
# DEV: A class that implements `#===` is ~20% faster than
|
21
|
+
# DEV: a `Proc` that always returns `true`.
|
22
|
+
def ===(other)
|
23
|
+
true
|
24
|
+
end
|
25
|
+
end.new
|
26
|
+
|
27
|
+
attr_reader :name, :service
|
28
|
+
|
29
|
+
# @param name [String,Regexp,Proc] Matcher for case equality (===) with the span name, defaults to always match
|
30
|
+
# @param service [String,Regexp,Proc] Matcher for case equality (===) with the service name, defaults to always match
|
31
|
+
def initialize(name: MATCH_ALL, service: MATCH_ALL)
|
32
|
+
@name = name
|
33
|
+
@service = service
|
34
|
+
end
|
35
|
+
|
36
|
+
def match?(span)
|
37
|
+
name === span.name && service === span.service
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# A \Matcher that allows for arbitrary span matching
|
42
|
+
# based on the return value of a provided block.
|
43
|
+
class ProcMatcher < Matcher
|
44
|
+
attr_reader :block
|
45
|
+
|
46
|
+
# @yield [name, service] Provides span name and service to the block
|
47
|
+
# @yieldreturn [Boolean] Whether the span conforms to this matcher
|
48
|
+
def initialize(&block)
|
49
|
+
@block = block
|
50
|
+
end
|
51
|
+
|
52
|
+
def match?(span)
|
53
|
+
block.call(span.name, span.service)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'ddtrace/utils/time'
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module Sampling
|
5
|
+
# Checks for rate limiting on a resource.
|
6
|
+
class RateLimiter
|
7
|
+
# Checks if resource of specified size can be
|
8
|
+
# conforms with the current limit.
|
9
|
+
#
|
10
|
+
# Implementations of this method are not guaranteed
|
11
|
+
# to be side-effect free.
|
12
|
+
#
|
13
|
+
# @return [Boolean] whether a resource conforms with the current limit
|
14
|
+
def allow?(size); end
|
15
|
+
|
16
|
+
# The effective rate limiting ratio based on
|
17
|
+
# recent calls to `allow?`.
|
18
|
+
#
|
19
|
+
# @return [Float] recent allowance ratio
|
20
|
+
def effective_rate; end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Implementation of the Token Bucket metering algorithm
|
24
|
+
# for rate limiting.
|
25
|
+
#
|
26
|
+
# @see https://en.wikipedia.org/wiki/Token_bucket Token bucket
|
27
|
+
class TokenBucket < RateLimiter
|
28
|
+
attr_reader :rate, :max_tokens
|
29
|
+
|
30
|
+
# @param rate [Numeric] Allowance rate, in units per second
|
31
|
+
# if rate is negative, always allow
|
32
|
+
# if rate is zero, never allow
|
33
|
+
# @param max_tokens [Numeric] Limit of available tokens
|
34
|
+
def initialize(rate, max_tokens = rate)
|
35
|
+
@rate = rate
|
36
|
+
@max_tokens = max_tokens
|
37
|
+
|
38
|
+
@tokens = max_tokens
|
39
|
+
@total_messages = 0
|
40
|
+
@conforming_messages = 0
|
41
|
+
@last_refill = Utils::Time.get_time
|
42
|
+
end
|
43
|
+
|
44
|
+
# Checks if a message of provided +size+
|
45
|
+
# conforms with the current bucket limit.
|
46
|
+
#
|
47
|
+
# If it does, return +true+ and remove +size+
|
48
|
+
# tokens from the bucket.
|
49
|
+
# If it does not, return +false+ without affecting
|
50
|
+
# the tokens form the bucket.
|
51
|
+
#
|
52
|
+
# @return [Boolean] +true+ if message conforms with current bucket limit
|
53
|
+
def allow?(size)
|
54
|
+
return false if @rate.zero?
|
55
|
+
return true if @rate < 0
|
56
|
+
|
57
|
+
refill_since_last_message
|
58
|
+
|
59
|
+
increment_total_count
|
60
|
+
|
61
|
+
return false if @tokens < size
|
62
|
+
|
63
|
+
increment_conforming_count
|
64
|
+
|
65
|
+
@tokens -= size
|
66
|
+
|
67
|
+
true
|
68
|
+
end
|
69
|
+
|
70
|
+
# Ratio of 'conformance' per 'total messages' checked
|
71
|
+
# on this bucket.
|
72
|
+
#
|
73
|
+
# Returns +1.0+ when no messages have been checked yet.
|
74
|
+
#
|
75
|
+
# @return [Float] Conformance ratio, between +[0,1]+
|
76
|
+
def effective_rate
|
77
|
+
return 0.0 if @rate.zero?
|
78
|
+
return 1.0 if @rate < 0 || @total_messages.zero?
|
79
|
+
|
80
|
+
@conforming_messages.to_f / @total_messages
|
81
|
+
end
|
82
|
+
|
83
|
+
# @return [Numeric] number of tokens currently available
|
84
|
+
def available_tokens
|
85
|
+
@tokens
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def refill_since_last_message
|
91
|
+
now = Utils::Time.get_time
|
92
|
+
elapsed = now - @last_refill
|
93
|
+
|
94
|
+
refill_tokens(@rate * elapsed)
|
95
|
+
|
96
|
+
@last_refill = now
|
97
|
+
end
|
98
|
+
|
99
|
+
def refill_tokens(size)
|
100
|
+
@tokens += size
|
101
|
+
@tokens = @max_tokens if @tokens > @max_tokens
|
102
|
+
end
|
103
|
+
|
104
|
+
def increment_total_count
|
105
|
+
@total_messages += 1
|
106
|
+
end
|
107
|
+
|
108
|
+
def increment_conforming_count
|
109
|
+
@conforming_messages += 1
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# \RateLimiter that accepts all resources,
|
114
|
+
# with no limits.
|
115
|
+
class UnlimitedLimiter < RateLimiter
|
116
|
+
# @return [Boolean] always +true+
|
117
|
+
def allow?(_)
|
118
|
+
true
|
119
|
+
end
|
120
|
+
|
121
|
+
# @return [Float] always 100%
|
122
|
+
def effective_rate
|
123
|
+
1.0
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
require 'ddtrace/sampling/matcher'
|
4
|
+
require 'ddtrace/sampler'
|
5
|
+
|
6
|
+
module Datadog
|
7
|
+
module Sampling
|
8
|
+
# Sampling rule that dictates if a span matches
|
9
|
+
# a specific criteria and what sampling strategy to
|
10
|
+
# apply in case of a positive match.
|
11
|
+
class Rule
|
12
|
+
extend Forwardable
|
13
|
+
|
14
|
+
attr_reader :matcher, :sampler
|
15
|
+
|
16
|
+
# @param [Matcher] matcher A matcher to verify span conformity against
|
17
|
+
# @param [Sampler] sampler A sampler to be consulted on a positive match
|
18
|
+
def initialize(matcher, sampler)
|
19
|
+
@matcher = matcher
|
20
|
+
@sampler = sampler
|
21
|
+
end
|
22
|
+
|
23
|
+
# Evaluates if the provided `span` conforms to the `matcher`.
|
24
|
+
#
|
25
|
+
# @param [Span] span
|
26
|
+
# @return [Boolean] whether this rules applies to the span
|
27
|
+
# @return [NilClass] if the matcher fails errs during evaluation
|
28
|
+
def match?(span)
|
29
|
+
@matcher.match?(span)
|
30
|
+
rescue => e
|
31
|
+
Datadog::Tracer.log.error("Matcher failed. Cause: #{e.message} Source: #{e.backtrace.first}")
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
|
35
|
+
def_delegators :@sampler, :sample?, :sample_rate
|
36
|
+
end
|
37
|
+
|
38
|
+
# A \Rule that matches a span based on
|
39
|
+
# operation name and/or service name and
|
40
|
+
# applies a fixed sampling to matching spans.
|
41
|
+
class SimpleRule < Rule
|
42
|
+
# @param name [String,Regexp,Proc] Matcher for case equality (===) with the span name, defaults to always match
|
43
|
+
# @param service [String,Regexp,Proc] Matcher for case equality (===) with the service name, defaults to always match
|
44
|
+
# @param sample_rate [Float] Sampling rate between +[0,1]+
|
45
|
+
def initialize(name: SimpleMatcher::MATCH_ALL, service: SimpleMatcher::MATCH_ALL, sample_rate: 1.0)
|
46
|
+
# We want to allow 0.0 to drop all traces, but \RateSampler
|
47
|
+
# considers 0.0 an invalid rate and falls back to 100% sampling.
|
48
|
+
#
|
49
|
+
# We address that here by not setting the rate in the constructor,
|
50
|
+
# but using the setter method.
|
51
|
+
#
|
52
|
+
# We don't want to make this change directly to \RateSampler
|
53
|
+
# because it breaks its current contract to existing users.
|
54
|
+
sampler = Datadog::RateSampler.new
|
55
|
+
sampler.sample_rate = sample_rate
|
56
|
+
|
57
|
+
super(SimpleMatcher.new(name: name, service: service), sampler)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|