newrelic_rpm 7.2.0 → 8.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/CHANGELOG.md +105 -9
  4. data/README.md +2 -0
  5. data/lib/new_relic/agent/adaptive_sampler.rb +2 -2
  6. data/lib/new_relic/agent/agent.rb +6 -6
  7. data/lib/new_relic/agent/commands/thread_profiler_session.rb +7 -3
  8. data/lib/new_relic/agent/configuration/default_source.rb +15 -7
  9. data/lib/new_relic/agent/configuration/event_harvest_config.rb +28 -12
  10. data/lib/new_relic/agent/configuration/manager.rb +0 -1
  11. data/lib/new_relic/agent/configuration/server_source.rb +3 -2
  12. data/lib/new_relic/agent/configuration/yaml_source.rb +22 -1
  13. data/lib/new_relic/agent/custom_event_aggregator.rb +2 -1
  14. data/lib/new_relic/agent/database.rb +5 -2
  15. data/lib/new_relic/agent/datastores/mongo.rb +5 -10
  16. data/lib/new_relic/agent/datastores.rb +7 -7
  17. data/lib/new_relic/agent/distributed_tracing/cross_app_payload.rb +5 -5
  18. data/lib/new_relic/agent/distributed_tracing/cross_app_tracing.rb +10 -6
  19. data/lib/new_relic/agent/distributed_tracing/distributed_trace_attributes.rb +0 -1
  20. data/lib/new_relic/agent/distributed_tracing/distributed_trace_payload.rb +1 -1
  21. data/lib/new_relic/agent/distributed_tracing/trace_context_payload.rb +1 -1
  22. data/lib/new_relic/agent/event_loop.rb +6 -6
  23. data/lib/new_relic/agent/external.rb +0 -32
  24. data/lib/new_relic/agent/http_clients/abstract.rb +2 -2
  25. data/lib/new_relic/agent/instrumentation/action_controller_subscriber.rb +1 -1
  26. data/lib/new_relic/agent/instrumentation/active_merchant.rb +3 -3
  27. data/lib/new_relic/agent/instrumentation/bunny/instrumentation.rb +1 -1
  28. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +1 -1
  29. data/lib/new_relic/agent/instrumentation/excon.rb +4 -23
  30. data/lib/new_relic/agent/instrumentation/mongo.rb +3 -141
  31. data/lib/new_relic/agent/instrumentation/queue_time.rb +4 -4
  32. data/lib/new_relic/agent/instrumentation/rails/action_controller.rb +5 -5
  33. data/lib/new_relic/agent/instrumentation/rails/action_web_service.rb +1 -1
  34. data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +5 -41
  35. data/lib/new_relic/agent/instrumentation/sidekiq.rb +6 -1
  36. data/lib/new_relic/agent/javascript_instrumentor.rb +3 -3
  37. data/lib/new_relic/agent/messaging.rb +10 -24
  38. data/lib/new_relic/agent/method_tracer.rb +132 -138
  39. data/lib/new_relic/agent/monitors/cross_app_monitor.rb +6 -1
  40. data/lib/new_relic/agent/new_relic_service.rb +9 -9
  41. data/lib/new_relic/agent/pipe_channel_manager.rb +10 -6
  42. data/lib/new_relic/agent/pipe_service.rb +1 -1
  43. data/lib/new_relic/agent/samplers/cpu_sampler.rb +1 -1
  44. data/lib/new_relic/agent/span_event_aggregator.rb +2 -2
  45. data/lib/new_relic/agent/sql_sampler.rb +1 -1
  46. data/lib/new_relic/agent/stats_engine/stats_hash.rb +1 -1
  47. data/lib/new_relic/agent/stats_engine.rb +1 -1
  48. data/lib/new_relic/agent/supported_versions.rb +1 -1
  49. data/lib/new_relic/agent/threading/backtrace_service.rb +4 -5
  50. data/lib/new_relic/agent/threading/thread_profile.rb +1 -1
  51. data/lib/new_relic/agent/tracer.rb +15 -37
  52. data/lib/new_relic/agent/transaction/abstract_segment.rb +3 -3
  53. data/lib/new_relic/agent/transaction/message_broker_segment.rb +5 -11
  54. data/lib/new_relic/agent/transaction.rb +7 -28
  55. data/lib/new_relic/agent/transaction_time_aggregator.rb +5 -5
  56. data/lib/new_relic/agent/vm/snapshot.rb +1 -1
  57. data/lib/new_relic/agent/worker_loop.rb +5 -5
  58. data/lib/new_relic/agent.rb +5 -5
  59. data/lib/new_relic/cli/commands/deployments.rb +2 -2
  60. data/lib/new_relic/constants.rb +0 -4
  61. data/lib/new_relic/noticed_error.rb +2 -2
  62. data/lib/new_relic/version.rb +2 -2
  63. data/lib/newrelic_rpm.rb +10 -34
  64. data/lib/tasks/all.rb +1 -1
  65. data/newrelic.yml +593 -3
  66. data/newrelic_rpm.gemspec +1 -1
  67. data/test/agent_helper.rb +27 -2
  68. metadata +3 -8
  69. data/lib/new_relic/agent/datastores/mongo/statement_formatter.rb +0 -53
  70. data/lib/new_relic/agent/instrumentation/excon/connection.rb +0 -49
  71. data/lib/new_relic/agent/instrumentation/merb/controller.rb +0 -44
  72. data/lib/new_relic/agent/instrumentation/merb/errors.rb +0 -33
  73. data/lib/new_relic/control/frameworks/merb.rb +0 -29
@@ -48,12 +48,12 @@ module NewRelic
48
48
 
49
49
  module MethodTracer
50
50
 
51
- def self.included clazz
52
- clazz.extend ClassMethods
51
+ def self.included(klass)
52
+ klass.extend(ClassMethods)
53
53
  end
54
54
 
55
- def self.extended clazz
56
- clazz.extend ClassMethods
55
+ def self.extended(klass)
56
+ klass.extend(ClassMethods)
57
57
  end
58
58
 
59
59
  # Trace a given block with stats and keep track of the caller.
@@ -69,7 +69,7 @@ module NewRelic
69
69
  # @api public
70
70
  #
71
71
  def trace_execution_scoped(metric_names, options=NewRelic::EMPTY_HASH) #THREAD_LOCAL_ACCESS
72
- NewRelic::Agent.record_api_supportability_metric :trace_execution_scoped
72
+ NewRelic::Agent.record_api_supportability_metric :trace_execution_scoped unless options[:internal]
73
73
  NewRelic::Agent::MethodTracerHelpers.trace_execution_scoped(metric_names, options) do
74
74
  # Using an implicit block avoids object allocation for a &block param
75
75
  yield
@@ -79,19 +79,19 @@ module NewRelic
79
79
  # Trace a given block with stats assigned to the given metric_name. It does not
80
80
  # provide scoped measurements, meaning whatever is being traced will not 'blame the
81
81
  # Controller'--that is to say appear in the breakdown chart.
82
- # This is code is inlined in #add_method_tracer.
82
+ #
83
83
  # * <tt>metric_names</tt> is a single name or an array of names of metrics
84
84
  #
85
85
  # @api public
86
86
  #
87
87
  def trace_execution_unscoped(metric_names, options=NewRelic::EMPTY_HASH) #THREAD_LOCAL_ACCESS
88
- NewRelic::Agent.record_api_supportability_metric :trace_execution_unscoped
88
+ NewRelic::Agent.record_api_supportability_metric :trace_execution_unscoped unless options[:internal]
89
89
  return yield unless NewRelic::Agent.tl_is_execution_traced?
90
- t0 = Time.now
90
+ t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
91
91
  begin
92
92
  yield
93
93
  ensure
94
- duration = (Time.now - t0).to_f # for some reason this is 3 usec faster than Time - Time
94
+ duration = Process.clock_gettime(Process::CLOCK_MONOTONIC) - t0
95
95
  NewRelic::Agent.instance.stats_engine.tl_record_unscoped_metrics(metric_names, duration)
96
96
  end
97
97
  end
@@ -103,50 +103,38 @@ module NewRelic
103
103
  module AddMethodTracer
104
104
  ALLOWED_KEYS = [:metric, :push_scope, :code_header, :code_footer].freeze
105
105
 
106
- # raises an error when the
107
- # NewRelic::Agent::MethodTracer::ClassMethods#add_method_tracer
108
- # method is called with improper keys. This aids in
109
- # debugging new instrumentation by failing fast
110
- def check_for_illegal_keys!(method_name, options)
111
- unrecognized_keys = options.keys - ALLOWED_KEYS
112
-
113
- if unrecognized_keys.any?
114
- raise "Unrecognized options when adding method tracer to #{method_name}: " +
115
- unrecognized_keys.join(', ')
116
- end
117
- end
118
-
119
- # validity checking - add_method_tracer must receive either
120
- # push scope or metric, or else it would record no
121
- # data. Raises an error if this is the case
122
- def check_for_push_scope_and_metric(options)
123
- unless options[:push_scope] || options[:metric]
124
- raise "Can't add a tracer where push_scope is false and metric is false"
125
- end
126
- end
127
-
128
106
  DEFAULT_SETTINGS = {:push_scope => true, :metric => true, :code_header => "", :code_footer => "" }.freeze
129
107
 
130
108
  # Checks the provided options to make sure that they make
131
109
  # sense. Raises an error if the options are incorrect to
132
110
  # assist with debugging, so that errors occur at class
133
111
  # construction time rather than instrumentation run time
134
- def validate_options(method_name, options)
112
+ def _nr_validate_method_tracer_options(method_name, options)
135
113
  unless options.is_a?(Hash)
136
114
  raise TypeError.new("Error adding method tracer to #{method_name}: provided options must be a Hash")
137
115
  end
138
- check_for_illegal_keys!(method_name, options)
116
+
117
+ unrecognized_keys = options.keys - ALLOWED_KEYS
118
+ if unrecognized_keys.any?
119
+ raise "Unrecognized options when adding method tracer to #{method_name}: " +
120
+ unrecognized_keys.join(', ')
121
+ end
122
+
139
123
  options = DEFAULT_SETTINGS.merge(options)
140
- check_for_push_scope_and_metric(options)
124
+ unless options[:push_scope] || options[:metric]
125
+ raise "Can't add a tracer where push_scope is false and metric is false"
126
+ end
127
+
141
128
  options
142
129
  end
143
130
 
144
131
  # Default to the class where the method is defined.
145
132
  #
146
133
  # Example:
147
- # Foo.default_metric_name_code('bar') #=> "Custom/#{Foo.name}/bar"
148
- def default_metric_name_code(method_name)
149
- "Custom/#{derived_class_name}/#{method_name}"
134
+ # Foo._nr_default_metric_name_code('bar') #=> "Custom/#{Foo.name}/bar"
135
+ def _nr_default_metric_name(method_name)
136
+ class_name = _nr_derived_class_name
137
+ -> (*) { "Custom/#{class_name}/#{method_name}" }
150
138
  end
151
139
 
152
140
  # Checks to see if the method we are attempting to trace
@@ -154,7 +142,7 @@ module NewRelic
154
142
  # anything if the method doesn't exist.
155
143
  def newrelic_method_exists?(method_name)
156
144
  exists = method_defined?(method_name) || private_method_defined?(method_name)
157
- ::NewRelic::Agent.logger.error("Did not trace #{derived_class_name}##{method_name} because that method does not exist") unless exists
145
+ ::NewRelic::Agent.logger.error("Did not trace #{_nr_derived_class_name}##{method_name} because that method does not exist") unless exists
158
146
  exists
159
147
  end
160
148
 
@@ -162,67 +150,25 @@ module NewRelic
162
150
  # given metric by checking to see if the traced method
163
151
  # exists. Warns the user if methods are being double-traced
164
152
  # to help with debugging custom instrumentation.
165
- def traced_method_exists?(method_name, metric_name_code)
166
- exists = method_defined?(_traced_method_name(method_name, metric_name_code))
167
- ::NewRelic::Agent.logger.error("Attempt to trace a method twice with the same metric: Method = #{method_name}, Metric Name = #{metric_name_code}") if exists
153
+ def method_traced?(method_name)
154
+ exists = method_name && _nr_traced_method_module.method_defined?(method_name)
155
+ ::NewRelic::Agent.logger.error("Attempt to trace a method twice: Method = #{method_name}") if exists
168
156
  exists
169
157
  end
170
158
 
171
- # Returns a code snippet to be eval'd that skips tracing
172
- # when the agent is not tracing execution. turns
173
- # instrumentation into effectively one method call overhead
174
- # when the agent is disabled
175
- def assemble_code_header(method_name, metric_name_code, options)
176
- header = "return #{_untraced_method_name(method_name, metric_name_code)}(#{ARGS_FOR_RUBY_VERSION}) unless NewRelic::Agent.tl_is_execution_traced?\n"
177
- header += options[:code_header].to_s
178
- header
159
+ # Returns an anonymous module that stores prepended trace methods.
160
+ def _nr_traced_method_module
161
+ @_nr_traced_method_module ||= Module.new
179
162
  end
180
163
 
181
- # returns an eval-able string that contains the traced
182
- # method code used if the agent is not creating a scope for
183
- # use in scoped metrics.
184
- def method_without_push_scope(method_name, metric_name_code, options)
185
- "def #{_traced_method_name(method_name, metric_name_code)}(#{ARGS_FOR_RUBY_VERSION})
186
- #{assemble_code_header(method_name, metric_name_code, options)}
187
- t0 = Time.now
188
- begin
189
- #{_untraced_method_name(method_name, metric_name_code)}(#{ARGS_FOR_RUBY_VERSION})\n
190
- ensure
191
- duration = (Time.now - t0).to_f
192
- NewRelic::Agent.record_metric(\"#{metric_name_code}\", duration)
193
- #{options[:code_footer]}
194
- end
195
- end"
196
- end
197
-
198
- # returns an eval-able string that contains the tracing code
199
- # for a fully traced metric including scoping
200
- def method_with_push_scope(method_name, metric_name_code, options)
201
- "def #{_traced_method_name(method_name, metric_name_code)}(#{ARGS_FOR_RUBY_VERSION})
202
- #{options[:code_header]}
203
- result = ::NewRelic::Agent::MethodTracerHelpers.trace_execution_scoped(\"#{metric_name_code}\",
204
- :metric => #{options[:metric]}) do
205
- #{_untraced_method_name(method_name, metric_name_code)}(#{ARGS_FOR_RUBY_VERSION})
206
- end
207
- #{options[:code_footer]}
208
- result
209
- end"
210
- end
211
-
212
- # Decides which code snippet we should be eval'ing in this
213
- # context, based on the options.
214
- def code_to_eval(method_name, metric_name_code, options)
215
- options = validate_options(method_name, options)
216
- if options[:push_scope]
217
- method_with_push_scope(method_name, metric_name_code, options)
218
- else
219
- method_without_push_scope(method_name, metric_name_code, options)
164
+ # for testing only
165
+ def _nr_clear_traced_methods!
166
+ _nr_traced_method_module.module_eval do
167
+ self.instance_methods.each { |m| remove_method m }
220
168
  end
221
169
  end
222
170
 
223
- private
224
-
225
- def derived_class_name
171
+ def _nr_derived_class_name
226
172
  return self.name if self.name && !self.name.empty?
227
173
  return "AnonymousModule" if self.to_s.start_with?("#<Module:")
228
174
 
@@ -248,22 +194,26 @@ module NewRelic
248
194
  #
249
195
  # === Overriding the metric name
250
196
  #
251
- # +metric_name_code+ is a string that is eval'd to get the name of the
252
- # metric associated with the call, so if you want to use interpolation
253
- # evaluated at call time, then single quote the value like this:
197
+ # +metric_name+ is a String or Proc. If a Proc is given, it is bound to
198
+ # the object that called the traced method. For example:
254
199
  #
255
- # add_method_tracer :foo, 'Custom/#{self.class.name}/foo'
200
+ # add_method_tracer :foo, -> { "Custom/#{self.class.name}/foo" }
256
201
  #
257
202
  # This would name the metric according to the class of the runtime
258
- # intance, as opposed to the class where +foo+ is defined.
203
+ # instance, as opposed to the class where +foo+ is defined.
259
204
  #
260
205
  # If not provided, the metric name will be <tt>Custom/ClassName/method_name</tt>.
261
206
  #
262
- # @param [Symbol] method_name the name of the method to trace
263
- # @param [String] metric_name_code the metric name to record calls to
264
- # the traced method under. This may be either a static string, or Ruby
265
- # code to be evaluated at call-time in order to determine the metric
207
+ # @param method_name [Symbol] the name of the method to trace
208
+ # @param metric_name [String,Proc,Array] the metric name to record calls to
209
+ # the traced method under. This may be either a String, or a Proc
210
+ # to be evaluated at call-time in order to determine the metric
266
211
  # name dynamically.
212
+ # This method also accepts an array of Strings/Procs, in which case the
213
+ # first metric given will be scoped, while the remaining metrics will be
214
+ # recorded as though passed with :push_scope => false. If an Array of
215
+ # metric names is given with :push_scope => false, all metrics will be
216
+ # unscoped.
267
217
  # @param [Hash] options additional options controlling how the method is
268
218
  # traced.
269
219
  # @option options [Boolean] :push_scope (true) If false, the traced method will
@@ -272,16 +222,17 @@ module NewRelic
272
222
  # @option options [Boolean] :metric (true) If false, the traced method will
273
223
  # only appear in transaction traces, but no metrics will be recorded
274
224
  # for it.
275
- # @option options [String] :code_header ('') Ruby code to be inserted and run
225
+ # @option options [Proc] :code_header ('') Ruby code to be inserted and run
276
226
  # before the tracer begins timing.
277
- # @option options [String] :code_footer ('') Ruby code to be inserted and run
227
+ # @option options [Proc] :code_footer ('') Ruby code to be inserted and run
278
228
  # after the tracer stops timing.
279
229
  #
280
230
  # @example
281
231
  # add_method_tracer :foo
282
232
  #
283
233
  # # With a custom metric name
284
- # add_method_tracer :foo, 'Custom/#{self.class.name}/foo'
234
+ # add_method_tracer :foo, "Custom/MyClass/foo"
235
+ # add_method_tracer :bar, -> { "Custom/#{self.class.name}/bar" }
285
236
  #
286
237
  # # Instrument foo only for custom dashboards (not in transaction
287
238
  # # traces or breakdown charts)
@@ -292,65 +243,108 @@ module NewRelic
292
243
  #
293
244
  # @api public
294
245
  #
295
- def add_method_tracer(method_name, metric_name_code = nil, options = {})
296
- ::NewRelic::Agent.add_or_defer_method_tracer(self, method_name, metric_name_code, options)
246
+ def add_method_tracer(method_name, metric_name = nil, options = {})
247
+ ::NewRelic::Agent.add_or_defer_method_tracer(self, method_name, metric_name, options)
297
248
  end
298
249
 
299
250
  # For tests only because tracers must be removed in reverse-order
300
251
  # from when they were added, or else other tracers that were added to the same method
301
252
  # may get removed as well.
302
- def remove_method_tracer(method_name, metric_name_code) # :nodoc:
253
+ def remove_method_tracer(method_name) # :nodoc:
303
254
  return unless Agent.config[:agent_enabled]
304
- if method_defined? "#{_traced_method_name(method_name, metric_name_code)}"
305
- alias_method method_name, "#{_untraced_method_name(method_name, metric_name_code)}"
306
- undef_method "#{_traced_method_name(method_name, metric_name_code)}"
307
- ::NewRelic::Agent.logger.debug("removed method tracer #{method_name} #{metric_name_code}\n")
255
+ if _nr_traced_method_module.method_defined?(method_name)
256
+ _nr_traced_method_module.send(:remove_method, method_name)
257
+ ::NewRelic::Agent.logger.debug("removed method tracer #{method_name}\n")
308
258
  else
309
- raise "No tracer for '#{metric_name_code}' on method '#{method_name}'"
259
+ raise "No tracer on method '#{method_name}'"
310
260
  end
311
261
  end
312
262
 
313
263
  private
314
264
 
315
- def _add_method_tracer_now(method_name, metric_name_code, options)
265
+ def _nr_add_method_tracer_now(method_name, metric_name, options)
316
266
  NewRelic::Agent.record_api_supportability_metric(:add_method_tracer)
317
-
318
267
  return unless newrelic_method_exists?(method_name)
319
- metric_name_code ||= default_metric_name_code(method_name)
320
- return if traced_method_exists?(method_name, metric_name_code)
268
+ remove_method_tracer(method_name) if method_traced?(method_name)
321
269
 
322
- traced_method = code_to_eval(method_name, metric_name_code, options)
270
+ options = _nr_validate_method_tracer_options(method_name, options)
323
271
 
324
272
  visibility = NewRelic::Helper.instance_method_visibility self, method_name
325
273
 
326
- class_eval traced_method, __FILE__, __LINE__
327
- alias_method _untraced_method_name(method_name, metric_name_code), method_name
328
- alias_method method_name, _traced_method_name(method_name, metric_name_code)
329
- ruby2_keywords(_traced_method_name(method_name, metric_name_code)) if respond_to?(:ruby2_keywords, true)
330
- send visibility, method_name
331
- send visibility, _traced_method_name(method_name, metric_name_code)
332
- ::NewRelic::Agent.logger.debug("Traced method: class = #{derived_class_name},"+
274
+ scoped_metric, unscoped_metrics = _nr_scoped_unscoped_metrics(metric_name, method_name, push_scope: options[:push_scope])
275
+
276
+ _nr_define_traced_method(method_name, scoped_metric: scoped_metric, unscoped_metrics: unscoped_metrics,
277
+ code_header: options[:code_header], code_footer: options[:code_footer],
278
+ record_metrics: options[:metric], visibility: visibility)
279
+
280
+ prepend(_nr_traced_method_module)
281
+
282
+ ::NewRelic::Agent.logger.debug("Traced method: class = #{_nr_derived_class_name},"+
333
283
  "method = #{method_name}, "+
334
- "metric = '#{metric_name_code}'")
284
+ "metric = '#{metric_name}'")
335
285
  end
336
286
 
337
- # given a method and a metric, this method returns the
338
- # untraced alias of the method name
339
- def _untraced_method_name(method_name, metric_name)
340
- "#{_sanitize_name(method_name)}_without_trace_#{_sanitize_name(metric_name)}"
287
+ # See #add_method_tracer; if multiple metric names are given, the first is
288
+ # treated as scoped, the rest unscoped. If options[:push_scope] is false,
289
+ # all given metrics are unscoped.
290
+ def _nr_scoped_unscoped_metrics(metric_name, method_name, push_scope: true)
291
+ if metric_name.is_a?(Array) && push_scope
292
+ [metric_name.shift, metric_name]
293
+ elsif push_scope
294
+ [metric_name || _nr_default_metric_name(method_name), []]
295
+ else
296
+ [nil, Array(metric_name)]
297
+ end
341
298
  end
342
299
 
343
- # given a method and a metric, this method returns the traced
344
- # alias of the method name
345
- def _traced_method_name(method_name, metric_name)
346
- "#{_sanitize_name(method_name)}_with_trace_#{_sanitize_name(metric_name)}"
347
- end
300
+ def _nr_define_traced_method(method_name, scoped_metric: nil, unscoped_metrics: [],
301
+ code_header: nil, code_footer: nil, record_metrics: true,
302
+ visibility: :public)
303
+ _nr_traced_method_module.module_eval do
304
+ define_method(method_name) do |*args, &block|
305
+ return super(*args, &block) unless NewRelic::Agent.tl_is_execution_traced?
306
+ scoped_metric_eval, unscoped_metrics_eval = nil, []
307
+
308
+ scoped_metric_eval = case scoped_metric
309
+ when Proc
310
+ instance_exec(*args, &scoped_metric)
311
+ when String
312
+ scoped_metric
313
+ else
314
+ nil
315
+ end
316
+
317
+ unscoped_metrics_eval = unscoped_metrics.map do |metric|
318
+ metric.kind_of?(Proc) ? instance_exec(*args, &metric) : metric.to_s
319
+ end
320
+
321
+ instance_exec(&code_header) if code_header.kind_of?(Proc)
348
322
 
349
- # makes sure that method names do not contain characters that
350
- # might break the interpreter, for example ! or ? characters
351
- # that are not allowed in the middle of method names
352
- def _sanitize_name(name)
353
- name.to_s.tr_s('^a-zA-Z0-9', '_')
323
+ # If tracing multiple metrics on this method, nest one unscoped trace inside the scoped trace.
324
+ begin
325
+ if scoped_metric_eval
326
+ self.class.trace_execution_scoped(scoped_metric_eval, metric: record_metrics, internal: true) do
327
+ if unscoped_metrics_eval.empty?
328
+ super(*args, &block)
329
+ else
330
+ self.class.trace_execution_unscoped(unscoped_metrics_eval, internal: true) do
331
+ super(*args, &block)
332
+ end
333
+ end
334
+ end
335
+ elsif !unscoped_metrics_eval.empty?
336
+ self.class.trace_execution_unscoped(unscoped_metrics_eval, internal: true) do
337
+ super(*args, &block)
338
+ end
339
+ end
340
+ ensure
341
+ instance_exec(&code_footer) if code_footer.kind_of?(Proc)
342
+ end
343
+ end
344
+
345
+ send visibility, method_name
346
+ ruby2_keywords(method_name) if respond_to?(:ruby2_keywords, true)
347
+ end
354
348
  end
355
349
  end
356
350
 
@@ -22,6 +22,11 @@ module NewRelic
22
22
  CONTENT_LENGTH_HEADER_KEY = 'HTTP_CONTENT_LENGTH'.freeze
23
23
 
24
24
  def on_finished_configuring(events)
25
+ Deprecator.deprecate('cross_application_tracer')
26
+ ::NewRelic::Agent.logger.warn(
27
+ "[DEPRECATED] Cross application tracing is enabled. Distributed tracing is replacing cross application tracing as the default means of tracing between services. To continue using cross application tracing, enable it with `cross_application_tracer.enabled: true` and `distributed_tracing.enabled: false`"
28
+ )
29
+
25
30
  register_event_listeners(events)
26
31
  end
27
32
 
@@ -107,4 +112,4 @@ module NewRelic
107
112
  end
108
113
  end
109
114
  end
110
- end
115
+ end
@@ -128,11 +128,11 @@ module NewRelic
128
128
 
129
129
  def metric_data(stats_hash)
130
130
  timeslice_start = stats_hash.started_at
131
- timeslice_end = stats_hash.harvested_at || Time.now
131
+ timeslice_end = stats_hash.harvested_at || Process.clock_gettime(Process::CLOCK_REALTIME)
132
132
  metric_data_array = build_metric_data_array(stats_hash)
133
133
  result = invoke_remote(
134
134
  :metric_data,
135
- [@agent_id, timeslice_start.to_f, timeslice_end.to_f, metric_data_array],
135
+ [@agent_id, timeslice_start, timeslice_end, metric_data_array],
136
136
  :item_count => metric_data_array.size
137
137
  )
138
138
  result
@@ -215,7 +215,7 @@ module NewRelic
215
215
  raise ArgumentError, "#{self.class}#shared_connection must be passed a block" unless block_given?
216
216
 
217
217
  begin
218
- t0 = Time.now
218
+ t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
219
219
  @in_session = true
220
220
  if NewRelic::Agent.config[:aggressive_keepalive]
221
221
  session_with_keepalive(&block)
@@ -223,7 +223,7 @@ module NewRelic
223
223
  session_without_keepalive(&block)
224
224
  end
225
225
  rescue *CONNECTION_ERRORS => e
226
- elapsed = Time.now - t0
226
+ elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - t0
227
227
  raise NewRelic::Agent::ServerConnectionException, "Recoverable error connecting to #{@collector} after #{elapsed} seconds: #{e}"
228
228
  ensure
229
229
  @in_session = false
@@ -412,7 +412,7 @@ module NewRelic
412
412
  # enough to be worth compressing, and handles any errors the
413
413
  # server may return
414
414
  def invoke_remote(method, payload = [], options = {})
415
- start_ts = Time.now
415
+ start_ts = Process.clock_gettime(Process::CLOCK_MONOTONIC)
416
416
 
417
417
  data, size, serialize_finish_ts, request_send_ts, response_check_ts = nil
418
418
  begin
@@ -420,7 +420,7 @@ module NewRelic
420
420
  rescue StandardError, SystemStackError => e
421
421
  handle_serialization_error(method, e)
422
422
  end
423
- serialize_finish_ts = Time.now
423
+ serialize_finish_ts = Process.clock_gettime(Process::CLOCK_MONOTONIC)
424
424
 
425
425
  data, encoding = compress_request_if_needed(data, method)
426
426
  size = data.size
@@ -443,13 +443,13 @@ module NewRelic
443
443
  full_uri = "#{endpoint_specific_collector}#{uri}"
444
444
 
445
445
  @audit_logger.log_request(full_uri, payload, @marshaller)
446
- request_send_ts = Time.now
446
+ request_send_ts = Process.clock_gettime(Process::CLOCK_MONOTONIC)
447
447
  response = send_request(:data => data,
448
448
  :uri => uri,
449
449
  :encoding => encoding,
450
450
  :collector => endpoint_specific_collector,
451
451
  :endpoint => method)
452
- response_check_ts = Time.now
452
+ response_check_ts = Process.clock_gettime(Process::CLOCK_MONOTONIC)
453
453
  @marshaller.load(decompress_response(response))
454
454
  ensure
455
455
  record_timing_supportability_metrics(method, start_ts, serialize_finish_ts, request_send_ts, response_check_ts)
@@ -469,7 +469,7 @@ module NewRelic
469
469
 
470
470
  def record_timing_supportability_metrics(method, start_ts, serialize_finish_ts, request_send_ts, response_check_ts)
471
471
  serialize_time = serialize_finish_ts && (serialize_finish_ts - start_ts)
472
- request_duration = response_check_ts && (response_check_ts - request_send_ts).to_f
472
+ request_duration = response_check_ts && (response_check_ts - request_send_ts)
473
473
  if request_duration
474
474
  NewRelic::Agent.record_metric("Supportability/Agent/Collector/#{method.to_s}/Duration", request_duration)
475
475
  end
@@ -67,7 +67,7 @@ module NewRelic
67
67
  if defined?(::Encoding::ASCII_8BIT)
68
68
  @in.set_encoding(::Encoding::ASCII_8BIT)
69
69
  end
70
- @last_read = Time.now
70
+ @last_read = Process.clock_gettime(Process::CLOCK_REALTIME)
71
71
  @parent_pid = $$
72
72
  end
73
73
 
@@ -92,7 +92,7 @@ module NewRelic
92
92
 
93
93
  def read
94
94
  @in.close unless @in.closed?
95
- @last_read = Time.now
95
+ @last_read = Process.clock_gettime(Process::CLOCK_REALTIME)
96
96
  length_bytes = @out.read(NUM_LENGTH_BYTES)
97
97
  if length_bytes
98
98
  message_length = deserialize_message_length(length_bytes)
@@ -171,11 +171,15 @@ module NewRelic
171
171
  @pipes.values.map{|pipe| pipe.out} + [wake.out]
172
172
  end
173
173
 
174
- NewRelic::Agent.record_metric('Supportability/Listeners',
175
- (Time.now - now).to_f) if now
174
+ if now
175
+ NewRelic::Agent.record_metric(
176
+ 'Supportability/Listeners',
177
+ Process.clock_gettime(Process::CLOCK_REALTIME) - now
178
+ )
179
+ end
176
180
 
177
181
  if ready = IO.select(pipes_to_listen_to, [], [], @select_timeout)
178
- now = Time.now
182
+ now = Process.clock_gettime(Process::CLOCK_REALTIME)
179
183
 
180
184
  ready_pipes = ready[0]
181
185
  ready_pipes.each do |pipe|
@@ -257,7 +261,7 @@ module NewRelic
257
261
  def clean_up_pipes
258
262
  @pipes_lock.synchronize do
259
263
  @pipes.values.each do |pipe|
260
- if pipe.last_read.to_f + @timeout < Time.now.to_f
264
+ if pipe.last_read + @timeout < Process.clock_gettime(Process::CLOCK_REALTIME)
261
265
  pipe.close unless pipe.closed?
262
266
  end
263
267
  end
@@ -61,7 +61,7 @@ module NewRelic
61
61
  write_to_pipe(:sql_trace_data, sql) if sql
62
62
  end
63
63
 
64
- def shutdown(time)
64
+ def shutdown
65
65
  @pipe.close if @pipe
66
66
  end
67
67
 
@@ -48,7 +48,7 @@ module NewRelic
48
48
  end
49
49
 
50
50
  def poll
51
- now = Time.now
51
+ now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
52
52
  t = Process.times
53
53
 
54
54
  if @last_time && t.utime != 0.0 && t.stime != 0.0
@@ -16,7 +16,7 @@ module NewRelic
16
16
  enabled_keys :'span_events.enabled',
17
17
  :'distributed_tracing.enabled'
18
18
 
19
- def record priority: nil, event:nil, &blk
19
+ def record(priority: nil, event: nil, &blk)
20
20
  unless(event || priority && blk)
21
21
  raise ArgumentError, "Expected priority and block, or event"
22
22
  end
@@ -33,7 +33,7 @@ module NewRelic
33
33
  SUPPORTABILITY_TOTAL_SENT = "Supportability/SpanEvent/TotalEventsSent".freeze
34
34
  SUPPORTABILITY_DISCARDED = "Supportability/SpanEvent/Discarded".freeze
35
35
 
36
- def after_harvest metadata
36
+ def after_harvest(metadata)
37
37
  seen = metadata[:seen]
38
38
  sent = metadata[:captured]
39
39
  discarded = seen - sent
@@ -46,7 +46,7 @@ module NewRelic
46
46
  NewRelic::Agent::Database.should_record_sql?(:slow_sql)
47
47
  end
48
48
 
49
- def on_start_transaction(state, start_time, uri=nil)
49
+ def on_start_transaction(state, uri=nil)
50
50
  return unless enabled?
51
51
 
52
52
  state.sql_sampler_transaction_data = TransactionSqlData.new
@@ -33,7 +33,7 @@ module NewRelic
33
33
 
34
34
  attr_accessor :started_at, :harvested_at
35
35
 
36
- def initialize(started_at=Time.now)
36
+ def initialize(started_at=Process.clock_gettime(Process::CLOCK_REALTIME))
37
37
  @started_at = started_at.to_f
38
38
  @scoped = Hash.new { |h, k| h[k] = NewRelic::Agent::Stats.new }
39
39
  @unscoped = Hash.new { |h, k| h[k] = NewRelic::Agent::Stats.new }
@@ -150,7 +150,7 @@ module NewRelic
150
150
  end
151
151
 
152
152
  def harvest!
153
- now = Time.now
153
+ now = Process.clock_gettime(Process::CLOCK_REALTIME)
154
154
  snapshot = reset!
155
155
  snapshot = apply_rules_to_metric_data(@metric_rules, snapshot)
156
156
  snapshot.harvested_at = now
@@ -198,7 +198,7 @@ module NewRelic
198
198
  :excon =>
199
199
  {
200
200
  :type => :http,
201
- :supported => [ ">= 0.10.1" ],
201
+ :supported => [ ">= 0.19.0" ],
202
202
  :url => "https://rubygems.org/gems/excon",
203
203
  :feed => "https://rubygems.org/gems/excon/versions.atom"
204
204
  },