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.
Files changed (150) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +148 -130
  3. data/.circleci/images/primary/Dockerfile-3.0.0 +73 -0
  4. data/.github/workflows/add-milestone-to-pull-requests.yml +42 -0
  5. data/.github/workflows/create-next-milestone.yml +20 -0
  6. data/.simplecov +3 -0
  7. data/Appraisals +414 -135
  8. data/CHANGELOG.md +1112 -342
  9. data/CONTRIBUTING.md +2 -2
  10. data/Gemfile +4 -2
  11. data/README.md +1 -0
  12. data/Rakefile +231 -29
  13. data/ddtrace.gemspec +8 -8
  14. data/docker-compose.yml +30 -0
  15. data/docs/DevelopmentGuide.md +12 -2
  16. data/docs/GettingStarted.md +187 -16
  17. data/lib/ddtrace.rb +10 -0
  18. data/lib/ddtrace/auto_instrument.rb +3 -0
  19. data/lib/ddtrace/auto_instrument_base.rb +6 -0
  20. data/lib/ddtrace/buffer.rb +259 -52
  21. data/lib/ddtrace/configuration.rb +19 -0
  22. data/lib/ddtrace/configuration/options.rb +3 -1
  23. data/lib/ddtrace/configuration/settings.rb +9 -3
  24. data/lib/ddtrace/context.rb +18 -0
  25. data/lib/ddtrace/context_provider.rb +17 -5
  26. data/lib/ddtrace/contrib/action_cable/integration.rb +7 -0
  27. data/lib/ddtrace/contrib/action_pack/integration.rb +7 -0
  28. data/lib/ddtrace/contrib/action_view/event.rb +0 -4
  29. data/lib/ddtrace/contrib/action_view/events/render_partial.rb +1 -0
  30. data/lib/ddtrace/contrib/action_view/events/render_template.rb +1 -0
  31. data/lib/ddtrace/contrib/action_view/integration.rb +7 -0
  32. data/lib/ddtrace/contrib/active_record/events/sql.rb +4 -0
  33. data/lib/ddtrace/contrib/active_record/integration.rb +7 -0
  34. data/lib/ddtrace/contrib/active_record/utils.rb +67 -21
  35. data/lib/ddtrace/contrib/active_support/cache/instrumentation.rb +104 -3
  36. data/lib/ddtrace/contrib/active_support/cache/patcher.rb +21 -0
  37. data/lib/ddtrace/contrib/active_support/ext.rb +3 -0
  38. data/lib/ddtrace/contrib/active_support/integration.rb +7 -1
  39. data/lib/ddtrace/contrib/active_support/notifications/event.rb +10 -0
  40. data/lib/ddtrace/contrib/active_support/notifications/subscription.rb +2 -2
  41. data/lib/ddtrace/contrib/auto_instrument.rb +48 -0
  42. data/lib/ddtrace/contrib/aws/instrumentation.rb +6 -1
  43. data/lib/ddtrace/contrib/aws/patcher.rb +0 -1
  44. data/lib/ddtrace/contrib/aws/services.rb +1 -0
  45. data/lib/ddtrace/contrib/configurable.rb +2 -0
  46. data/lib/ddtrace/contrib/configuration/resolvers/pattern_resolver.rb +6 -5
  47. data/lib/ddtrace/contrib/cucumber/configuration/settings.rb +38 -0
  48. data/lib/ddtrace/contrib/cucumber/ext.rb +19 -0
  49. data/lib/ddtrace/contrib/cucumber/formatter.rb +104 -0
  50. data/lib/ddtrace/contrib/cucumber/instrumentation.rb +24 -0
  51. data/lib/ddtrace/contrib/cucumber/integration.rb +45 -0
  52. data/lib/ddtrace/contrib/cucumber/patcher.rb +23 -0
  53. data/lib/ddtrace/contrib/dalli/instrumentation.rb +4 -0
  54. data/lib/ddtrace/contrib/delayed_job/configuration/settings.rb +2 -0
  55. data/lib/ddtrace/contrib/delayed_job/ext.rb +2 -0
  56. data/lib/ddtrace/contrib/delayed_job/plugin.rb +39 -15
  57. data/lib/ddtrace/contrib/elasticsearch/patcher.rb +4 -0
  58. data/lib/ddtrace/contrib/ethon/easy_patch.rb +10 -7
  59. data/lib/ddtrace/contrib/ethon/ext.rb +1 -0
  60. data/lib/ddtrace/contrib/ethon/multi_patch.rb +4 -0
  61. data/lib/ddtrace/contrib/excon/middleware.rb +11 -1
  62. data/lib/ddtrace/contrib/extensions.rb +27 -1
  63. data/lib/ddtrace/contrib/faraday/middleware.rb +4 -0
  64. data/lib/ddtrace/contrib/faraday/patcher.rb +1 -1
  65. data/lib/ddtrace/contrib/grape/configuration/settings.rb +7 -0
  66. data/lib/ddtrace/contrib/grape/endpoint.rb +53 -18
  67. data/lib/ddtrace/contrib/grape/ext.rb +1 -0
  68. data/lib/ddtrace/contrib/grpc/datadog_interceptor/client.rb +5 -1
  69. data/lib/ddtrace/contrib/grpc/datadog_interceptor/server.rb +4 -0
  70. data/lib/ddtrace/contrib/http/instrumentation.rb +6 -2
  71. data/lib/ddtrace/contrib/httpclient/configuration/settings.rb +32 -0
  72. data/lib/ddtrace/contrib/httpclient/ext.rb +17 -0
  73. data/lib/ddtrace/contrib/httpclient/instrumentation.rb +152 -0
  74. data/lib/ddtrace/contrib/httpclient/integration.rb +43 -0
  75. data/lib/ddtrace/contrib/httpclient/patcher.rb +35 -0
  76. data/lib/ddtrace/contrib/httprb/instrumentation.rb +6 -3
  77. data/lib/ddtrace/contrib/kafka/event.rb +1 -1
  78. data/lib/ddtrace/contrib/mongodb/subscribers.rb +4 -0
  79. data/lib/ddtrace/contrib/mysql2/instrumentation.rb +4 -0
  80. data/lib/ddtrace/contrib/patchable.rb +18 -7
  81. data/lib/ddtrace/contrib/presto/instrumentation.rb +3 -0
  82. data/lib/ddtrace/contrib/qless/configuration/settings.rb +35 -0
  83. data/lib/ddtrace/contrib/qless/ext.rb +20 -0
  84. data/lib/ddtrace/contrib/qless/integration.rb +38 -0
  85. data/lib/ddtrace/contrib/qless/patcher.rb +35 -0
  86. data/lib/ddtrace/contrib/qless/qless_job.rb +72 -0
  87. data/lib/ddtrace/contrib/qless/tracer_cleaner.rb +32 -0
  88. data/lib/ddtrace/contrib/que/configuration/settings.rb +1 -0
  89. data/lib/ddtrace/contrib/que/tracer.rb +2 -1
  90. data/lib/ddtrace/contrib/racecar/event.rb +4 -0
  91. data/lib/ddtrace/contrib/rack/integration.rb +7 -0
  92. data/lib/ddtrace/contrib/rack/middlewares.rb +1 -1
  93. data/lib/ddtrace/contrib/rack/request_queue.rb +6 -1
  94. data/lib/ddtrace/contrib/rails/auto_instrument_railtie.rb +10 -0
  95. data/lib/ddtrace/contrib/rails/patcher.rb +19 -5
  96. data/lib/ddtrace/contrib/rails/utils.rb +4 -0
  97. data/lib/ddtrace/contrib/rake/integration.rb +1 -1
  98. data/lib/ddtrace/contrib/redis/configuration/resolver.rb +3 -1
  99. data/lib/ddtrace/contrib/redis/configuration/settings.rb +5 -0
  100. data/lib/ddtrace/contrib/redis/ext.rb +1 -0
  101. data/lib/ddtrace/contrib/redis/patcher.rb +20 -3
  102. data/lib/ddtrace/contrib/redis/quantize.rb +27 -0
  103. data/lib/ddtrace/contrib/redis/tags.rb +9 -1
  104. data/lib/ddtrace/contrib/resque/configuration/settings.rb +1 -0
  105. data/lib/ddtrace/contrib/resque/integration.rb +1 -1
  106. data/lib/ddtrace/contrib/resque/resque_job.rb +1 -1
  107. data/lib/ddtrace/contrib/rest_client/request_patch.rb +4 -0
  108. data/lib/ddtrace/contrib/rspec/configuration/settings.rb +38 -0
  109. data/lib/ddtrace/contrib/rspec/example.rb +61 -0
  110. data/lib/ddtrace/contrib/rspec/example_group.rb +61 -0
  111. data/lib/ddtrace/contrib/rspec/ext.rb +19 -0
  112. data/lib/ddtrace/contrib/rspec/integration.rb +46 -0
  113. data/lib/ddtrace/contrib/rspec/patcher.rb +25 -0
  114. data/lib/ddtrace/contrib/sequel/database.rb +3 -1
  115. data/lib/ddtrace/contrib/sequel/dataset.rb +3 -2
  116. data/lib/ddtrace/contrib/sequel/ext.rb +1 -0
  117. data/lib/ddtrace/contrib/sequel/utils.rb +16 -5
  118. data/lib/ddtrace/contrib/shoryuken/configuration/settings.rb +1 -0
  119. data/lib/ddtrace/contrib/shoryuken/tracer.rb +4 -1
  120. data/lib/ddtrace/contrib/sidekiq/configuration/settings.rb +1 -0
  121. data/lib/ddtrace/contrib/sidekiq/server_tracer.rb +4 -1
  122. data/lib/ddtrace/contrib/sinatra/tracer_middleware.rb +2 -2
  123. data/lib/ddtrace/contrib/sneakers/configuration/settings.rb +1 -0
  124. data/lib/ddtrace/contrib/sneakers/tracer.rb +17 -20
  125. data/lib/ddtrace/contrib/status_code_matcher.rb +67 -0
  126. data/lib/ddtrace/ext/app_types.rb +1 -0
  127. data/lib/ddtrace/ext/ci.rb +297 -0
  128. data/lib/ddtrace/ext/distributed.rb +8 -2
  129. data/lib/ddtrace/ext/git.rb +11 -0
  130. data/lib/ddtrace/ext/integration.rb +8 -0
  131. data/lib/ddtrace/ext/runtime.rb +2 -0
  132. data/lib/ddtrace/ext/test.rb +24 -0
  133. data/lib/ddtrace/opentracer/distributed_headers.rb +1 -1
  134. data/lib/ddtrace/propagation/grpc_propagator.rb +18 -6
  135. data/lib/ddtrace/propagation/http_propagator.rb +17 -2
  136. data/lib/ddtrace/runtime/identity.rb +4 -5
  137. data/lib/ddtrace/runtime/metrics.rb +6 -2
  138. data/lib/ddtrace/sampler.rb +2 -2
  139. data/lib/ddtrace/sampling/rate_limiter.rb +65 -16
  140. data/lib/ddtrace/span.rb +152 -27
  141. data/lib/ddtrace/tracer.rb +25 -13
  142. data/lib/ddtrace/transport/http/adapters/net.rb +8 -2
  143. data/lib/ddtrace/transport/http/statistics.rb +14 -1
  144. data/lib/ddtrace/transport/traces.rb +7 -2
  145. data/lib/ddtrace/utils.rb +16 -13
  146. data/lib/ddtrace/utils/forking.rb +52 -0
  147. data/lib/ddtrace/version.rb +1 -1
  148. data/lib/ddtrace/workers/runtime_metrics.rb +7 -3
  149. data/lib/ddtrace/writer.rb +19 -1
  150. metadata +111 -19
@@ -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'
@@ -0,0 +1,3 @@
1
+ require 'ddtrace'
2
+
3
+ Datadog.add_auto_instrument
@@ -0,0 +1,6 @@
1
+ module Datadog
2
+ # base methods stubbed for adding auto instrument extensions
3
+ module AutoInstrumentBase
4
+ def add_auto_instrument; end
5
+ end
6
+ end
@@ -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
- # Trace buffer that stores application traces. The buffer has a maximum size and when
7
- # the buffer is full, a random trace is discarded. This class is thread-safe and is used
8
- # automatically by the ``Tracer`` instance when a ``Span`` is finished.
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
- # Initialize metric values
18
- @buffer_accepted = 0
19
- @buffer_accepted_lengths = 0
20
- @buffer_dropped = 0
21
- @buffer_spans = 0
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
- # Add a new ``trace`` in the local queue. This method doesn't block the execution
25
- # even if the buffer is full. In that case, a random trace is discarded.
26
- def push(trace)
27
- @mutex.synchronize do
28
- return if @closed
29
- len = @traces.length
30
- if len < @max_size || @max_size <= 0
31
- @traces << trace
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
- # we should replace a random trace with the new one
34
- replace_index = rand(len)
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
- measure_accept(trace)
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
- @mutex.synchronize do
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
- @mutex.synchronize do
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
- @mutex.synchronize do
61
- traces = @traces
62
- @traces = []
164
+ synchronize { super }
165
+ end
63
166
 
64
- measure_pop(traces)
167
+ def close
168
+ synchronize { super }
169
+ end
65
170
 
66
- return traces
67
- end
171
+ def synchronize
172
+ @mutex.synchronize { yield }
68
173
  end
174
+ end
69
175
 
70
- def close
71
- @mutex.synchronize do
72
- @closed = true
73
- end
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
- # Aggregate metrics:
77
- # They reflect buffer activity since last #pop.
78
- # These may not be as accurate or as granular, but they
79
- # don't use as much network traffic as live stats.
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