ddtrace 0.11.2 → 0.11.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -37,6 +37,10 @@ module Datadog
37
37
  request_span = tracer.trace('rack.request', trace_options)
38
38
  env[:datadog_rack_request_span] = request_span
39
39
 
40
+ # Copy the original env, before the rest of the stack executes.
41
+ # Values may change; we want values before that happens.
42
+ original_env = env.dup
43
+
40
44
  # call the rest of the stack
41
45
  status, headers, response = @app.call(env)
42
46
  [status, headers, response]
@@ -60,7 +64,7 @@ module Datadog
60
64
  # the result for this request; `resource` and `tags` are expected to
61
65
  # be set in another level but if they're missing, reasonable defaults
62
66
  # are used.
63
- set_request_tags!(request_span, env, status, headers, response)
67
+ set_request_tags!(request_span, env, status, headers, response, original_env)
64
68
 
65
69
  # ensure the request_span is finished and the context reset;
66
70
  # this assumes that the Rack middleware creates a root span
@@ -80,13 +84,20 @@ module Datadog
80
84
  end
81
85
  end
82
86
 
83
- def set_request_tags!(request_span, env, status, headers, response)
84
- # the source of truth in Rack is the PATH_INFO key that holds the
85
- # URL for the current request; some framework may override that
86
- # value, especially during exception handling and because of that
87
- # we prefer using the `REQUEST_URI` if this is available.
88
- # NOTE: `REQUEST_URI` is Rails specific and may not apply for other frameworks
89
- url = env['REQUEST_URI'] || env['PATH_INFO']
87
+ def set_request_tags!(request_span, env, status, headers, response, original_env)
88
+ # http://www.rubydoc.info/github/rack/rack/file/SPEC
89
+ # The source of truth in Rack is the PATH_INFO key that holds the
90
+ # URL for the current request; but some frameworks may override that
91
+ # value, especially during exception handling.
92
+ #
93
+ # Because of this, we prefer to use REQUEST_URI, if available, which is the
94
+ # relative path + query string, and doesn't mutate.
95
+ #
96
+ # REQUEST_URI is only available depending on what web server is running though.
97
+ # So when its not available, we want the original, unmutated PATH_INFO, which
98
+ # is just the relative path without query strings.
99
+ url = env['REQUEST_URI'] || original_env['PATH_INFO']
100
+ request_id = get_request_id(headers, env)
90
101
 
91
102
  request_span.resource ||= resource_name_for(env, status)
92
103
  if request_span.get_tag(Datadog::Ext::HTTP::METHOD).nil?
@@ -110,6 +121,9 @@ module Datadog
110
121
  if request_span.get_tag(Datadog::Ext::HTTP::STATUS_CODE).nil? && status
111
122
  request_span.set_tag(Datadog::Ext::HTTP::STATUS_CODE, status)
112
123
  end
124
+ if request_span.get_tag(Datadog::Ext::HTTP::REQUEST_ID).nil? && request_id
125
+ request_span.set_tag(Datadog::Ext::HTTP::REQUEST_ID, request_id)
126
+ end
113
127
 
114
128
  # detect if the status code is a 5xx and flag the request span as an error
115
129
  # unless it has been already set by the underlying framework
@@ -117,6 +131,14 @@ module Datadog
117
131
  request_span.status = 1
118
132
  end
119
133
  end
134
+
135
+ # If Rails is present, it will sanitize & use the Request ID header,
136
+ # or generate a UUID if no request ID header is present, then set that as headers['X-Request-Id'].
137
+ # Othewise use whatever Rack variables are present (they should all be the same.)
138
+ def get_request_id(headers, env)
139
+ headers ||= {}
140
+ headers['X-Request-Id'] || headers['X-Request-ID'] || env['HTTP_X_REQUEST_ID']
141
+ end
120
142
  end
121
143
  end
122
144
  end
@@ -6,9 +6,13 @@ module Datadog
6
6
  module Rails
7
7
  # Code used to create and handle 'rails.action_controller' spans.
8
8
  module ActionController
9
+ include Datadog::Patcher
10
+
9
11
  def self.instrument
10
12
  # patch Rails core components
11
- Datadog::RailsActionPatcher.patch_action_controller
13
+ do_once(:instrument) do
14
+ Datadog::RailsActionPatcher.patch_action_controller
15
+ end
12
16
  end
13
17
 
14
18
  def self.start_processing(payload)
@@ -46,20 +50,14 @@ module Datadog
46
50
  span.set_tag('rails.route.action', payload.fetch(:action))
47
51
  span.set_tag('rails.route.controller', payload.fetch(:controller))
48
52
 
49
- if payload[:exception].nil?
53
+ exception = payload[:exception_object]
54
+ if exception.nil?
50
55
  # [christian] in some cases :status is not defined,
51
56
  # rather than firing an error, simply acknowledge we don't know it.
52
57
  status = payload.fetch(:status, '?').to_s
53
58
  span.status = 1 if status.starts_with?('5')
54
- else
55
- error = payload[:exception]
56
- if defined?(::ActionDispatch::ExceptionWrapper)
57
- status = ::ActionDispatch::ExceptionWrapper.status_code_for_exception(error[0])
58
- status = status ? status.to_s : '?'
59
- else
60
- status = '500'
61
- end
62
- span.set_error(error) if status.starts_with?('5')
59
+ elsif Utils.exception_is_error?(exception)
60
+ span.set_error(exception)
63
61
  end
64
62
  ensure
65
63
  span.finish()
@@ -5,9 +5,13 @@ module Datadog
5
5
  module Rails
6
6
  # Code used to create and handle 'rails.render_template' and 'rails.render_partial' spans.
7
7
  module ActionView
8
+ include Datadog::Patcher
9
+
8
10
  def self.instrument
9
11
  # patch Rails core components
10
- Datadog::RailsRendererPatcher.patch_renderer
12
+ do_once(:instrument) do
13
+ Datadog::RailsRendererPatcher.patch_renderer
14
+ end
11
15
  end
12
16
 
13
17
  def self.start_render_template(payload)
@@ -7,13 +7,17 @@ module Datadog
7
7
  module Rails
8
8
  # Code used to create and handle 'mysql.query', 'postgres.query', ... spans.
9
9
  module ActiveRecord
10
+ include Datadog::Patcher
11
+
10
12
  def self.instrument
11
13
  # ActiveRecord is instrumented only if it's available
12
14
  return unless defined?(::ActiveRecord)
13
15
 
14
- # subscribe when the active record query has been processed
15
- ::ActiveSupport::Notifications.subscribe('sql.active_record') do |*args|
16
- sql(*args)
16
+ do_once(:instrument) do
17
+ # subscribe when the active record query has been processed
18
+ ::ActiveSupport::Notifications.subscribe('sql.active_record') do |*args|
19
+ sql(*args)
20
+ end
17
21
  end
18
22
  end
19
23
 
@@ -6,9 +6,13 @@ module Datadog
6
6
  module Rails
7
7
  # Code used to create and handle 'rails.cache' spans.
8
8
  module ActiveSupport
9
+ include Datadog::Patcher
10
+
9
11
  def self.instrument
10
- # patch Rails core components
11
- Datadog::RailsCachePatcher.patch_cache_store
12
+ do_once(:instrument) do
13
+ # patch Rails core components
14
+ Datadog::RailsCachePatcher.patch_cache_store
15
+ end
12
16
  end
13
17
 
14
18
  def self.start_trace_cache(payload)
@@ -4,193 +4,211 @@ module Datadog
4
4
  # rubocop:disable Metrics/MethodLength
5
5
  # rubocop:disable Metrics/ModuleLength
6
6
  module RailsRendererPatcher
7
+ include Datadog::Patcher
8
+
7
9
  module_function
8
10
 
9
11
  def patch_renderer
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')
12
+ do_once(:patch_renderer) do
13
+ if defined?(::ActionView::TemplateRenderer) && defined?(::ActionView::PartialRenderer)
14
+ patch_template_renderer(::ActionView::TemplateRenderer)
15
+ patch_partial_renderer(::ActionView::PartialRenderer)
16
+ elsif defined?(::ActionView::Rendering) && defined?(::ActionView::Partials::PartialRenderer)
17
+ # NOTE: Rails < 3.1 compatibility: different classes are used
18
+ patch_template_renderer(::ActionView::Rendering)
19
+ patch_partial_renderer(::ActionView::Partials::PartialRenderer)
20
+ else
21
+ Datadog::Tracer.log.debug('Expected Template/Partial classes not found; template rendering disabled')
22
+ end
19
23
  end
20
24
  end
21
25
 
22
26
  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
- Datadog::Contrib::Rails::ActionView.start_render_template(tracing_context: @tracing_context)
27
+ do_once(:patch_template_renderer) do
28
+ klass.class_eval do
29
+ def render_with_datadog(*args, &block)
30
+ # create a tracing context and start the rendering span
31
+ # NOTE: Rails < 3.1 compatibility: preserve the tracing
32
+ # context when a partial is rendered
33
+ @tracing_context ||= {}
34
+ if @tracing_context.empty?
35
+ Datadog::Contrib::Rails::ActionView.start_render_template(tracing_context: @tracing_context)
36
+ end
37
+
38
+ render_without_datadog(*args, &block)
39
+ rescue Exception => e
40
+ # attach the exception to the tracing context if any
41
+ @tracing_context[:exception] = e
42
+ raise e
43
+ ensure
44
+ # ensure that the template `Span` is finished even during exceptions
45
+ Datadog::Contrib::Rails::ActionView.finish_render_template(tracing_context: @tracing_context)
31
46
  end
32
47
 
33
- render_without_datadog(*args)
34
- rescue Exception => e
35
- # attach the exception to the tracing context if any
36
- @tracing_context[:exception] = e
37
- raise e
38
- ensure
39
- # ensure that the template `Span` is finished even during exceptions
40
- Datadog::Contrib::Rails::ActionView.finish_render_template(tracing_context: @tracing_context)
41
- end
42
-
43
- def render_template_with_datadog(*args)
44
- begin
45
- # arguments based on render_template signature (stable since Rails 3.2)
46
- template = args[0]
47
- layout_name = args[1]
48
-
49
- # update the tracing context with computed values before the rendering
50
- template_name = template.try('identifier')
51
- template_name = Datadog::Contrib::Rails::Utils.normalize_template_name(template_name)
52
- layout = if layout_name.is_a?(String)
53
- # NOTE: Rails < 3.1 compatibility: the second argument is the layout name
54
- layout_name
55
- else
56
- layout_name.try(:[], 'virtual_path')
57
- end
58
- @tracing_context[:template_name] = template_name
59
- @tracing_context[:layout] = layout
60
- rescue StandardError => e
61
- Datadog::Tracer.log.debug(e.message)
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)
67
+ end
68
+
69
+ # execute the original function anyway
70
+ render_template_without_datadog(*args)
62
71
  end
63
72
 
64
- # execute the original function anyway
65
- render_template_without_datadog(*args)
66
- end
73
+ # method aliasing to patch the class
74
+ alias_method :render_without_datadog, :render
75
+ alias_method :render, :render_with_datadog
67
76
 
68
- # method aliasing to patch the class
69
- alias_method :render_without_datadog, :render
70
- alias_method :render, :render_with_datadog
71
-
72
- if klass.private_method_defined?(:render_template) || klass.method_defined?(:render_template)
73
- alias_method :render_template_without_datadog, :render_template
74
- alias_method :render_template, :render_template_with_datadog
75
- else
76
- # NOTE: Rails < 3.1 compatibility: the method name is different
77
- alias_method :render_template_without_datadog, :_render_template
78
- alias_method :_render_template, :render_template_with_datadog
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
84
+ end
79
85
  end
80
86
  end
81
87
  end
82
88
 
83
89
  def patch_partial_renderer(klass)
84
- klass.class_eval do
85
- def render_with_datadog(*args, &block)
86
- # Create a tracing context and start the rendering span
87
- tracing_context = {}
88
- Datadog::Contrib::Rails::ActionView.start_render_partial(tracing_context: tracing_context)
89
- tracing_contexts[current_span_id] = tracing_context
90
-
91
- render_without_datadog(*args)
92
- rescue Exception => e
93
- # attach the exception to the tracing context if any
94
- tracing_contexts[current_span_id][:exception] = e
95
- raise e
96
- ensure
97
- # Ensure that the template `Span` is finished even during exceptions
98
- # Remove the existing tracing context (to avoid leaks)
99
- tracing_contexts.delete(current_span_id)
100
-
101
- # Then finish the span associated with the context
102
- Datadog::Contrib::Rails::ActionView.finish_render_partial(tracing_context: tracing_context)
103
- end
90
+ do_once(:patch_partial_renderer) do
91
+ klass.class_eval do
92
+ def render_with_datadog(*args, &block)
93
+ # Create a tracing context and start the rendering span
94
+ tracing_context = {}
95
+ Datadog::Contrib::Rails::ActionView.start_render_partial(tracing_context: tracing_context)
96
+ tracing_contexts[current_span_id] = tracing_context
97
+
98
+ render_without_datadog(*args)
99
+ rescue Exception => e
100
+ # attach the exception to the tracing context if any
101
+ tracing_contexts[current_span_id][:exception] = e
102
+ raise e
103
+ ensure
104
+ # Ensure that the template `Span` is finished even during exceptions
105
+ # Remove the existing tracing context (to avoid leaks)
106
+ tracing_contexts.delete(current_span_id)
104
107
 
105
- def render_partial_with_datadog(*args)
106
- begin
107
- # update the tracing context with computed values before the rendering
108
- template_name = Datadog::Contrib::Rails::Utils.normalize_template_name(@template.try('identifier'))
109
- tracing_contexts[current_span_id][:template_name] = template_name
110
- rescue StandardError => e
111
- Datadog::Tracer.log.debug(e.message)
108
+ # Then finish the span associated with the context
109
+ Datadog::Contrib::Rails::ActionView.finish_render_partial(tracing_context: tracing_context)
112
110
  end
113
111
 
114
- # execute the original function anyway
115
- render_partial_without_datadog(*args)
116
- end
112
+ def render_partial_with_datadog(*args)
113
+ begin
114
+ # update the tracing context with computed values before the rendering
115
+ template_name = Datadog::Contrib::Rails::Utils.normalize_template_name(@template.try('identifier'))
116
+ tracing_contexts[current_span_id][:template_name] = template_name
117
+ rescue StandardError => e
118
+ Datadog::Tracer.log.debug(e.message)
119
+ end
120
+
121
+ # execute the original function anyway
122
+ render_partial_without_datadog(*args)
123
+ end
117
124
 
118
- # Table of tracing contexts, one per partial/span, keyed by span_id
119
- # because there will be multiple concurrent contexts, depending on how
120
- # many partials are nested within one another.
121
- def tracing_contexts
122
- @tracing_contexts ||= {}
123
- end
125
+ # Table of tracing contexts, one per partial/span, keyed by span_id
126
+ # because there will be multiple concurrent contexts, depending on how
127
+ # many partials are nested within one another.
128
+ def tracing_contexts
129
+ @tracing_contexts ||= {}
130
+ end
124
131
 
125
- def current_span_id
126
- Datadog.configuration[:rails][:tracer].call_context.current_span.span_id
127
- end
132
+ def current_span_id
133
+ Datadog.configuration[:rails][:tracer].call_context.current_span.span_id
134
+ end
128
135
 
129
- # method aliasing to patch the class
130
- alias_method :render_without_datadog, :render
131
- alias_method :render, :render_with_datadog
132
- alias_method :render_partial_without_datadog, :render_partial
133
- alias_method :render_partial, :render_partial_with_datadog
136
+ # method aliasing to patch the class
137
+ alias_method :render_without_datadog, :render
138
+ alias_method :render, :render_with_datadog
139
+ alias_method :render_partial_without_datadog, :render_partial
140
+ alias_method :render_partial, :render_partial_with_datadog
141
+ end
134
142
  end
135
143
  end
136
144
  end
137
145
 
138
146
  # RailsActionPatcher contains functions to patch Rails action controller instrumentation
139
147
  module RailsActionPatcher
148
+ include Datadog::Patcher
149
+
140
150
  module_function
141
151
 
142
152
  def patch_action_controller
143
- patch_process_action
153
+ do_once(:patch_action_controller) do
154
+ patch_process_action
155
+ end
144
156
  end
145
157
 
146
158
  def patch_process_action
147
- ::ActionController::Instrumentation.class_eval do
148
- def process_action_with_datadog(*args)
149
- # mutable payload with a tracing context that is used in two different
150
- # signals; it propagates the request span so that it can be finished
151
- # no matter what
152
- payload = {
153
- controller: self.class,
154
- action: action_name,
155
- headers: {
156
- # The exception this controller was given in the request,
157
- # which is typical if the controller is configured to handle exceptions.
158
- request_exception: request.headers['action_dispatch.exception']
159
- },
160
- tracing_context: {}
161
- }
162
-
163
- begin
164
- # process and catch request exceptions
165
- Datadog::Contrib::Rails::ActionController.start_processing(payload)
166
- result = process_action_without_datadog(*args)
167
- payload[:status] = response.status
168
- result
169
- rescue Exception => e
170
- payload[:exception] = [e.class.name, e.message]
171
- payload[:exception_object] = e
172
- raise e
159
+ do_once(:patch_process_action) do
160
+ ::ActionController::Instrumentation.class_eval do
161
+ def process_action_with_datadog(*args)
162
+ # mutable payload with a tracing context that is used in two different
163
+ # signals; it propagates the request span so that it can be finished
164
+ # no matter what
165
+ payload = {
166
+ controller: self.class,
167
+ action: action_name,
168
+ headers: {
169
+ # The exception this controller was given in the request,
170
+ # which is typical if the controller is configured to handle exceptions.
171
+ request_exception: request.headers['action_dispatch.exception']
172
+ },
173
+ tracing_context: {}
174
+ }
175
+
176
+ begin
177
+ # process and catch request exceptions
178
+ Datadog::Contrib::Rails::ActionController.start_processing(payload)
179
+ result = process_action_without_datadog(*args)
180
+ payload[:status] = response.status
181
+ result
182
+ rescue Exception => e
183
+ payload[:exception] = [e.class.name, e.message]
184
+ payload[:exception_object] = e
185
+ raise e
186
+ end
187
+ ensure
188
+ Datadog::Contrib::Rails::ActionController.finish_processing(payload)
173
189
  end
174
- ensure
175
- Datadog::Contrib::Rails::ActionController.finish_processing(payload)
176
- end
177
190
 
178
- alias_method :process_action_without_datadog, :process_action
179
- alias_method :process_action, :process_action_with_datadog
191
+ alias_method :process_action_without_datadog, :process_action
192
+ alias_method :process_action, :process_action_with_datadog
193
+ end
180
194
  end
181
195
  end
182
196
  end
183
197
 
184
198
  # RailsCachePatcher contains function to patch Rails caching libraries.
185
199
  module RailsCachePatcher
200
+ include Datadog::Patcher
201
+
186
202
  module_function
187
203
 
188
204
  def patch_cache_store
189
- patch_cache_store_read
190
- patch_cache_store_fetch
191
- patch_cache_store_write
192
- patch_cache_store_delete
193
- reload_cache_store
205
+ do_once(:patch_cache_store) do
206
+ patch_cache_store_read
207
+ patch_cache_store_fetch
208
+ patch_cache_store_write
209
+ patch_cache_store_delete
210
+ reload_cache_store
211
+ end
194
212
  end
195
213
 
196
214
  def cache_store_class(k)
@@ -210,107 +228,116 @@ module Datadog
210
228
  end
211
229
 
212
230
  def patch_cache_store_read
213
- cache_store_class(:read).class_eval do
214
- alias_method :read_without_datadog, :read
215
- def read(*args, &block)
216
- payload = {
217
- action: 'GET',
218
- key: args[0],
219
- tracing_context: {}
220
- }
221
-
222
- begin
223
- # process and catch cache exceptions
224
- Datadog::Contrib::Rails::ActiveSupport.start_trace_cache(payload)
225
- read_without_datadog(*args, &block)
226
- rescue Exception => e
227
- payload[:exception] = [e.class.name, e.message]
228
- payload[:exception_object] = e
229
- raise e
231
+ do_once(:patch_cache_store_read) do
232
+ cache_store_class(:read).class_eval do
233
+ alias_method :read_without_datadog, :read
234
+ def read(*args, &block)
235
+ payload = {
236
+ action: 'GET',
237
+ key: args[0],
238
+ tracing_context: {}
239
+ }
240
+
241
+ begin
242
+ # process and catch cache exceptions
243
+ Datadog::Contrib::Rails::ActiveSupport.start_trace_cache(payload)
244
+ read_without_datadog(*args, &block)
245
+ rescue Exception => e
246
+ payload[:exception] = [e.class.name, e.message]
247
+ payload[:exception_object] = e
248
+ raise e
249
+ end
250
+ ensure
251
+ Datadog::Contrib::Rails::ActiveSupport.finish_trace_cache(payload)
230
252
  end
231
- ensure
232
- Datadog::Contrib::Rails::ActiveSupport.finish_trace_cache(payload)
233
253
  end
234
254
  end
235
255
  end
236
256
 
237
257
  def patch_cache_store_fetch
238
- cache_store_class(:fetch).class_eval do
239
- alias_method :fetch_without_datadog, :fetch
240
- def fetch(*args, &block)
241
- payload = {
242
- action: 'GET',
243
- key: args[0],
244
- tracing_context: {}
245
- }
246
-
247
- begin
248
- # process and catch cache exceptions
249
- Datadog::Contrib::Rails::ActiveSupport.start_trace_cache(payload)
250
- fetch_without_datadog(*args, &block)
251
- rescue Exception => e
252
- payload[:exception] = [e.class.name, e.message]
253
- payload[:exception_object] = e
254
- raise e
258
+ do_once(:patch_cache_store_fetch) do
259
+ cache_store_class(:fetch).class_eval do
260
+ alias_method :fetch_without_datadog, :fetch
261
+ def fetch(*args, &block)
262
+ payload = {
263
+ action: 'GET',
264
+ key: args[0],
265
+ tracing_context: {}
266
+ }
267
+
268
+ begin
269
+ # process and catch cache exceptions
270
+ Datadog::Contrib::Rails::ActiveSupport.start_trace_cache(payload)
271
+ fetch_without_datadog(*args, &block)
272
+ rescue Exception => e
273
+ payload[:exception] = [e.class.name, e.message]
274
+ payload[:exception_object] = e
275
+ raise e
276
+ end
277
+ ensure
278
+ Datadog::Contrib::Rails::ActiveSupport.finish_trace_cache(payload)
255
279
  end
256
- ensure
257
- Datadog::Contrib::Rails::ActiveSupport.finish_trace_cache(payload)
258
280
  end
259
281
  end
260
282
  end
261
283
 
262
284
  def patch_cache_store_write
263
- cache_store_class(:write).class_eval do
264
- alias_method :write_without_datadog, :write
265
- def write(*args, &block)
266
- payload = {
267
- action: 'SET',
268
- key: args[0],
269
- tracing_context: {}
270
- }
271
-
272
- begin
273
- # process and catch cache exceptions
274
- Datadog::Contrib::Rails::ActiveSupport.start_trace_cache(payload)
275
- write_without_datadog(*args, &block)
276
- rescue Exception => e
277
- payload[:exception] = [e.class.name, e.message]
278
- payload[:exception_object] = e
279
- raise e
285
+ do_once(:patch_cache_store_write) do
286
+ cache_store_class(:write).class_eval do
287
+ alias_method :write_without_datadog, :write
288
+ def write(*args, &block)
289
+ payload = {
290
+ action: 'SET',
291
+ key: args[0],
292
+ tracing_context: {}
293
+ }
294
+
295
+ begin
296
+ # process and catch cache exceptions
297
+ Datadog::Contrib::Rails::ActiveSupport.start_trace_cache(payload)
298
+ write_without_datadog(*args, &block)
299
+ rescue Exception => e
300
+ payload[:exception] = [e.class.name, e.message]
301
+ payload[:exception_object] = e
302
+ raise e
303
+ end
304
+ ensure
305
+ Datadog::Contrib::Rails::ActiveSupport.finish_trace_cache(payload)
280
306
  end
281
- ensure
282
- Datadog::Contrib::Rails::ActiveSupport.finish_trace_cache(payload)
283
307
  end
284
308
  end
285
309
  end
286
310
 
287
311
  def patch_cache_store_delete
288
- cache_store_class(:delete).class_eval do
289
- alias_method :delete_without_datadog, :delete
290
- def delete(*args, &block)
291
- payload = {
292
- action: 'DELETE',
293
- key: args[0],
294
- tracing_context: {}
295
- }
296
-
297
- begin
298
- # process and catch cache exceptions
299
- Datadog::Contrib::Rails::ActiveSupport.start_trace_cache(payload)
300
- delete_without_datadog(*args, &block)
301
- rescue Exception => e
302
- payload[:exception] = [e.class.name, e.message]
303
- payload[:exception_object] = e
304
- raise e
312
+ do_once(:patch_cache_store_delete) do
313
+ cache_store_class(:delete).class_eval do
314
+ alias_method :delete_without_datadog, :delete
315
+ def delete(*args, &block)
316
+ payload = {
317
+ action: 'DELETE',
318
+ key: args[0],
319
+ tracing_context: {}
320
+ }
321
+
322
+ begin
323
+ # process and catch cache exceptions
324
+ Datadog::Contrib::Rails::ActiveSupport.start_trace_cache(payload)
325
+ delete_without_datadog(*args, &block)
326
+ rescue Exception => e
327
+ payload[:exception] = [e.class.name, e.message]
328
+ payload[:exception_object] = e
329
+ raise e
330
+ end
331
+ ensure
332
+ Datadog::Contrib::Rails::ActiveSupport.finish_trace_cache(payload)
305
333
  end
306
- ensure
307
- Datadog::Contrib::Rails::ActiveSupport.finish_trace_cache(payload)
308
334
  end
309
335
  end
310
336
  end
311
337
 
312
338
  def self.reload_cache_store
313
- return unless Datadog.registry[:redis].patched?
339
+ redis = Datadog.registry[:redis]
340
+ return unless redis && redis.patched?
314
341
 
315
342
  return unless defined?(::ActiveSupport::Cache::RedisStore) &&
316
343
  defined?(::Rails.cache) &&