ddtrace 0.40.0 → 0.45.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 +4 -4
- data/.circleci/config.yml +148 -130
- data/.circleci/images/primary/Dockerfile-3.0.0 +73 -0
- data/.github/workflows/add-milestone-to-pull-requests.yml +42 -0
- data/.github/workflows/create-next-milestone.yml +20 -0
- data/.simplecov +3 -0
- data/Appraisals +414 -135
- data/CHANGELOG.md +1112 -342
- data/CONTRIBUTING.md +2 -2
- data/Gemfile +4 -2
- data/README.md +1 -0
- data/Rakefile +231 -29
- data/ddtrace.gemspec +8 -8
- data/docker-compose.yml +30 -0
- data/docs/DevelopmentGuide.md +12 -2
- data/docs/GettingStarted.md +187 -16
- data/lib/ddtrace.rb +10 -0
- data/lib/ddtrace/auto_instrument.rb +3 -0
- data/lib/ddtrace/auto_instrument_base.rb +6 -0
- data/lib/ddtrace/buffer.rb +259 -52
- data/lib/ddtrace/configuration.rb +19 -0
- data/lib/ddtrace/configuration/options.rb +3 -1
- data/lib/ddtrace/configuration/settings.rb +9 -3
- data/lib/ddtrace/context.rb +18 -0
- data/lib/ddtrace/context_provider.rb +17 -5
- data/lib/ddtrace/contrib/action_cable/integration.rb +7 -0
- data/lib/ddtrace/contrib/action_pack/integration.rb +7 -0
- data/lib/ddtrace/contrib/action_view/event.rb +0 -4
- data/lib/ddtrace/contrib/action_view/events/render_partial.rb +1 -0
- data/lib/ddtrace/contrib/action_view/events/render_template.rb +1 -0
- data/lib/ddtrace/contrib/action_view/integration.rb +7 -0
- data/lib/ddtrace/contrib/active_record/events/sql.rb +4 -0
- data/lib/ddtrace/contrib/active_record/integration.rb +7 -0
- data/lib/ddtrace/contrib/active_record/utils.rb +67 -21
- data/lib/ddtrace/contrib/active_support/cache/instrumentation.rb +104 -3
- data/lib/ddtrace/contrib/active_support/cache/patcher.rb +21 -0
- data/lib/ddtrace/contrib/active_support/ext.rb +3 -0
- data/lib/ddtrace/contrib/active_support/integration.rb +7 -1
- data/lib/ddtrace/contrib/active_support/notifications/event.rb +10 -0
- data/lib/ddtrace/contrib/active_support/notifications/subscription.rb +2 -2
- data/lib/ddtrace/contrib/auto_instrument.rb +48 -0
- data/lib/ddtrace/contrib/aws/instrumentation.rb +6 -1
- data/lib/ddtrace/contrib/aws/patcher.rb +0 -1
- data/lib/ddtrace/contrib/aws/services.rb +1 -0
- data/lib/ddtrace/contrib/configurable.rb +2 -0
- data/lib/ddtrace/contrib/configuration/resolvers/pattern_resolver.rb +6 -5
- data/lib/ddtrace/contrib/cucumber/configuration/settings.rb +38 -0
- data/lib/ddtrace/contrib/cucumber/ext.rb +19 -0
- data/lib/ddtrace/contrib/cucumber/formatter.rb +104 -0
- data/lib/ddtrace/contrib/cucumber/instrumentation.rb +24 -0
- data/lib/ddtrace/contrib/cucumber/integration.rb +45 -0
- data/lib/ddtrace/contrib/cucumber/patcher.rb +23 -0
- data/lib/ddtrace/contrib/dalli/instrumentation.rb +4 -0
- data/lib/ddtrace/contrib/delayed_job/configuration/settings.rb +2 -0
- data/lib/ddtrace/contrib/delayed_job/ext.rb +2 -0
- data/lib/ddtrace/contrib/delayed_job/plugin.rb +39 -15
- data/lib/ddtrace/contrib/elasticsearch/patcher.rb +4 -0
- data/lib/ddtrace/contrib/ethon/easy_patch.rb +10 -7
- data/lib/ddtrace/contrib/ethon/ext.rb +1 -0
- data/lib/ddtrace/contrib/ethon/multi_patch.rb +4 -0
- data/lib/ddtrace/contrib/excon/middleware.rb +11 -1
- data/lib/ddtrace/contrib/extensions.rb +27 -1
- data/lib/ddtrace/contrib/faraday/middleware.rb +4 -0
- data/lib/ddtrace/contrib/faraday/patcher.rb +1 -1
- data/lib/ddtrace/contrib/grape/configuration/settings.rb +7 -0
- data/lib/ddtrace/contrib/grape/endpoint.rb +53 -18
- data/lib/ddtrace/contrib/grape/ext.rb +1 -0
- data/lib/ddtrace/contrib/grpc/datadog_interceptor/client.rb +5 -1
- data/lib/ddtrace/contrib/grpc/datadog_interceptor/server.rb +4 -0
- data/lib/ddtrace/contrib/http/instrumentation.rb +6 -2
- data/lib/ddtrace/contrib/httpclient/configuration/settings.rb +32 -0
- data/lib/ddtrace/contrib/httpclient/ext.rb +17 -0
- data/lib/ddtrace/contrib/httpclient/instrumentation.rb +152 -0
- data/lib/ddtrace/contrib/httpclient/integration.rb +43 -0
- data/lib/ddtrace/contrib/httpclient/patcher.rb +35 -0
- data/lib/ddtrace/contrib/httprb/instrumentation.rb +6 -3
- data/lib/ddtrace/contrib/kafka/event.rb +1 -1
- data/lib/ddtrace/contrib/mongodb/subscribers.rb +4 -0
- data/lib/ddtrace/contrib/mysql2/instrumentation.rb +4 -0
- data/lib/ddtrace/contrib/patchable.rb +18 -7
- data/lib/ddtrace/contrib/presto/instrumentation.rb +3 -0
- data/lib/ddtrace/contrib/qless/configuration/settings.rb +35 -0
- data/lib/ddtrace/contrib/qless/ext.rb +20 -0
- data/lib/ddtrace/contrib/qless/integration.rb +38 -0
- data/lib/ddtrace/contrib/qless/patcher.rb +35 -0
- data/lib/ddtrace/contrib/qless/qless_job.rb +72 -0
- data/lib/ddtrace/contrib/qless/tracer_cleaner.rb +32 -0
- data/lib/ddtrace/contrib/que/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/que/tracer.rb +2 -1
- data/lib/ddtrace/contrib/racecar/event.rb +4 -0
- data/lib/ddtrace/contrib/rack/integration.rb +7 -0
- data/lib/ddtrace/contrib/rack/middlewares.rb +1 -1
- data/lib/ddtrace/contrib/rack/request_queue.rb +6 -1
- data/lib/ddtrace/contrib/rails/auto_instrument_railtie.rb +10 -0
- data/lib/ddtrace/contrib/rails/patcher.rb +19 -5
- data/lib/ddtrace/contrib/rails/utils.rb +4 -0
- data/lib/ddtrace/contrib/rake/integration.rb +1 -1
- data/lib/ddtrace/contrib/redis/configuration/resolver.rb +3 -1
- data/lib/ddtrace/contrib/redis/configuration/settings.rb +5 -0
- data/lib/ddtrace/contrib/redis/ext.rb +1 -0
- data/lib/ddtrace/contrib/redis/patcher.rb +20 -3
- data/lib/ddtrace/contrib/redis/quantize.rb +27 -0
- data/lib/ddtrace/contrib/redis/tags.rb +9 -1
- data/lib/ddtrace/contrib/resque/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/resque/integration.rb +1 -1
- data/lib/ddtrace/contrib/resque/resque_job.rb +1 -1
- data/lib/ddtrace/contrib/rest_client/request_patch.rb +4 -0
- data/lib/ddtrace/contrib/rspec/configuration/settings.rb +38 -0
- data/lib/ddtrace/contrib/rspec/example.rb +61 -0
- data/lib/ddtrace/contrib/rspec/example_group.rb +61 -0
- data/lib/ddtrace/contrib/rspec/ext.rb +19 -0
- data/lib/ddtrace/contrib/rspec/integration.rb +46 -0
- data/lib/ddtrace/contrib/rspec/patcher.rb +25 -0
- data/lib/ddtrace/contrib/sequel/database.rb +3 -1
- data/lib/ddtrace/contrib/sequel/dataset.rb +3 -2
- data/lib/ddtrace/contrib/sequel/ext.rb +1 -0
- data/lib/ddtrace/contrib/sequel/utils.rb +16 -5
- data/lib/ddtrace/contrib/shoryuken/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/shoryuken/tracer.rb +4 -1
- data/lib/ddtrace/contrib/sidekiq/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/sidekiq/server_tracer.rb +4 -1
- data/lib/ddtrace/contrib/sinatra/tracer_middleware.rb +2 -2
- data/lib/ddtrace/contrib/sneakers/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/sneakers/tracer.rb +17 -20
- data/lib/ddtrace/contrib/status_code_matcher.rb +67 -0
- data/lib/ddtrace/ext/app_types.rb +1 -0
- data/lib/ddtrace/ext/ci.rb +297 -0
- data/lib/ddtrace/ext/distributed.rb +8 -2
- data/lib/ddtrace/ext/git.rb +11 -0
- data/lib/ddtrace/ext/integration.rb +8 -0
- data/lib/ddtrace/ext/runtime.rb +2 -0
- data/lib/ddtrace/ext/test.rb +24 -0
- data/lib/ddtrace/opentracer/distributed_headers.rb +1 -1
- data/lib/ddtrace/propagation/grpc_propagator.rb +18 -6
- data/lib/ddtrace/propagation/http_propagator.rb +17 -2
- data/lib/ddtrace/runtime/identity.rb +4 -5
- data/lib/ddtrace/runtime/metrics.rb +6 -2
- data/lib/ddtrace/sampler.rb +2 -2
- data/lib/ddtrace/sampling/rate_limiter.rb +65 -16
- data/lib/ddtrace/span.rb +152 -27
- data/lib/ddtrace/tracer.rb +25 -13
- data/lib/ddtrace/transport/http/adapters/net.rb +8 -2
- data/lib/ddtrace/transport/http/statistics.rb +14 -1
- data/lib/ddtrace/transport/traces.rb +7 -2
- data/lib/ddtrace/utils.rb +16 -13
- data/lib/ddtrace/utils/forking.rb +52 -0
- data/lib/ddtrace/version.rb +1 -1
- data/lib/ddtrace/workers/runtime_metrics.rb +7 -3
- data/lib/ddtrace/writer.rb +19 -1
- metadata +111 -19
data/lib/ddtrace.rb
CHANGED
|
@@ -17,11 +17,13 @@ require 'ddtrace/configuration'
|
|
|
17
17
|
require 'ddtrace/patcher'
|
|
18
18
|
require 'ddtrace/augmentation'
|
|
19
19
|
require 'ddtrace/metrics'
|
|
20
|
+
require 'ddtrace/auto_instrument_base'
|
|
20
21
|
|
|
21
22
|
# \Datadog global namespace that includes all tracing functionality for Tracer and Span classes.
|
|
22
23
|
module Datadog
|
|
23
24
|
extend Augmentation
|
|
24
25
|
extend Configuration
|
|
26
|
+
extend AutoInstrumentBase
|
|
25
27
|
|
|
26
28
|
# Load and extend Contrib by default
|
|
27
29
|
require 'ddtrace/contrib/extensions'
|
|
@@ -31,6 +33,10 @@ module Datadog
|
|
|
31
33
|
require 'ddtrace/opentelemetry/extensions'
|
|
32
34
|
extend OpenTelemetry::Extensions
|
|
33
35
|
|
|
36
|
+
# Load and extend AutoInstrument
|
|
37
|
+
require 'ddtrace/contrib/auto_instrument'
|
|
38
|
+
extend Contrib::AutoInstrument
|
|
39
|
+
|
|
34
40
|
# Add shutdown hook:
|
|
35
41
|
# Ensures the tracer has an opportunity to flush traces
|
|
36
42
|
# and cleanup before terminating the process.
|
|
@@ -45,6 +51,7 @@ require 'ddtrace/contrib/active_record/integration'
|
|
|
45
51
|
require 'ddtrace/contrib/active_support/integration'
|
|
46
52
|
require 'ddtrace/contrib/aws/integration'
|
|
47
53
|
require 'ddtrace/contrib/concurrent_ruby/integration'
|
|
54
|
+
require 'ddtrace/contrib/cucumber/integration'
|
|
48
55
|
require 'ddtrace/contrib/dalli/integration'
|
|
49
56
|
require 'ddtrace/contrib/delayed_job/integration'
|
|
50
57
|
require 'ddtrace/contrib/elasticsearch/integration'
|
|
@@ -55,6 +62,7 @@ require 'ddtrace/contrib/grape/integration'
|
|
|
55
62
|
require 'ddtrace/contrib/graphql/integration'
|
|
56
63
|
require 'ddtrace/contrib/grpc/integration'
|
|
57
64
|
require 'ddtrace/contrib/http/integration'
|
|
65
|
+
require 'ddtrace/contrib/httpclient/integration'
|
|
58
66
|
require 'ddtrace/contrib/httprb/integration'
|
|
59
67
|
require 'ddtrace/contrib/integration'
|
|
60
68
|
require 'ddtrace/contrib/kafka/integration'
|
|
@@ -62,6 +70,7 @@ require 'ddtrace/contrib/presto/integration'
|
|
|
62
70
|
require 'ddtrace/contrib/que/integration'
|
|
63
71
|
require 'ddtrace/contrib/mysql2/integration'
|
|
64
72
|
require 'ddtrace/contrib/mongodb/integration'
|
|
73
|
+
require 'ddtrace/contrib/qless/integration'
|
|
65
74
|
require 'ddtrace/contrib/racecar/integration'
|
|
66
75
|
require 'ddtrace/contrib/rack/integration'
|
|
67
76
|
require 'ddtrace/contrib/rails/integration'
|
|
@@ -69,6 +78,7 @@ require 'ddtrace/contrib/rake/integration'
|
|
|
69
78
|
require 'ddtrace/contrib/redis/integration'
|
|
70
79
|
require 'ddtrace/contrib/resque/integration'
|
|
71
80
|
require 'ddtrace/contrib/rest_client/integration'
|
|
81
|
+
require 'ddtrace/contrib/rspec/integration'
|
|
72
82
|
require 'ddtrace/contrib/sequel/integration'
|
|
73
83
|
require 'ddtrace/contrib/shoryuken/integration'
|
|
74
84
|
require 'ddtrace/contrib/sidekiq/integration'
|
data/lib/ddtrace/buffer.rb
CHANGED
|
@@ -2,107 +2,284 @@ require 'thread'
|
|
|
2
2
|
require 'ddtrace/diagnostics/health'
|
|
3
3
|
require 'ddtrace/runtime/object_space'
|
|
4
4
|
|
|
5
|
+
# Trace buffer that accumulates traces for a consumer.
|
|
6
|
+
# Consumption can happen from a different thread.
|
|
5
7
|
module Datadog
|
|
6
|
-
#
|
|
7
|
-
# the buffer is full, a random
|
|
8
|
-
|
|
9
|
-
class TraceBuffer
|
|
8
|
+
# Buffer that stores objects. The buffer has a maximum size and when
|
|
9
|
+
# the buffer is full, a random object is discarded.
|
|
10
|
+
class Buffer
|
|
10
11
|
def initialize(max_size)
|
|
11
12
|
@max_size = max_size
|
|
12
|
-
|
|
13
|
-
@mutex = Mutex.new()
|
|
14
|
-
@traces = []
|
|
13
|
+
@items = []
|
|
15
14
|
@closed = false
|
|
15
|
+
end
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
# Add a new ``item`` in the local queue. This method doesn't block the execution
|
|
18
|
+
# even if the buffer is full. In that case, a random item is discarded.
|
|
19
|
+
def push(item)
|
|
20
|
+
return if closed?
|
|
21
|
+
full? ? replace!(item) : add!(item)
|
|
22
|
+
item
|
|
22
23
|
end
|
|
23
24
|
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
def
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
25
|
+
# A bulk push alternative to +#push+. Use this method if
|
|
26
|
+
# pushing more than one item for efficiency.
|
|
27
|
+
def concat(items)
|
|
28
|
+
return if closed?
|
|
29
|
+
|
|
30
|
+
# Segment items into underflow and overflow
|
|
31
|
+
underflow, overflow = overflow_segments(items)
|
|
32
|
+
|
|
33
|
+
# Concatenate items do not exceed capacity.
|
|
34
|
+
add_all!(underflow) unless underflow.nil?
|
|
35
|
+
|
|
36
|
+
# Iteratively replace items, to ensure pseudo-random replacement.
|
|
37
|
+
overflow.each { |item| replace!(item) } unless overflow.nil?
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Stored items are returned and the local buffer is reset.
|
|
41
|
+
def pop
|
|
42
|
+
drain!
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Return the current number of stored traces.
|
|
46
|
+
def length
|
|
47
|
+
@items.length
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Return if the buffer is empty.
|
|
51
|
+
def empty?
|
|
52
|
+
@items.empty?
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Closes this buffer, preventing further pushing.
|
|
56
|
+
# Draining is still allowed.
|
|
57
|
+
def close
|
|
58
|
+
@closed = true
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def closed?
|
|
62
|
+
@closed
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
protected
|
|
66
|
+
|
|
67
|
+
# Segment items into two distinct segments: underflow and overflow.
|
|
68
|
+
# Underflow are items that will fit into buffer.
|
|
69
|
+
# Overflow are items that will exceed capacity, after underflow is added.
|
|
70
|
+
# Returns each array, and nil if there is no underflow/overflow.
|
|
71
|
+
def overflow_segments(items)
|
|
72
|
+
underflow = nil
|
|
73
|
+
overflow = nil
|
|
74
|
+
|
|
75
|
+
overflow_size = @max_size > 0 ? (@items.length + items.length) - @max_size : 0
|
|
76
|
+
|
|
77
|
+
if overflow_size > 0
|
|
78
|
+
# Items will overflow
|
|
79
|
+
if overflow_size < items.length
|
|
80
|
+
# Partial overflow
|
|
81
|
+
underflow_end_index = items.length - overflow_size - 1
|
|
82
|
+
underflow = items[0..underflow_end_index]
|
|
83
|
+
overflow = items[(underflow_end_index + 1)..-1]
|
|
32
84
|
else
|
|
33
|
-
#
|
|
34
|
-
|
|
35
|
-
replaced_trace = @traces[replace_index]
|
|
36
|
-
@traces[replace_index] = trace
|
|
37
|
-
measure_drop(replaced_trace)
|
|
85
|
+
# Total overflow
|
|
86
|
+
overflow = items
|
|
38
87
|
end
|
|
39
|
-
|
|
40
|
-
|
|
88
|
+
else
|
|
89
|
+
# Items do not exceed capacity.
|
|
90
|
+
underflow = items
|
|
41
91
|
end
|
|
92
|
+
|
|
93
|
+
[underflow, overflow]
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def full?
|
|
97
|
+
@max_size > 0 && @items.length >= @max_size
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def add_all!(items)
|
|
101
|
+
@items.concat(items)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def add!(item)
|
|
105
|
+
@items << item
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def replace!(item)
|
|
109
|
+
# Choose random item to be replaced
|
|
110
|
+
replace_index = rand(@items.length)
|
|
111
|
+
|
|
112
|
+
# Replace random item
|
|
113
|
+
discarded_item = @items[replace_index]
|
|
114
|
+
@items[replace_index] = item
|
|
115
|
+
|
|
116
|
+
# Return discarded item
|
|
117
|
+
discarded_item
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def drain!
|
|
121
|
+
items = @items
|
|
122
|
+
@items = []
|
|
123
|
+
items
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Buffer that stores objects, has a maximum size, and
|
|
128
|
+
# can be safely used concurrently on any environment.
|
|
129
|
+
#
|
|
130
|
+
# This implementation uses a {Mutex} around public methods, incurring
|
|
131
|
+
# overhead in order to ensure thread-safety.
|
|
132
|
+
#
|
|
133
|
+
# This is implementation is recommended for non-CRuby environments.
|
|
134
|
+
# If using CRuby, {Datadog::CRubyBuffer} is a faster implementation with minimal compromise.
|
|
135
|
+
class ThreadSafeBuffer < Buffer
|
|
136
|
+
def initialize(max_size)
|
|
137
|
+
super
|
|
138
|
+
|
|
139
|
+
@mutex = Mutex.new
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Add a new ``item`` in the local queue. This method doesn't block the execution
|
|
143
|
+
# even if the buffer is full. In that case, a random item is discarded.
|
|
144
|
+
def push(item)
|
|
145
|
+
synchronize { super }
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def concat(items)
|
|
149
|
+
synchronize { super }
|
|
42
150
|
end
|
|
43
151
|
|
|
44
152
|
# Return the current number of stored traces.
|
|
45
153
|
def length
|
|
46
|
-
|
|
47
|
-
return @traces.length
|
|
48
|
-
end
|
|
154
|
+
synchronize { super }
|
|
49
155
|
end
|
|
50
156
|
|
|
51
157
|
# Return if the buffer is empty.
|
|
52
158
|
def empty?
|
|
53
|
-
|
|
54
|
-
return @traces.empty?
|
|
55
|
-
end
|
|
159
|
+
synchronize { super }
|
|
56
160
|
end
|
|
57
161
|
|
|
58
162
|
# Stored traces are returned and the local buffer is reset.
|
|
59
163
|
def pop
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
@traces = []
|
|
164
|
+
synchronize { super }
|
|
165
|
+
end
|
|
63
166
|
|
|
64
|
-
|
|
167
|
+
def close
|
|
168
|
+
synchronize { super }
|
|
169
|
+
end
|
|
65
170
|
|
|
66
|
-
|
|
67
|
-
|
|
171
|
+
def synchronize
|
|
172
|
+
@mutex.synchronize { yield }
|
|
68
173
|
end
|
|
174
|
+
end
|
|
69
175
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
176
|
+
# Buffer that stores objects, has a maximum size, and
|
|
177
|
+
# can be safely used concurrently with CRuby.
|
|
178
|
+
#
|
|
179
|
+
# Under extreme concurrency scenarios, this class can exceed
|
|
180
|
+
# its +max_size+ by up to 4%.
|
|
181
|
+
#
|
|
182
|
+
# Because singular +Array+ operations are thread-safe in CRuby,
|
|
183
|
+
# we can implement the trace buffer without an explicit lock,
|
|
184
|
+
# while making the compromise of allowing the buffer to go
|
|
185
|
+
# over its maximum limit under extreme circumstances.
|
|
186
|
+
#
|
|
187
|
+
# On the following scenario:
|
|
188
|
+
# * 4.5 million spans/second.
|
|
189
|
+
# * Pushed into a single CRubyTraceBuffer from 1000 threads.
|
|
190
|
+
# The buffer can exceed its maximum size by no more than 4%.
|
|
191
|
+
#
|
|
192
|
+
# This implementation allocates less memory and is faster
|
|
193
|
+
# than {Datadog::ThreadSafeBuffer}.
|
|
194
|
+
#
|
|
195
|
+
# @see spec/ddtrace/benchmark/buffer_benchmark_spec.rb Buffer benchmarks
|
|
196
|
+
# @see https://github.com/ruby-concurrency/concurrent-ruby/blob/c1114a0c6891d9634f019f1f9fe58dcae8658964/lib/concurrent-ruby/concurrent/array.rb#L23-L27
|
|
197
|
+
class CRubyBuffer < Buffer
|
|
198
|
+
# Add a new ``trace`` in the local queue. This method doesn't block the execution
|
|
199
|
+
# even if the buffer is full. In that case, a random trace is discarded.
|
|
200
|
+
def replace!(item)
|
|
201
|
+
# we should replace a random trace with the new one
|
|
202
|
+
replace_index = rand(@items.size)
|
|
203
|
+
replaced_trace = @items.delete_at(replace_index)
|
|
204
|
+
@items << item
|
|
205
|
+
|
|
206
|
+
# We might have deleted an element right when the buffer
|
|
207
|
+
# was drained, thus +replaced_trace+ will be +nil+.
|
|
208
|
+
# In that case, nothing was replaced, and this method
|
|
209
|
+
# performed a simple insertion into the buffer.
|
|
210
|
+
replaced_trace
|
|
74
211
|
end
|
|
212
|
+
end
|
|
75
213
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
214
|
+
# Health metrics for trace buffers.
|
|
215
|
+
module MeasuredBuffer
|
|
216
|
+
def initialize(*_)
|
|
217
|
+
super
|
|
218
|
+
|
|
219
|
+
@buffer_accepted = 0
|
|
220
|
+
@buffer_accepted_lengths = 0
|
|
221
|
+
@buffer_dropped = 0
|
|
222
|
+
@buffer_spans = 0
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def add!(trace)
|
|
226
|
+
super
|
|
227
|
+
|
|
228
|
+
# Emit health metrics
|
|
229
|
+
measure_accept(trace)
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def add_all!(traces)
|
|
233
|
+
super
|
|
234
|
+
|
|
235
|
+
# Emit health metrics
|
|
236
|
+
traces.each { |trace| measure_accept(trace) }
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def replace!(trace)
|
|
240
|
+
discarded_trace = super
|
|
241
|
+
|
|
242
|
+
# Emit health metrics
|
|
243
|
+
measure_accept(trace)
|
|
244
|
+
measure_drop(discarded_trace) if discarded_trace
|
|
245
|
+
|
|
246
|
+
discarded_trace
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
# Stored traces are returned and the local buffer is reset.
|
|
250
|
+
def drain!
|
|
251
|
+
traces = super
|
|
252
|
+
measure_pop(traces)
|
|
253
|
+
traces
|
|
254
|
+
end
|
|
80
255
|
|
|
81
256
|
def measure_accept(trace)
|
|
82
|
-
@buffer_spans += trace.length
|
|
83
257
|
@buffer_accepted += 1
|
|
84
258
|
@buffer_accepted_lengths += trace.length
|
|
259
|
+
|
|
260
|
+
@buffer_spans += trace.length
|
|
85
261
|
rescue StandardError => e
|
|
86
262
|
Datadog.logger.debug("Failed to measure queue accept. Cause: #{e.message} Source: #{e.backtrace.first}")
|
|
87
263
|
end
|
|
88
264
|
|
|
89
265
|
def measure_drop(trace)
|
|
90
266
|
@buffer_dropped += 1
|
|
267
|
+
|
|
91
268
|
@buffer_spans -= trace.length
|
|
92
|
-
@buffer_accepted_lengths -= trace.length
|
|
93
269
|
rescue StandardError => e
|
|
94
270
|
Datadog.logger.debug("Failed to measure queue drop. Cause: #{e.message} Source: #{e.backtrace.first}")
|
|
95
271
|
end
|
|
96
272
|
|
|
97
273
|
def measure_pop(traces)
|
|
98
|
-
# Accepted
|
|
274
|
+
# Accepted, cumulative totals
|
|
99
275
|
Datadog.health_metrics.queue_accepted(@buffer_accepted)
|
|
100
276
|
Datadog.health_metrics.queue_accepted_lengths(@buffer_accepted_lengths)
|
|
101
277
|
|
|
102
|
-
# Dropped
|
|
278
|
+
# Dropped, cumulative totals
|
|
103
279
|
Datadog.health_metrics.queue_dropped(@buffer_dropped)
|
|
280
|
+
# TODO: are we missing a +queue_dropped_lengths+ metric?
|
|
104
281
|
|
|
105
|
-
# Queue gauges
|
|
282
|
+
# Queue gauges, current values
|
|
106
283
|
Datadog.health_metrics.queue_max_length(@max_size)
|
|
107
284
|
Datadog.health_metrics.queue_spans(@buffer_spans)
|
|
108
285
|
Datadog.health_metrics.queue_length(traces.length)
|
|
@@ -116,4 +293,34 @@ module Datadog
|
|
|
116
293
|
Datadog.logger.debug("Failed to measure queue. Cause: #{e.message} Source: #{e.backtrace.first}")
|
|
117
294
|
end
|
|
118
295
|
end
|
|
296
|
+
|
|
297
|
+
# Trace buffer that stores application traces, has a maximum size, and
|
|
298
|
+
# can be safely used concurrently on any environment.
|
|
299
|
+
#
|
|
300
|
+
# @see {Datadog::ThreadSafeBuffer}
|
|
301
|
+
class ThreadSafeTraceBuffer < ThreadSafeBuffer
|
|
302
|
+
prepend MeasuredBuffer
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
# Trace buffer that stores application traces, has a maximum size, and
|
|
306
|
+
# can be safely used concurrently with CRuby.
|
|
307
|
+
#
|
|
308
|
+
# @see {Datadog::CRubyBuffer}
|
|
309
|
+
class CRubyTraceBuffer < CRubyBuffer
|
|
310
|
+
prepend MeasuredBuffer
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
# Trace buffer that stores application traces. The buffer has a maximum size and when
|
|
314
|
+
# the buffer is full, a random trace is discarded. This class is thread-safe and is used
|
|
315
|
+
# automatically by the ``Tracer`` instance when a ``Span`` is finished.
|
|
316
|
+
#
|
|
317
|
+
# We choose the default TraceBuffer implementation for current platform dynamically here.
|
|
318
|
+
#
|
|
319
|
+
# TODO We should restructure this module, so that classes are not declared at top-level ::Datadog.
|
|
320
|
+
# TODO Making such a change is potentially breaking for users manually configuring the tracer.
|
|
321
|
+
TraceBuffer = if Datadog::Ext::Runtime::RUBY_ENGINE == 'ruby' # rubocop:disable Style/ConstantName
|
|
322
|
+
CRubyTraceBuffer
|
|
323
|
+
else
|
|
324
|
+
ThreadSafeTraceBuffer
|
|
325
|
+
end
|
|
119
326
|
end
|
|
@@ -55,10 +55,29 @@ module Datadog
|
|
|
55
55
|
end
|
|
56
56
|
end
|
|
57
57
|
|
|
58
|
+
# Gracefully shuts down all components.
|
|
59
|
+
#
|
|
60
|
+
# Components will still respond to method calls as usual,
|
|
61
|
+
# but might not internally perform their work after shutdown.
|
|
62
|
+
#
|
|
63
|
+
# This avoids errors being raised across the host application
|
|
64
|
+
# during shutdown, while allowing for graceful decommission of resources.
|
|
65
|
+
#
|
|
66
|
+
# Components won't be automatically reinitialized after a shutdown.
|
|
58
67
|
def shutdown!
|
|
59
68
|
components.shutdown! if instance_variable_defined?(:@components) && @components
|
|
60
69
|
end
|
|
61
70
|
|
|
71
|
+
# Gracefully shuts down the tracer and disposes of component references,
|
|
72
|
+
# allowing execution to start anew.
|
|
73
|
+
#
|
|
74
|
+
# In contrast with +#shutdown!+, components will be automatically
|
|
75
|
+
# reinitialized after a reset.
|
|
76
|
+
def reset!
|
|
77
|
+
shutdown!
|
|
78
|
+
@components = nil
|
|
79
|
+
end
|
|
80
|
+
|
|
62
81
|
protected
|
|
63
82
|
|
|
64
83
|
def components
|