wd_newrelic_rpm 3.5.6 → 3.5.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. data/CHANGELOG +43 -3
  2. data/Gemfile +6 -2
  3. data/LICENSE +23 -0
  4. data/lib/new_relic/agent.rb +50 -3
  5. data/lib/new_relic/agent/agent.rb +40 -60
  6. data/lib/new_relic/agent/configuration/defaults.rb +9 -3
  7. data/lib/new_relic/agent/configuration/server_source.rb +4 -0
  8. data/lib/new_relic/agent/cross_app_monitor.rb +239 -0
  9. data/lib/new_relic/agent/cross_app_tracing.rb +281 -0
  10. data/lib/new_relic/agent/database.rb +28 -10
  11. data/lib/new_relic/agent/error_collector.rb +5 -0
  12. data/lib/new_relic/agent/event_listener.rb +4 -0
  13. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +58 -39
  14. data/lib/new_relic/agent/instrumentation/metric_frame.rb +16 -3
  15. data/lib/new_relic/agent/instrumentation/net.rb +13 -11
  16. data/lib/new_relic/agent/instrumentation/queue_time.rb +50 -192
  17. data/lib/new_relic/agent/instrumentation/rails4/action_controller.rb +145 -0
  18. data/lib/new_relic/agent/instrumentation/rails4/errors.rb +45 -0
  19. data/lib/new_relic/agent/instrumentation/resque.rb +10 -10
  20. data/lib/new_relic/agent/instrumentation/sinatra.rb +19 -9
  21. data/lib/new_relic/agent/new_relic_service.rb +63 -9
  22. data/lib/new_relic/agent/pipe_service.rb +8 -12
  23. data/lib/new_relic/agent/rules_engine.rb +72 -0
  24. data/lib/new_relic/agent/shim_agent.rb +0 -1
  25. data/lib/new_relic/agent/sql_sampler.rb +3 -2
  26. data/lib/new_relic/agent/stats.rb +149 -0
  27. data/lib/new_relic/agent/stats_engine.rb +9 -0
  28. data/lib/new_relic/agent/stats_engine/gc_profiler.rb +1 -24
  29. data/lib/new_relic/agent/stats_engine/metric_stats.rb +84 -185
  30. data/lib/new_relic/agent/stats_engine/stats_hash.rb +58 -0
  31. data/lib/new_relic/agent/stats_engine/transactions.rb +10 -2
  32. data/lib/new_relic/agent/transaction_info.rb +31 -6
  33. data/lib/new_relic/agent/transaction_sample_builder.rb +19 -8
  34. data/lib/new_relic/agent/transaction_sampler.rb +17 -10
  35. data/lib/new_relic/helper.rb +32 -0
  36. data/lib/new_relic/local_environment.rb +24 -32
  37. data/lib/new_relic/okjson.rb +599 -0
  38. data/lib/new_relic/transaction_sample.rb +2 -1
  39. data/lib/new_relic/transaction_sample/segment.rb +2 -1
  40. data/lib/new_relic/version.rb +1 -1
  41. data/newrelic.yml +27 -41
  42. data/test/multiverse/suites/agent_only/Envfile +5 -1
  43. data/test/multiverse/suites/agent_only/audit_log_test.rb +2 -4
  44. data/test/multiverse/suites/agent_only/config/newrelic.yml +1 -2
  45. data/test/multiverse/suites/agent_only/{cross_process_test.rb → cross_application_tracing_test.rb} +3 -3
  46. data/test/multiverse/suites/agent_only/key_transactions_test.rb +66 -0
  47. data/test/multiverse/suites/agent_only/marshaling_test.rb +9 -22
  48. data/test/multiverse/suites/agent_only/rename_rule_test.rb +57 -0
  49. data/test/multiverse/suites/agent_only/start_up_test.rb +1 -1
  50. data/test/multiverse/suites/agent_only/thread_profiling_test.rb +17 -6
  51. data/test/multiverse/suites/rails/error_tracing_test.rb +20 -8
  52. data/test/multiverse/suites/rails/queue_time_test.rb +2 -2
  53. data/test/multiverse/suites/resque/instrumentation_test.rb +4 -3
  54. data/test/multiverse/suites/sinatra/Envfile +2 -0
  55. data/test/multiverse/suites/sinatra/config/newrelic.yml +1 -0
  56. data/test/multiverse/suites/sinatra/sinatra_metric_explosion_test.rb +5 -5
  57. data/test/multiverse/suites/sinatra/sinatra_test.rb +77 -10
  58. data/test/new_relic/agent/agent/connect_test.rb +45 -1
  59. data/test/new_relic/agent/agent/start_worker_thread_test.rb +0 -3
  60. data/test/new_relic/agent/agent_test.rb +20 -40
  61. data/test/new_relic/agent/agent_test_controller_test.rb +27 -60
  62. data/test/new_relic/agent/busy_calculator_test.rb +1 -1
  63. data/test/new_relic/agent/configuration/server_source_test.rb +8 -3
  64. data/test/new_relic/agent/cross_app_monitor_test.rb +237 -0
  65. data/test/new_relic/agent/database_test.rb +60 -16
  66. data/test/new_relic/agent/error_collector_test.rb +28 -4
  67. data/test/new_relic/agent/event_listener_test.rb +23 -2
  68. data/test/new_relic/agent/instrumentation/browser_monitoring_timings_test.rb +1 -1
  69. data/test/new_relic/agent/instrumentation/controller_instrumentation_test.rb +85 -12
  70. data/test/new_relic/agent/instrumentation/metric_frame_test.rb +95 -0
  71. data/test/new_relic/agent/instrumentation/net_instrumentation_test.rb +436 -59
  72. data/test/new_relic/agent/instrumentation/queue_time_test.rb +58 -357
  73. data/test/new_relic/agent/instrumentation/task_instrumentation_test.rb +2 -5
  74. data/test/new_relic/agent/method_tracer_test.rb +4 -2
  75. data/test/new_relic/agent/new_relic_service_test.rb +108 -6
  76. data/test/new_relic/agent/pipe_channel_manager_test.rb +1 -1
  77. data/test/new_relic/agent/pipe_service_test.rb +9 -9
  78. data/test/new_relic/agent/rpm_agent_test.rb +0 -11
  79. data/test/new_relic/agent/rules_engine_test.rb +82 -0
  80. data/test/new_relic/agent/shim_agent_test.rb +0 -4
  81. data/test/new_relic/agent/sql_sampler_test.rb +7 -0
  82. data/test/new_relic/agent/stats_engine/gc_profiler_test.rb +85 -0
  83. data/test/new_relic/agent/stats_engine/metric_stats_test.rb +110 -23
  84. data/test/new_relic/agent/stats_engine_test.rb +1 -46
  85. data/test/new_relic/agent/stats_hash_test.rb +93 -0
  86. data/test/new_relic/agent/stats_test.rb +197 -0
  87. data/test/new_relic/agent/transaction_info_test.rb +63 -11
  88. data/test/new_relic/agent/transaction_sample_builder_test.rb +10 -3
  89. data/test/new_relic/agent/transaction_sampler_test.rb +92 -80
  90. data/test/new_relic/agent/worker_loop_test.rb +1 -1
  91. data/test/new_relic/agent_test.rb +35 -5
  92. data/test/new_relic/control_test.rb +1 -1
  93. data/test/new_relic/fake_collector.rb +87 -9
  94. data/test/new_relic/helper_test.rb +24 -0
  95. data/test/new_relic/metric_data_test.rb +11 -11
  96. data/test/new_relic/metric_spec_test.rb +1 -1
  97. data/test/script/ci.sh +1 -1
  98. data/test/test_contexts.rb +0 -1
  99. data/test/test_helper.rb +21 -3
  100. metadata +34 -41
  101. data/lib/new_relic/agent/cross_process_monitoring.rb +0 -187
  102. data/lib/new_relic/stats.rb +0 -337
  103. data/test/new_relic/agent/cross_process_monitoring_test.rb +0 -190
  104. data/test/new_relic/agent/stats_engine/metric_stats/harvest_test.rb +0 -133
  105. data/test/new_relic/fakes_sending_data.rb +0 -30
  106. data/test/new_relic/stats_test.rb +0 -421
@@ -0,0 +1,45 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under New Relic's license terms.
3
+ # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
+
5
+ module NewRelic
6
+ module Agent
7
+ module Instrumentation
8
+ module Rails4
9
+ module Errors
10
+ def newrelic_notice_error(exception, custom_params = {})
11
+ filtered_params = (respond_to? :filter_parameters) ? filter_parameters(params) : params
12
+ filtered_params.merge!(custom_params)
13
+ NewRelic::Agent::Instrumentation::MetricFrame.notice_error( \
14
+ exception, \
15
+ :request => request, \
16
+ :metric => newrelic_metric_path, \
17
+ :custom_params => filtered_params)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ DependencyDetection.defer do
26
+ @name = :rails4_error
27
+
28
+ depends_on do
29
+ defined?(::Rails) && ::Rails.respond_to?(:version) && ::Rails.version.to_i == 4
30
+ end
31
+
32
+ depends_on do
33
+ defined?(ActionController) && defined?(ActionController::Base)
34
+ end
35
+
36
+ executes do
37
+ ::NewRelic::Agent.logger.info 'Installing Rails4 Error instrumentation'
38
+ end
39
+
40
+ executes do
41
+ class ActionController::Base
42
+ include NewRelic::Agent::Instrumentation::Rails4::Errors
43
+ end
44
+ end
45
+ end
@@ -1,6 +1,6 @@
1
1
  DependencyDetection.defer do
2
2
  @name = :resque
3
-
3
+
4
4
  depends_on do
5
5
  defined?(::Resque::Job) && !NewRelic::Agent.config[:disable_resque] &&
6
6
  !NewRelic::LanguageSupport.using_version?('1.9.1')
@@ -9,19 +9,19 @@ DependencyDetection.defer do
9
9
  executes do
10
10
  ::NewRelic::Agent.logger.info 'Installing Resque instrumentation'
11
11
  end
12
-
12
+
13
13
  executes do
14
14
  # == Resque Instrumentation
15
15
  #
16
16
  # Installs a hook to ensure the agent starts manually when the worker
17
17
  # starts and also adds the tracer to the process method which executes
18
18
  # in the forked task.
19
-
19
+
20
20
  module Resque
21
21
  module Plugins
22
22
  module NewRelicInstrumentation
23
23
  include NewRelic::Agent::Instrumentation::ControllerInstrumentation
24
-
24
+
25
25
  def around_perform_with_monitoring(*args)
26
26
  begin
27
27
  perform_action_with_newrelic_trace(:name => 'perform',
@@ -36,7 +36,7 @@ DependencyDetection.defer do
36
36
  end
37
37
  end
38
38
  end
39
-
39
+
40
40
  module NewRelic
41
41
  module Agent
42
42
  module Instrumentation
@@ -51,13 +51,13 @@ DependencyDetection.defer do
51
51
  end
52
52
  end
53
53
  end
54
-
54
+
55
55
  ::Resque::Job.class_eval do
56
56
  def self.new(*args)
57
57
  super(*args).extend NewRelic::Agent::Instrumentation::ResqueInstrumentationInstaller
58
58
  end
59
59
  end
60
-
60
+
61
61
  if NewRelic::LanguageSupport.can_fork?
62
62
  ::Resque.before_first_fork do
63
63
  NewRelic::Agent.manual_start(:dispatcher => :resque,
@@ -65,17 +65,17 @@ DependencyDetection.defer do
65
65
  :start_channel_listener => true,
66
66
  :report_instance_busy => false)
67
67
  end
68
-
68
+
69
69
  ::Resque.before_fork do |job|
70
70
  NewRelic::Agent.register_report_channel(job.object_id)
71
71
  end
72
-
72
+
73
73
  ::Resque.after_fork do |job|
74
74
  NewRelic::Agent.after_fork(:report_to_channel => job.object_id)
75
75
  end
76
76
  end
77
77
  end
78
- end
78
+ end
79
79
 
80
80
  # call this now so it is memoized before potentially forking worker processes
81
81
  NewRelic::LanguageSupport.can_fork?
@@ -36,26 +36,33 @@ module NewRelic
36
36
  include ::NewRelic::Agent::Instrumentation::ControllerInstrumentation
37
37
 
38
38
  def dispatch_with_newrelic
39
+ # We're trying to determine the transaction name via Sinatra's
40
+ # process_route, but calling it here misses Sinatra's normal error handling.
41
+ #
42
+ # Relies on transaction_name to always safely return a value for us
39
43
  txn_name = NewRelic.transaction_name(self.class.routes, @request) do |pattern, keys, conditions|
40
- process_route(pattern, keys, conditions) do
44
+ result = process_route(pattern, keys, conditions) do
41
45
  pattern.source
42
46
  end
47
+ result if result.class == String
43
48
  end
44
49
 
45
50
  perform_action_with_newrelic_trace(:category => :sinatra,
46
51
  :name => txn_name,
47
52
  :params => @request.params) do
48
- result = dispatch_without_newrelic
49
-
50
- # Will only see an error raised if :show_exceptions is true, but
51
- # will always see them in the env hash if they occur
52
- had_error = env.has_key?('sinatra.error')
53
- ::NewRelic::Agent.notice_error(env['sinatra.error']) if had_error
54
-
55
- result
53
+ dispatch_and_notice_errors_with_newrelic
56
54
  end
57
55
  end
58
56
 
57
+ def dispatch_and_notice_errors_with_newrelic
58
+ dispatch_without_newrelic
59
+ ensure
60
+ # Will only see an error raised if :show_exceptions is true, but
61
+ # will always see them in the env hash if they occur
62
+ had_error = env.has_key?('sinatra.error')
63
+ ::NewRelic::Agent.notice_error(env['sinatra.error']) if had_error
64
+ end
65
+
59
66
  # Define Request Header accessor for Sinatra
60
67
  def newrelic_request_headers
61
68
  request.env
@@ -88,6 +95,9 @@ module NewRelic
88
95
  end
89
96
 
90
97
  name
98
+ rescue => e
99
+ ::NewRelic::Agent.logger.debug("#{e.class} : #{e.message} - Error encountered trying to identify Sinatra transaction name")
100
+ '(unknown)'
91
101
  end
92
102
  end
93
103
  end
@@ -7,7 +7,8 @@ module NewRelic
7
7
  # Specifies the version of the agent's communication protocol with
8
8
  # the NewRelic hosted site.
9
9
 
10
- PROTOCOL_VERSION = 10
10
+ PROTOCOL_VERSION = 12
11
+ # 1f147a42: v10 (tag 3.5.3.17)
11
12
  # cf0d1ff1: v9 (tag 3.5.0)
12
13
  # 14105: v8 (tag 2.10.3)
13
14
  # (no v7)
@@ -18,12 +19,13 @@ module NewRelic
18
19
  # 534: v2 (shows up in 2.1.0, our first tag)
19
20
 
20
21
  attr_accessor :request_timeout, :agent_id
21
- attr_reader :collector, :marshaller
22
+ attr_reader :collector, :marshaller, :metric_id_cache
22
23
 
23
24
  def initialize(license_key=nil, collector=control.server)
24
25
  @license_key = license_key || Agent.config[:license_key]
25
26
  @collector = collector
26
27
  @request_timeout = Agent.config[:timeout]
28
+ @metric_id_cache = {}
27
29
 
28
30
  @audit_logger = ::NewRelic::Agent::AuditLogger.new(Agent.config)
29
31
  Agent.config.register_callback(:'audit_log.enabled') do |enabled|
@@ -70,9 +72,47 @@ module NewRelic
70
72
  invoke_remote(:shutdown, @agent_id, time.to_i) if @agent_id
71
73
  end
72
74
 
75
+ def reset_metric_id_cache
76
+ @metric_id_cache = {}
77
+ end
78
+
79
+ # takes an array of arrays of spec and id, adds it into the
80
+ # metric cache so we can save the collector some work by
81
+ # sending integers instead of strings the next time around
82
+ def fill_metric_id_cache(pairs_of_specs_and_ids)
83
+ Array(pairs_of_specs_and_ids).each do |metric_spec_hash, metric_id|
84
+ metric_spec = MetricSpec.new(metric_spec_hash['name'],
85
+ metric_spec_hash['scope'])
86
+ metric_id_cache[metric_spec] = metric_id
87
+ end
88
+ end
89
+
90
+ # The collector wants to recieve metric data in a format that's different
91
+ # from how we store it internally, so this method handles the translation.
92
+ # It also handles translating metric names to IDs using our metric ID cache.
93
+ def build_metric_data_array(stats_hash)
94
+ metric_data_array = []
95
+ stats_hash.each do |metric_spec, stats|
96
+ # Omit empty stats as an optimization
97
+ unless stats.is_reset?
98
+ metric_id = metric_id_cache[metric_spec]
99
+ metric_data = if metric_id
100
+ NewRelic::MetricData.new(nil, stats, metric_id)
101
+ else
102
+ NewRelic::MetricData.new(metric_spec, stats, nil)
103
+ end
104
+ metric_data_array << metric_data
105
+ end
106
+ end
107
+ metric_data_array
108
+ end
109
+
73
110
  def metric_data(last_harvest_time, now, unsent_timeslice_data)
74
- invoke_remote(:metric_data, @agent_id, last_harvest_time, now,
75
- unsent_timeslice_data)
111
+ metric_data_array = build_metric_data_array(unsent_timeslice_data)
112
+ result = invoke_remote(:metric_data, @agent_id, last_harvest_time, now,
113
+ metric_data_array)
114
+ fill_metric_id_cache(result)
115
+ result
76
116
  end
77
117
 
78
118
  def error_data(unsent_errors)
@@ -207,7 +247,14 @@ module NewRelic
207
247
  def invoke_remote(method, *args)
208
248
  now = Time.now
209
249
 
210
- data = @marshaller.dump(args)
250
+ data = nil
251
+ begin
252
+ data = @marshaller.dump(args)
253
+ rescue JsonError
254
+ @marshaller = PrubyMarshaller.new
255
+ retry
256
+ end
257
+
211
258
  data, encoding = compress_request_if_needed(data)
212
259
 
213
260
  uri = remote_method_uri(method, @marshaller.format)
@@ -341,6 +388,12 @@ module NewRelic
341
388
  end
342
389
  end
343
390
 
391
+ # Used to wrap errors reported to agent by the collector
392
+ class CollectorError < StandardError; end
393
+
394
+ # Used to wrap any problem with the JSON marshaller
395
+ class JsonError < StandardError; end
396
+
344
397
  class Marshaller
345
398
  def parsed_error(error)
346
399
  error_class = error['error_type'].split('::') \
@@ -426,13 +479,16 @@ module NewRelic
426
479
 
427
480
  def dump(ruby, opts={})
428
481
  JSON.dump(prepare(ruby, opts))
482
+ rescue => e
483
+ ::NewRelic::Agent.logger.debug "#{e.class.name} : #{e.message} encountered dumping agent data: #{ruby}"
484
+ raise JsonError.new(e)
429
485
  end
430
486
 
431
487
  def load(data)
432
488
  return unless data && data != ''
433
489
  return_value(JSON.load(data))
434
- rescue
435
- ::NewRelic::Agent.logger.debug "Error encountered loading collector response: #{data}"
490
+ rescue => e
491
+ ::NewRelic::Agent.logger.debug "#{e.class.name} : #{e.message} encountered loading collector response: #{data}"
436
492
  raise
437
493
  end
438
494
 
@@ -452,8 +508,6 @@ module NewRelic
452
508
  true # for some definitions of 'human'
453
509
  end
454
510
  end
455
-
456
- class CollectorError < StandardError; end
457
511
  end
458
512
  end
459
513
  end
@@ -3,13 +3,13 @@ module NewRelic
3
3
  class PipeService
4
4
  attr_reader :channel_id, :buffer
5
5
  attr_accessor :request_timeout, :agent_id, :collector
6
-
6
+
7
7
  def initialize(channel_id)
8
8
  @channel_id = channel_id
9
9
  @collector = NewRelic::Control::Server.new(:name => 'parent',
10
10
  :port => 0)
11
11
  end
12
-
12
+
13
13
  def connect(config)
14
14
  nil
15
15
  end
@@ -19,7 +19,7 @@ module NewRelic
19
19
  end
20
20
 
21
21
  def metric_data(last_harvest_time, now, unsent_timeslice_data)
22
- write_to_pipe(:stats => hash_from_metric_data(unsent_timeslice_data))
22
+ write_to_pipe(:stats => unsent_timeslice_data)
23
23
  {}
24
24
  end
25
25
 
@@ -34,7 +34,7 @@ module NewRelic
34
34
  def sql_trace_data(sql)
35
35
  write_to_pipe(:sql_traces => sql) if sql
36
36
  end
37
-
37
+
38
38
  def shutdown(time)
39
39
  write_to_pipe('EOF')
40
40
  NewRelic::Agent::PipeChannelManager.channels[@channel_id].close
@@ -46,17 +46,13 @@ module NewRelic
46
46
  def session
47
47
  yield
48
48
  end
49
-
50
- private
51
49
 
52
- def hash_from_metric_data(metric_data)
53
- metric_hash = {}
54
- metric_data.each do |metric_entry|
55
- metric_hash[metric_entry.metric_spec] = metric_entry
56
- end
57
- metric_hash
50
+ def reset_metric_id_cache
51
+ # we don't cache metric IDs, so nothing to do
58
52
  end
59
53
 
54
+ private
55
+
60
56
  def write_to_pipe(data)
61
57
  NewRelic::Agent::PipeChannelManager.channels[@channel_id].write(data)
62
58
  rescue => e
@@ -0,0 +1,72 @@
1
+ module NewRelic
2
+ module Agent
3
+ class RulesEngine
4
+ include Enumerable
5
+ extend Forwardable
6
+
7
+ def_delegators :@rules, :size, :<<, :inspect, :each
8
+
9
+ attr_accessor :rules
10
+
11
+ def initialize(rules=[])
12
+ @rules = rules
13
+ end
14
+
15
+ def rename(original_string)
16
+ @rules.sort.inject(original_string) do |string,rule|
17
+ if rule.each_segment
18
+ result, matched = rule.map_to_list(string.split('/'))
19
+ result = result.join('/')
20
+ else
21
+ result, matched = rule.apply(string)
22
+ end
23
+
24
+ break result if matched && rule.terminate_chain
25
+ result
26
+ end
27
+ end
28
+
29
+ class Rule
30
+ attr_reader(:terminate_chain, :each_segment, :ignore, :replace_all, :eval_order,
31
+ :match_expression, :replacement)
32
+
33
+ def initialize(options)
34
+ if !options['match_expression']
35
+ raise ArgumentError.new('missing required match_expression')
36
+ end
37
+ if !options['replacement'] && !options['ignore']
38
+ raise ArgumentError.new('must specify replacement when ignore is false')
39
+ end
40
+
41
+ @match_expression = Regexp.new(options['match_expression'])
42
+ @replacement = options['replacement']
43
+ @ignore = options['ignore'] || false
44
+ @eval_order = options['eval_order'] || 0
45
+ @replace_all = options['replace_all'] || false
46
+ @each_segment = options['each_segment'] || false
47
+ @terminate_chain = options['terminate_chain'] || false
48
+ end
49
+
50
+ def apply(string)
51
+ method = @replace_all ? :gsub : :sub
52
+ result = string.send(method, @match_expression, @replacement)
53
+ [result, result != string]
54
+ end
55
+
56
+ def map_to_list(list)
57
+ matched = false
58
+ result = list.map do |string|
59
+ str_result, str_match = apply(string)
60
+ matched ||= str_match
61
+ str_result
62
+ end
63
+ [result, matched]
64
+ end
65
+
66
+ def <=>(other)
67
+ eval_order <=> other.eval_order
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -18,7 +18,6 @@ module NewRelic
18
18
  def after_fork *args; end
19
19
  def start *args; end
20
20
  def shutdown *args; end
21
- def serialize; end
22
21
  def merge_data_from *args; end
23
22
  def push_trace_execution_flag *args; end
24
23
  def pop_trace_execution_flag *args; end
@@ -99,7 +99,8 @@ module NewRelic
99
99
  if NewRelic::Agent.is_sql_recorded?
100
100
  if duration > Agent.config[:'slow_sql.explain_threshold']
101
101
  backtrace = caller.join("\n")
102
- transaction_data.sql_data << SlowSql.new(sql, metric_name, config,
102
+ transaction_data.sql_data << SlowSql.new(TransactionSampler.truncate_message(sql),
103
+ metric_name, config,
103
104
  duration, backtrace)
104
105
  end
105
106
  end
@@ -176,7 +177,7 @@ module NewRelic
176
177
  end
177
178
  end
178
179
 
179
- class SqlTrace < MethodTraceStats
180
+ class SqlTrace < Stats
180
181
  attr_reader :path
181
182
  attr_reader :url
182
183
  attr_reader :sql_id