ddtrace 0.8.2 → 0.9.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/.env +3 -1
- data/.gitignore +1 -0
- data/Appraisals +10 -0
- data/Rakefile +27 -1
- data/ddtrace.gemspec +2 -2
- data/docker-compose.yml +10 -0
- data/docs/GettingStarted.md +119 -0
- data/gemfiles/contrib.gemfile +5 -0
- data/gemfiles/contrib_old.gemfile +4 -0
- data/lib/ddtrace.rb +4 -11
- data/lib/ddtrace/buffer.rb +14 -0
- data/lib/ddtrace/contrib/aws/instrumentation.rb +43 -0
- data/lib/ddtrace/contrib/aws/parsed_context.rb +56 -0
- data/lib/ddtrace/contrib/aws/patcher.rb +56 -0
- data/lib/ddtrace/contrib/aws/services.rb +115 -0
- data/lib/ddtrace/contrib/dalli/instrumentation.rb +35 -0
- data/lib/ddtrace/contrib/dalli/patcher.rb +50 -0
- data/lib/ddtrace/contrib/dalli/quantize.rb +17 -0
- data/lib/ddtrace/contrib/faraday/middleware.rb +75 -0
- data/lib/ddtrace/contrib/faraday/patcher.rb +52 -0
- data/lib/ddtrace/contrib/mongodb/parsers.rb +57 -0
- data/lib/ddtrace/contrib/mongodb/patcher.rb +93 -0
- data/lib/ddtrace/contrib/mongodb/subscribers.rb +71 -0
- data/lib/ddtrace/contrib/rails/action_controller.rb +18 -19
- data/lib/ddtrace/contrib/rails/action_view.rb +51 -61
- data/lib/ddtrace/contrib/rails/active_support.rb +29 -73
- data/lib/ddtrace/contrib/rails/core_extensions.rb +191 -53
- data/lib/ddtrace/contrib/redis/quantize.rb +4 -6
- data/lib/ddtrace/contrib/resque/patcher.rb +38 -0
- data/lib/ddtrace/contrib/resque/resque_job.rb +31 -0
- data/lib/ddtrace/contrib/sucker_punch/exception_handler.rb +26 -0
- data/lib/ddtrace/contrib/sucker_punch/instrumentation.rb +60 -0
- data/lib/ddtrace/contrib/sucker_punch/patcher.rb +50 -0
- data/lib/ddtrace/ext/http.rb +1 -0
- data/lib/ddtrace/ext/mongo.rb +12 -0
- data/lib/ddtrace/monkey.rb +18 -0
- data/lib/ddtrace/pipeline.rb +46 -0
- data/lib/ddtrace/pipeline/span_filter.rb +38 -0
- data/lib/ddtrace/pipeline/span_processor.rb +20 -0
- data/lib/ddtrace/tracer.rb +18 -0
- data/lib/ddtrace/utils.rb +23 -3
- data/lib/ddtrace/version.rb +2 -2
- data/lib/ddtrace/workers.rb +30 -22
- data/lib/ddtrace/writer.rb +5 -7
- metadata +30 -9
@@ -1,50 +1,170 @@
|
|
1
1
|
module Datadog
|
2
2
|
# RailsRendererPatcher contains function to patch Rails rendering libraries.
|
3
|
+
# rubocop:disable Lint/RescueException
|
4
|
+
# rubocop:disable Metrics/MethodLength
|
5
|
+
# rubocop:disable Metrics/BlockLength
|
3
6
|
module RailsRendererPatcher
|
4
7
|
module_function
|
5
8
|
|
6
9
|
def patch_renderer
|
7
|
-
|
8
|
-
|
10
|
+
if defined?(::ActionView::TemplateRenderer) && defined?(::ActionView::PartialRenderer)
|
11
|
+
patch_template_renderer(::ActionView::TemplateRenderer)
|
12
|
+
patch_partial_renderer(::ActionView::PartialRenderer)
|
13
|
+
elsif defined?(::ActionView::Rendering) && defined?(::ActionView::Partials::PartialRenderer)
|
14
|
+
# NOTE: Rails < 3.1 compatibility: different classes are used
|
15
|
+
patch_template_renderer(::ActionView::Rendering)
|
16
|
+
patch_partial_renderer(::ActionView::Partials::PartialRenderer)
|
17
|
+
else
|
18
|
+
Datadog::Tracer.log.debug('Expected Template/Partial classes not found; template rendering disabled')
|
19
|
+
end
|
9
20
|
end
|
10
21
|
|
11
|
-
def
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
22
|
+
def patch_template_renderer(klass)
|
23
|
+
klass.class_eval do
|
24
|
+
def render_with_datadog(*args, &block)
|
25
|
+
# create a tracing context and start the rendering span
|
26
|
+
# NOTE: Rails < 3.1 compatibility: preserve the tracing
|
27
|
+
# context when a partial is rendered
|
28
|
+
@tracing_context ||= {}
|
29
|
+
if @tracing_context.empty?
|
30
|
+
::ActiveSupport::Notifications.instrument(
|
31
|
+
'!datadog.start_render_template.action_view',
|
32
|
+
tracing_context: @tracing_context
|
33
|
+
)
|
18
34
|
end
|
35
|
+
render_without_datadog(*args)
|
36
|
+
rescue Exception => e
|
37
|
+
# attach the exception to the tracing context if any
|
38
|
+
@tracing_context[:exception] = e
|
39
|
+
raise e
|
40
|
+
ensure
|
41
|
+
# ensure that the template `Span` is finished even during exceptions
|
42
|
+
::ActiveSupport::Notifications.instrument(
|
43
|
+
'!datadog.finish_render_template.action_view',
|
44
|
+
tracing_context: @tracing_context
|
45
|
+
)
|
19
46
|
end
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
47
|
+
|
48
|
+
def render_template_with_datadog(*args)
|
49
|
+
begin
|
50
|
+
# arguments based on render_template signature (stable since Rails 3.2)
|
51
|
+
template = args[0]
|
52
|
+
layout_name = args[1]
|
53
|
+
|
54
|
+
# update the tracing context with computed values before the rendering
|
55
|
+
template_name = template.try('identifier')
|
56
|
+
template_name = Datadog::Contrib::Rails::Utils.normalize_template_name(template_name)
|
57
|
+
layout = if layout_name.is_a?(String)
|
58
|
+
# NOTE: Rails < 3.1 compatibility: the second argument is the layout name
|
59
|
+
layout_name
|
60
|
+
else
|
61
|
+
layout_name.try(:[], 'virtual_path')
|
62
|
+
end
|
63
|
+
@tracing_context[:template_name] = template_name
|
64
|
+
@tracing_context[:layout] = layout
|
65
|
+
rescue StandardError => e
|
66
|
+
Datadog::Tracer.log.debug(e.message)
|
26
67
|
end
|
68
|
+
|
69
|
+
# execute the original function anyway
|
70
|
+
render_template_without_datadog(*args)
|
71
|
+
end
|
72
|
+
|
73
|
+
# method aliasing to patch the class
|
74
|
+
alias_method :render_without_datadog, :render
|
75
|
+
alias_method :render, :render_with_datadog
|
76
|
+
|
77
|
+
if klass.private_method_defined?(:render_template) || klass.method_defined?(:render_template)
|
78
|
+
alias_method :render_template_without_datadog, :render_template
|
79
|
+
alias_method :render_template, :render_template_with_datadog
|
80
|
+
else
|
81
|
+
# NOTE: Rails < 3.1 compatibility: the method name is different
|
82
|
+
alias_method :render_template_without_datadog, :_render_template
|
83
|
+
alias_method :_render_template, :render_template_with_datadog
|
27
84
|
end
|
28
85
|
end
|
29
86
|
end
|
30
87
|
|
31
|
-
def
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
88
|
+
def patch_partial_renderer(klass)
|
89
|
+
klass.class_eval do
|
90
|
+
def render_with_datadog(*args, &block)
|
91
|
+
# create a tracing context and start the rendering span
|
92
|
+
@tracing_context = {}
|
93
|
+
::ActiveSupport::Notifications.instrument(
|
94
|
+
'!datadog.start_render_partial.action_view',
|
95
|
+
tracing_context: @tracing_context
|
96
|
+
)
|
97
|
+
render_without_datadog(*args)
|
98
|
+
rescue Exception => e
|
99
|
+
# attach the exception to the tracing context if any
|
100
|
+
@tracing_context[:exception] = e
|
101
|
+
raise e
|
102
|
+
ensure
|
103
|
+
# ensure that the template `Span` is finished even during exceptions
|
104
|
+
::ActiveSupport::Notifications.instrument(
|
105
|
+
'!datadog.finish_render_partial.action_view',
|
106
|
+
tracing_context: @tracing_context
|
107
|
+
)
|
108
|
+
end
|
109
|
+
|
110
|
+
def render_partial_with_datadog(*args)
|
111
|
+
begin
|
112
|
+
# update the tracing context with computed values before the rendering
|
113
|
+
template_name = Datadog::Contrib::Rails::Utils.normalize_template_name(@template.try('identifier'))
|
114
|
+
@tracing_context[:template_name] = template_name
|
115
|
+
rescue StandardError => e
|
116
|
+
Datadog::Tracer.log.debug(e.message)
|
38
117
|
end
|
118
|
+
|
119
|
+
# execute the original function anyway
|
120
|
+
render_partial_without_datadog(*args)
|
39
121
|
end
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
122
|
+
|
123
|
+
# method aliasing to patch the class
|
124
|
+
alias_method :render_without_datadog, :render
|
125
|
+
alias_method :render, :render_with_datadog
|
126
|
+
alias_method :render_partial_without_datadog, :render_partial
|
127
|
+
alias_method :render_partial, :render_partial_with_datadog
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# RailsActionPatcher contains functions to patch Rails action controller instrumentation
|
133
|
+
module RailsActionPatcher
|
134
|
+
module_function
|
135
|
+
|
136
|
+
def patch_action_controller
|
137
|
+
patch_process_action
|
138
|
+
end
|
139
|
+
|
140
|
+
def patch_process_action
|
141
|
+
::ActionController::Instrumentation.class_eval do
|
142
|
+
def process_action_with_datadog(*args)
|
143
|
+
# mutable payload with a tracing context that is used in two different
|
144
|
+
# signals; it propagates the request span so that it can be finished
|
145
|
+
# no matter what
|
146
|
+
raw_payload = {
|
147
|
+
controller: self.class.name,
|
148
|
+
action: action_name,
|
149
|
+
tracing_context: {}
|
150
|
+
}
|
151
|
+
|
152
|
+
# emits two different signals that start and finish the trace; this approach
|
153
|
+
# mimics the original behavior that is available since Rails 3.0:
|
154
|
+
# - https://github.com/rails/rails/blob/3-0-stable/actionpack/lib/action_controller/metal/instrumentation.rb#L17-L35
|
155
|
+
# - https://github.com/rails/rails/blob/5-1-stable/actionpack/lib/action_controller/metal/instrumentation.rb#L17-L39
|
156
|
+
ActiveSupport::Notifications.instrument('!datadog.start_processing.action_controller', raw_payload)
|
157
|
+
|
158
|
+
# process the request and finish the trace
|
159
|
+
ActiveSupport::Notifications.instrument('!datadog.finish_processing.action_controller', raw_payload) do |payload|
|
160
|
+
result = process_action_without_datadog(*args)
|
161
|
+
payload[:status] = response.status
|
162
|
+
result
|
46
163
|
end
|
47
164
|
end
|
165
|
+
|
166
|
+
alias_method :process_action_without_datadog, :process_action
|
167
|
+
alias_method :process_action, :process_action_with_datadog
|
48
168
|
end
|
49
169
|
end
|
50
170
|
end
|
@@ -58,7 +178,6 @@ module Datadog
|
|
58
178
|
patch_cache_store_fetch
|
59
179
|
patch_cache_store_write
|
60
180
|
patch_cache_store_delete
|
61
|
-
patch_cache_store_instrument
|
62
181
|
end
|
63
182
|
|
64
183
|
def cache_store_class(k)
|
@@ -81,8 +200,17 @@ module Datadog
|
|
81
200
|
cache_store_class(:read).class_eval do
|
82
201
|
alias_method :read_without_datadog, :read
|
83
202
|
def read(*args, &block)
|
84
|
-
|
85
|
-
|
203
|
+
raw_payload = {
|
204
|
+
action: 'GET',
|
205
|
+
key: args[0],
|
206
|
+
tracing_context: {}
|
207
|
+
}
|
208
|
+
|
209
|
+
ActiveSupport::Notifications.instrument('!datadog.start_cache_tracing.active_support', raw_payload)
|
210
|
+
|
211
|
+
ActiveSupport::Notifications.instrument('!datadog.finish_cache_tracing.active_support', raw_payload) do
|
212
|
+
read_without_datadog(*args, &block)
|
213
|
+
end
|
86
214
|
end
|
87
215
|
end
|
88
216
|
end
|
@@ -91,8 +219,17 @@ module Datadog
|
|
91
219
|
cache_store_class(:fetch).class_eval do
|
92
220
|
alias_method :fetch_without_datadog, :fetch
|
93
221
|
def fetch(*args, &block)
|
94
|
-
|
95
|
-
|
222
|
+
raw_payload = {
|
223
|
+
action: 'GET',
|
224
|
+
key: args[0],
|
225
|
+
tracing_context: {}
|
226
|
+
}
|
227
|
+
|
228
|
+
ActiveSupport::Notifications.instrument('!datadog.start_cache_tracing.active_support', raw_payload)
|
229
|
+
|
230
|
+
ActiveSupport::Notifications.instrument('!datadog.finish_cache_tracing.active_support', raw_payload) do
|
231
|
+
fetch_without_datadog(*args, &block)
|
232
|
+
end
|
96
233
|
end
|
97
234
|
end
|
98
235
|
end
|
@@ -101,8 +238,17 @@ module Datadog
|
|
101
238
|
cache_store_class(:write).class_eval do
|
102
239
|
alias_method :write_without_datadog, :write
|
103
240
|
def write(*args, &block)
|
104
|
-
|
105
|
-
|
241
|
+
raw_payload = {
|
242
|
+
action: 'SET',
|
243
|
+
key: args[0],
|
244
|
+
tracing_context: {}
|
245
|
+
}
|
246
|
+
|
247
|
+
ActiveSupport::Notifications.instrument('!datadog.start_cache_tracing.active_support', raw_payload)
|
248
|
+
|
249
|
+
ActiveSupport::Notifications.instrument('!datadog.finish_cache_tracing.active_support', raw_payload) do
|
250
|
+
write_without_datadog(*args, &block)
|
251
|
+
end
|
106
252
|
end
|
107
253
|
end
|
108
254
|
end
|
@@ -111,25 +257,17 @@ module Datadog
|
|
111
257
|
cache_store_class(:delete).class_eval do
|
112
258
|
alias_method :delete_without_datadog, :delete
|
113
259
|
def delete(*args, &block)
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
260
|
+
raw_payload = {
|
261
|
+
action: 'DELETE',
|
262
|
+
key: args[0],
|
263
|
+
tracing_context: {}
|
264
|
+
}
|
119
265
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
# More details: https://github.com/rails/rails/blob/v3.2.22.5/activesupport/lib/active_support/cache.rb#L175-L177
|
126
|
-
return unless ::Rails::VERSION::MAJOR.to_i == 3
|
127
|
-
::ActiveSupport::Cache::Store.singleton_class.class_eval do
|
128
|
-
# Add the instrument function that Rails 3.x uses
|
129
|
-
# to know if the underlying cache should be instrumented or not. By default,
|
130
|
-
# we force that instrumentation if the Rails application is auto instrumented.
|
131
|
-
def instrument
|
132
|
-
true
|
266
|
+
ActiveSupport::Notifications.instrument('!datadog.start_cache_tracing.active_support', raw_payload)
|
267
|
+
|
268
|
+
ActiveSupport::Notifications.instrument('!datadog.finish_cache_tracing.active_support', raw_payload) do
|
269
|
+
delete_without_datadog(*args, &block)
|
270
|
+
end
|
133
271
|
end
|
134
272
|
end
|
135
273
|
end
|
@@ -11,18 +11,16 @@ module Datadog
|
|
11
11
|
module_function
|
12
12
|
|
13
13
|
def format_arg(arg)
|
14
|
-
|
15
|
-
|
16
|
-
a
|
14
|
+
str = arg.to_s
|
15
|
+
Utils.truncate(str, VALUE_MAX_LEN, TOO_LONG_MARK)
|
17
16
|
rescue StandardError => e
|
18
|
-
Datadog::Tracer.log.debug("non formattable Redis arg #{
|
17
|
+
Datadog::Tracer.log.debug("non formattable Redis arg #{str}: #{e}")
|
19
18
|
PLACEHOLDER
|
20
19
|
end
|
21
20
|
|
22
21
|
def format_command_args(command_args)
|
23
22
|
cmd = command_args.map { |x| format_arg(x) }.join(' ')
|
24
|
-
cmd
|
25
|
-
cmd
|
23
|
+
Utils.truncate(cmd, CMD_MAX_LEN, TOO_LONG_MARK)
|
26
24
|
end
|
27
25
|
end
|
28
26
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Datadog
|
2
|
+
module Contrib
|
3
|
+
module Resque
|
4
|
+
SERVICE = 'resque'.freeze
|
5
|
+
|
6
|
+
# Patcher for Resque integration - sets up the pin for the integration
|
7
|
+
module Patcher
|
8
|
+
@patched = false
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def patch
|
12
|
+
return @patched if patched? || !defined?(::Resque)
|
13
|
+
|
14
|
+
require 'ddtrace/ext/app_types'
|
15
|
+
|
16
|
+
add_pin
|
17
|
+
@patched = true
|
18
|
+
rescue => e
|
19
|
+
Tracer.log.error("Unable to apply Resque integration: #{e}")
|
20
|
+
@patched
|
21
|
+
end
|
22
|
+
|
23
|
+
def patched?
|
24
|
+
@patched
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def add_pin
|
30
|
+
Pin.new(SERVICE, app_type: Ext::AppTypes::WORKER).tap do |pin|
|
31
|
+
pin.onto(::Resque)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'ddtrace/ext/app_types'
|
2
|
+
require 'resque'
|
3
|
+
|
4
|
+
module Datadog
|
5
|
+
module Contrib
|
6
|
+
module Resque
|
7
|
+
# Uses Resque job hooks to create traces
|
8
|
+
module ResqueJob
|
9
|
+
def around_perform(*args)
|
10
|
+
pin = Pin.get_from(::Resque)
|
11
|
+
pin.tracer.trace('resque.job', service: pin.service) do |span|
|
12
|
+
span.resource = name
|
13
|
+
span.span_type = pin.app_type
|
14
|
+
yield
|
15
|
+
span.service = pin.service
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def after_perform(*args)
|
20
|
+
pin = Pin.get_from(::Resque)
|
21
|
+
pin.tracer.shutdown!
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
Resque.before_first_fork do
|
29
|
+
pin = Datadog::Pin.get_from(Resque)
|
30
|
+
pin.tracer.set_service_info(pin.service, 'resque', Datadog::Ext::AppTypes::WORKER)
|
31
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'sucker_punch'
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module Contrib
|
5
|
+
module SuckerPunch
|
6
|
+
# Patches `sucker_punch` exception handling
|
7
|
+
module ExceptionHandler
|
8
|
+
METHOD = ->(e, *) { raise(e) }
|
9
|
+
|
10
|
+
module_function
|
11
|
+
|
12
|
+
def patch!
|
13
|
+
::SuckerPunch.class_eval do
|
14
|
+
class << self
|
15
|
+
alias_method :__exception_handler, :exception_handler
|
16
|
+
|
17
|
+
def exception_handler
|
18
|
+
::Datadog::Contrib::SuckerPunch::ExceptionHandler::METHOD
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'sucker_punch'
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module Contrib
|
5
|
+
module SuckerPunch
|
6
|
+
# Defines instrumentation patches for the `sucker_punch` gem
|
7
|
+
module Instrumentation
|
8
|
+
module_function
|
9
|
+
|
10
|
+
# rubocop:disable Metrics/MethodLength
|
11
|
+
def patch!
|
12
|
+
::SuckerPunch::Job::ClassMethods.class_eval do
|
13
|
+
alias_method :__run_perform_without_datadog, :__run_perform
|
14
|
+
def __run_perform(*args)
|
15
|
+
pin = Datadog::Pin.get_from(::SuckerPunch)
|
16
|
+
pin.tracer.provider.context = Datadog::Context.new
|
17
|
+
|
18
|
+
__with_instrumentation('sucker_punch.perform') do |span|
|
19
|
+
span.resource = "PROCESS #{self}"
|
20
|
+
__run_perform_without_datadog(*args)
|
21
|
+
end
|
22
|
+
rescue => e
|
23
|
+
::SuckerPunch.__exception_handler.call(e, self, args)
|
24
|
+
end
|
25
|
+
|
26
|
+
alias_method :__perform_async, :perform_async
|
27
|
+
def perform_async(*args)
|
28
|
+
__with_instrumentation('sucker_punch.perform_async') do |span|
|
29
|
+
span.resource = "ENQUEUE #{self}"
|
30
|
+
__perform_async(*args)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
alias_method :__perform_in, :perform_in
|
35
|
+
def perform_in(interval, *args)
|
36
|
+
__with_instrumentation('sucker_punch.perform_in') do |span|
|
37
|
+
span.resource = "ENQUEUE #{self}"
|
38
|
+
span.set_tag('sucker_punch.perform_in', interval)
|
39
|
+
__perform_in(interval, *args)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def __with_instrumentation(name)
|
46
|
+
pin = Datadog::Pin.get_from(::SuckerPunch)
|
47
|
+
|
48
|
+
pin.tracer.trace(name) do |span|
|
49
|
+
span.service = pin.service
|
50
|
+
span.span_type = pin.app_type
|
51
|
+
span.set_tag('sucker_punch.queue', to_s)
|
52
|
+
yield span
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|