newrelic_rpm 2.9.9 → 2.10.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of newrelic_rpm might be problematic. Click here for more details.

Files changed (120) hide show
  1. data/CHANGELOG +117 -49
  2. data/bin/mongrel_rpm +2 -2
  3. data/install.rb +42 -33
  4. data/lib/new_relic/agent.rb +149 -39
  5. data/lib/new_relic/agent/agent.rb +139 -122
  6. data/lib/new_relic/agent/busy_calculator.rb +91 -0
  7. data/lib/new_relic/agent/collection_helper.rb +11 -2
  8. data/lib/new_relic/agent/error_collector.rb +33 -27
  9. data/lib/new_relic/agent/instrumentation/active_record_instrumentation.rb +30 -26
  10. data/lib/new_relic/agent/instrumentation/authlogic.rb +8 -0
  11. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +316 -105
  12. data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +22 -0
  13. data/lib/new_relic/agent/instrumentation/memcache.rb +18 -12
  14. data/lib/new_relic/agent/instrumentation/merb/errors.rb +2 -1
  15. data/lib/new_relic/agent/instrumentation/metric_frame.rb +258 -0
  16. data/lib/new_relic/agent/instrumentation/net.rb +7 -11
  17. data/lib/new_relic/agent/instrumentation/passenger_instrumentation.rb +1 -1
  18. data/lib/new_relic/agent/instrumentation/rack.rb +109 -0
  19. data/lib/new_relic/agent/instrumentation/rails/action_controller.rb +6 -5
  20. data/lib/new_relic/agent/instrumentation/rails/errors.rb +7 -7
  21. data/lib/new_relic/agent/instrumentation/sinatra.rb +46 -0
  22. data/lib/new_relic/agent/method_tracer.rb +305 -150
  23. data/lib/new_relic/agent/sampler.rb +34 -0
  24. data/lib/new_relic/agent/samplers/cpu_sampler.rb +11 -1
  25. data/lib/new_relic/agent/samplers/delayed_job_lock_sampler.rb +37 -0
  26. data/lib/new_relic/agent/samplers/memory_sampler.rb +22 -10
  27. data/lib/new_relic/agent/samplers/object_sampler.rb +24 -0
  28. data/lib/new_relic/agent/shim_agent.rb +10 -0
  29. data/lib/new_relic/agent/stats_engine.rb +16 -278
  30. data/lib/new_relic/agent/stats_engine/metric_stats.rb +118 -0
  31. data/lib/new_relic/agent/stats_engine/samplers.rb +81 -0
  32. data/lib/new_relic/agent/stats_engine/transactions.rb +149 -0
  33. data/lib/new_relic/agent/transaction_sampler.rb +73 -67
  34. data/lib/new_relic/agent/worker_loop.rb +69 -68
  35. data/lib/new_relic/commands/deployments.rb +4 -6
  36. data/lib/new_relic/control.rb +121 -60
  37. data/lib/new_relic/control/external.rb +13 -0
  38. data/lib/new_relic/control/merb.rb +2 -0
  39. data/lib/new_relic/control/rails.rb +16 -6
  40. data/lib/new_relic/control/ruby.rb +8 -5
  41. data/lib/new_relic/control/sinatra.rb +18 -0
  42. data/lib/new_relic/delayed_job_injection.rb +25 -0
  43. data/lib/new_relic/histogram.rb +89 -0
  44. data/lib/new_relic/local_environment.rb +64 -30
  45. data/lib/new_relic/metric_data.rb +15 -6
  46. data/lib/new_relic/metric_parser.rb +14 -1
  47. data/lib/new_relic/metric_parser/active_record.rb +14 -0
  48. data/lib/new_relic/metric_parser/controller.rb +5 -2
  49. data/lib/new_relic/metric_parser/external.rb +50 -0
  50. data/lib/new_relic/metric_parser/other_transaction.rb +15 -0
  51. data/lib/new_relic/metric_parser/web_frontend.rb +14 -0
  52. data/lib/new_relic/metric_spec.rb +39 -20
  53. data/lib/new_relic/metrics.rb +9 -7
  54. data/lib/new_relic/noticed_error.rb +6 -8
  55. data/lib/new_relic/rack/metric_app.rb +5 -4
  56. data/lib/new_relic/rack/{newrelic.ru → mongrel_rpm.ru} +4 -4
  57. data/lib/new_relic/rack/newrelic.yml +1 -0
  58. data/lib/new_relic/{rack.rb → rack_app.rb} +0 -0
  59. data/lib/new_relic/recipes.rb +1 -1
  60. data/lib/new_relic/stats.rb +40 -26
  61. data/lib/new_relic/transaction_analysis.rb +5 -2
  62. data/lib/new_relic/transaction_sample.rb +134 -55
  63. data/lib/new_relic/version.rb +27 -20
  64. data/lib/new_relic_api.rb +67 -47
  65. data/lib/newrelic_rpm.rb +5 -5
  66. data/lib/tasks/tests.rake +2 -0
  67. data/newrelic.yml +69 -29
  68. data/test/active_record_fixtures.rb +2 -2
  69. data/test/config/newrelic.yml +4 -7
  70. data/test/config/test_control.rb +1 -2
  71. data/test/new_relic/agent/active_record_instrumentation_test.rb +115 -31
  72. data/test/new_relic/agent/agent_controller_test.rb +274 -0
  73. data/test/new_relic/agent/agent_test_controller.rb +42 -6
  74. data/test/new_relic/agent/busy_calculator_test.rb +79 -0
  75. data/test/new_relic/agent/collection_helper_test.rb +10 -3
  76. data/test/new_relic/agent/error_collector_test.rb +35 -17
  77. data/test/new_relic/agent/method_tracer_test.rb +60 -20
  78. data/test/new_relic/agent/metric_data_test.rb +2 -2
  79. data/test/new_relic/agent/metric_frame_test.rb +51 -0
  80. data/test/new_relic/agent/net_instrumentation_test.rb +77 -0
  81. data/test/new_relic/agent/{agent_test.rb → rpm_agent_test.rb} +26 -5
  82. data/test/new_relic/agent/stats_engine/metric_stats_test.rb +79 -0
  83. data/test/new_relic/{samplers_test.rb → agent/stats_engine/samplers_test.rb} +23 -22
  84. data/test/new_relic/agent/{stats_engine_test.rb → stats_engine/stats_engine_test.rb} +19 -101
  85. data/test/new_relic/agent/task_instrumentation_test.rb +176 -0
  86. data/test/new_relic/agent/transaction_sample_builder_test.rb +2 -2
  87. data/test/new_relic/agent/transaction_sample_test.rb +53 -38
  88. data/test/new_relic/agent/transaction_sampler_test.rb +101 -33
  89. data/test/new_relic/agent/worker_loop_test.rb +16 -14
  90. data/test/new_relic/control_test.rb +26 -13
  91. data/test/new_relic/metric_parser_test.rb +31 -1
  92. data/test/new_relic/metric_spec_test.rb +2 -2
  93. data/test/new_relic/stats_test.rb +0 -8
  94. data/test/new_relic/version_number_test.rb +31 -1
  95. data/test/test_helper.rb +37 -1
  96. data/ui/controllers/newrelic_controller.rb +19 -11
  97. data/ui/helpers/google_pie_chart.rb +5 -11
  98. data/ui/helpers/newrelic_helper.rb +40 -35
  99. data/ui/views/layouts/newrelic_default.rhtml +7 -7
  100. data/ui/views/newrelic/_sample.rhtml +5 -1
  101. data/ui/views/newrelic/images/new-relic-rpm-desktop.gif +0 -0
  102. data/ui/views/newrelic/images/textmate.png +0 -0
  103. data/ui/views/newrelic/index.rhtml +13 -1
  104. data/ui/views/newrelic/show_sample.rhtml +5 -2
  105. data/ui/views/newrelic/stylesheets/style.css +54 -3
  106. metadata +65 -145
  107. data/Manifest +0 -143
  108. data/Rakefile +0 -22
  109. data/init.rb +0 -38
  110. data/lib/new_relic/agent/instrumentation/dispatcher_instrumentation.rb +0 -127
  111. data/lib/new_relic/agent/instrumentation/error_instrumentation.rb +0 -14
  112. data/lib/new_relic/agent/instrumentation/merb/dispatcher.rb +0 -13
  113. data/lib/new_relic/agent/instrumentation/rails/dispatcher.rb +0 -38
  114. data/lib/new_relic/agent/patch_const_missing.rb +0 -125
  115. data/lib/new_relic/agent/samplers/mongrel_sampler.rb +0 -22
  116. data/lib/new_relic/metric_parser/database.rb +0 -23
  117. data/newrelic_rpm.gemspec +0 -35
  118. data/test/new_relic/agent/classloader_patch_test.rb +0 -56
  119. data/test/new_relic/agent/controller_test.rb +0 -107
  120. data/test/new_relic/agent/dispatcher_instrumentation_test.rb +0 -70
@@ -5,7 +5,7 @@ module NewRelic
5
5
  attr_accessor :stats
6
6
 
7
7
  def initialize(metric_spec, stats, metric_id)
8
- self.metric_spec = metric_spec
8
+ @metric_spec = metric_spec
9
9
  self.stats = stats
10
10
  self.metric_id = metric_id
11
11
  end
@@ -13,16 +13,25 @@ module NewRelic
13
13
  def eql?(o)
14
14
  (metric_spec.eql? o.metric_spec) && (stats.eql? o.stats)
15
15
  end
16
+
17
+ def original_spec
18
+ @original_spec || @metric_spec
19
+ end
20
+ def metric_spec
21
+ @metric_spec
22
+ end
23
+ def metric_spec= new_spec
24
+ @original_spec = @metric_spec if @metric_spec
25
+ @metric_spec = new_spec
26
+ end
16
27
 
17
28
  def hash
18
- metric_spec.hash + stats.hash
29
+ metric_spec.hash ^ stats.hash
19
30
  end
20
31
 
32
+ # Serialize with all attributes, but if the metric id is not nil, then don't send the metric spec
21
33
  def to_json(*a)
22
- {'metric_spec' => metric_spec,
23
- 'stats' => stats,
24
- 'metric_id' => metric_id
25
- }.to_json(*a)
34
+ %Q[{"metric_spec":#{metric_id ? 'null' : metric_spec.to_json},"stats":{"total_exclusive_time":#{stats.total_exclusive_time},"min_call_time":#{stats.min_call_time},"call_count":#{stats.call_count},"sum_of_squares":#{stats.sum_of_squares},"total_call_time":#{stats.total_call_time},"max_call_time":#{stats.max_call_time}},"metric_id":#{metric_id ? metric_id : 'null'}}]
26
35
  end
27
36
 
28
37
  def to_s
@@ -66,6 +66,15 @@ module NewRelic
66
66
  short_name
67
67
  end
68
68
 
69
+ def apdex_metric_path
70
+ "Apdex/#{segments[1..-1].join('/')}"
71
+ end
72
+
73
+ # A short name for legends in the graphs
74
+ def legend_name
75
+ short_name
76
+ end
77
+
69
78
  # Return the name of another metric if the current
70
79
  # metric is really add-on data for another metric.
71
80
  def base_metric_name
@@ -102,7 +111,11 @@ module NewRelic
102
111
  def url
103
112
  ''
104
113
  end
105
-
114
+
115
+ # returns a hash of params for url_for(), giving you a drilldown URL to an RPM page for this metric
116
+ # define in subclasses - TB 2009-12-18
117
+ # def drilldown_url(metric_id); end
118
+
106
119
  def initialize(name)
107
120
  @name = name
108
121
  end
@@ -5,6 +5,20 @@ class NewRelic::MetricParser::ActiveRecord < NewRelic::MetricParser
5
5
  return segments[1]
6
6
  end
7
7
 
8
+ def legend_name
9
+ if name == 'ActiveRecord/all'
10
+ 'Database'
11
+ else
12
+ super
13
+ end
14
+ end
15
+ def tooltip_name
16
+ if name == 'ActiveRecord/all'
17
+ 'all SQL execution'
18
+ else
19
+ super
20
+ end
21
+ end
8
22
  def developer_name
9
23
  "#{model_class}##{segments.last}"
10
24
  end
@@ -1,11 +1,14 @@
1
1
  class NewRelic::MetricParser::Controller < NewRelic::MetricParser
2
-
2
+
3
3
  def is_controller?
4
4
  true
5
5
  end
6
6
 
7
+ # If the controller name segments look like a file path, convert it to the controller
8
+ # class name. If it begins with a capital letter, assume it's already a class name
7
9
  def controller_name
8
- segments[1..-2].join('/').camelize+"Controller"
10
+ path = segments[1..-2].join('/')
11
+ path < 'a' ? path : path.camelize+"Controller"
9
12
  end
10
13
 
11
14
  def action_name
@@ -0,0 +1,50 @@
1
+ class NewRelic::MetricParser::External < NewRelic::MetricParser
2
+
3
+ def all?
4
+ host == 'all' || host == 'allWeb' || host == 'allOther'
5
+ end
6
+ def hosts_all?
7
+ library == 'all'
8
+ end
9
+ def host
10
+ segments[1]
11
+ end
12
+ def library
13
+ segments[2]
14
+ end
15
+ def operation
16
+ segments[3] && segments[3..-1].join("/")
17
+ end
18
+ def legend_name
19
+ case
20
+ when all?
21
+ "External Services"
22
+ when hosts_all?
23
+ "All #{host} calls"
24
+ else
25
+ developer_name
26
+ end
27
+ end
28
+ def tooltip_name
29
+ case
30
+ when all?
31
+ "calls to external systems"
32
+ when hosts_all?
33
+ "calls to #{host}"
34
+ else
35
+ "calls to #{developer_name}"
36
+ end
37
+ end
38
+ def developer_name
39
+ case
40
+ when all?
41
+ 'All External'
42
+ when hosts_all?
43
+ host
44
+ when operation
45
+ "#{library}[#{host}]: #{operation}"
46
+ else
47
+ "#{library}[#{host}]"
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,15 @@
1
+ # OtherTransaction metrics must have at least three segments: /OtherTransaction/<task>/*
2
+
3
+ class NewRelic::MetricParser::OtherTransaction < NewRelic::MetricParser
4
+ def task
5
+ segments[1]
6
+ end
7
+
8
+ def developer_name
9
+ segments[2..-1].join(NewRelic::MetricParser::SEPARATOR)
10
+ end
11
+
12
+ def drilldown_url(metric_id)
13
+ {:controller => '/v2/background_tasks', :action => 'index', :task => task, :anchor => "id=#{metric_id}"}
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ # The metric where the mongrel queue time is stored
2
+
3
+ class NewRelic::MetricParser::WebFrontend < NewRelic::MetricParser
4
+ def short_name
5
+ if segments.last == 'Average Queue Time'
6
+ 'Mongrel Average Queue Time'
7
+ else
8
+ super
9
+ end
10
+ end
11
+ def legend_name
12
+ 'Mongrel Wait'
13
+ end
14
+ end
@@ -4,21 +4,51 @@ class NewRelic::MetricSpec
4
4
  attr_accessor :name
5
5
  attr_accessor :scope
6
6
 
7
- def initialize (metric_name, metric_scope = '')
8
- self.name = metric_name
9
- self.scope = metric_scope
7
+ MAX_LENGTH = 100
8
+ # Need a "zero-arg" constructor so it can be instantiated from java (using
9
+ # jruby) for sending responses to ruby agents from the java collector.
10
+ #
11
+ def initialize(metric_name = '', metric_scope = '')
12
+ self.name = (metric_name || '') && metric_name[0...MAX_LENGTH]
13
+ self.scope = metric_scope && metric_scope[0...MAX_LENGTH]
10
14
  end
11
15
 
12
- def eql? (o)
13
- scope_equal = scope.nil? ? o.scope.nil? : scope.eql?(o.scope)
14
- name.eql?(o.name) && scope_equal
16
+ def truncate!
17
+ self.name = name[0...100] if name && name.size > 100
18
+ self.scope = scope[0...100] if scope && scope.size > 100
19
+ end
20
+
21
+ def ==(o)
22
+ self.eql?(o)
23
+ end
24
+
25
+ def eql? o
26
+ self.class == o.class &&
27
+ name.eql?(o.name) &&
28
+ # coerce scope to a string and compare
29
+ (scope || '') == (o.scope || '')
15
30
  end
16
31
 
17
32
  def hash
18
33
  h = name.hash
19
- h += scope.hash unless scope.nil?
34
+ h ^= scope.hash unless scope.nil?
20
35
  h
21
36
  end
37
+ # return a new metric spec if the given regex
38
+ # matches the name or scope.
39
+ def sub(pattern, replacement, apply_to_scope = true)
40
+ return nil if name !~ pattern &&
41
+ (!apply_to_scope || scope.nil? || scope !~ pattern)
42
+ new_name = name.sub(pattern, replacement)[0...MAX_LENGTH]
43
+
44
+ if apply_to_scope
45
+ new_scope = (scope && scope.sub(pattern, replacement)[0...MAX_LENGTH])
46
+ else
47
+ new_scope = scope
48
+ end
49
+
50
+ self.class.new new_name, new_scope
51
+ end
22
52
 
23
53
  def to_s
24
54
  "#{name}:#{scope}"
@@ -30,19 +60,8 @@ class NewRelic::MetricSpec
30
60
  end
31
61
 
32
62
  def <=>(o)
33
- namecmp = name <=> o.name
63
+ namecmp = self.name <=> o.name
34
64
  return namecmp if namecmp != 0
35
-
36
- # i'm sure there's a more elegant way to code this correctly, but at least this passes
37
- # my unit test
38
- if scope.nil? && o.scope.nil?
39
- return 0
40
- elsif scope.nil?
41
- return -1
42
- elsif o.scope.nil?
43
- return 1
44
- else
45
- return scope <=> o.scope
46
- end
65
+ return (self.scope || '') <=> (o.scope || '')
47
66
  end
48
67
  end
@@ -1,7 +1,9 @@
1
- module NewRelic::Metrics
2
- CONTROLLER = "Controller"
3
- DISPATCHER = "Rails/HTTP Dispatch"
4
- ACTIVE_RECORD = "ActiveRecord"
5
- USER_TIME = "CPU/User Time"
6
- MEMORY = "Memory/Physical"
7
- end
1
+ module NewRelic
2
+ module Metrics
3
+ CONTROLLER = "Controller"
4
+ DISPATCHER = "HttpDispatcher"
5
+ ACTIVE_RECORD = "ActiveRecord"
6
+ USER_TIME = "CPU/User Time"
7
+ MEMORY = "Memory/Physical"
8
+ end
9
+ end
@@ -1,25 +1,23 @@
1
- # this class encapsulates an error that was noticed by RPM in a managed app.
2
- # Unfortunately it was put in the agent in the global namespace early on and
3
- # for backward compatibility it needs to remain here.
1
+ # This class encapsulates an error that was noticed by RPM in a managed app.
4
2
  class NewRelic::NoticedError
5
3
  attr_accessor :path, :timestamp, :params, :exception_class, :message
6
4
 
7
- def initialize(path, data, exception)
5
+ def initialize(path, data, exception, timestamp = Time.now)
8
6
  self.path = path
9
7
  self.params = data
10
8
 
11
- self.exception_class = exception.class.name
9
+ self.exception_class = exception ? exception.class.name : '<no exception>'
12
10
 
13
11
  if exception.respond_to?('original_exception')
14
12
  self.message = exception.original_exception.message.to_s
15
13
  else
16
- self.message = exception.message.to_s
14
+ self.message = (exception || '<no message>').to_s
17
15
  end
18
16
 
19
17
  # clamp long messages to 4k so that we don't send a lot of
20
18
  # overhead across the wire
21
- self.message = self.message[0..4096] if self.message.length > 4096
19
+ self.message = self.message[0..4095] if self.message.length > 4096
22
20
 
23
- self.timestamp = Time.now
21
+ self.timestamp = timestamp
24
22
  end
25
23
  end
@@ -1,5 +1,6 @@
1
1
  require 'fileutils'
2
- module NewRelic::Rack
2
+ module NewRelic
3
+ module Rack
3
4
  class MetricApp
4
5
  def initialize(options)
5
6
  if options[:install]
@@ -12,7 +13,6 @@ module NewRelic::Rack
12
13
  options[:app_name] ||= 'EPM Monitor'
13
14
  options[:disable_samplers] = true
14
15
  NewRelic::Agent.manual_start options
15
- @stats_engine = NewRelic::Agent.instance.stats_engine
16
16
  unless NewRelic::Control.instance.license_key
17
17
  NewRelic::Control.instance.log.error "Please add a valid license key to newrelic.yml."
18
18
  exit 1
@@ -24,7 +24,7 @@ module NewRelic::Rack
24
24
  metric = "Custom/" + segments.join("/")
25
25
  raise "Expected value parameter!" unless request['value']
26
26
  data = request['value'].to_f
27
- stats = @stats_engine.get_stats(metric, false)
27
+ stats = NewRelic::Agent.get_stats(metric, false)
28
28
  stats.record_data_point data
29
29
  response = ::Rack::Response.new "#{metric}=#{data}"
30
30
  response.finish
@@ -54,4 +54,5 @@ module NewRelic::Rack
54
54
  response.finish
55
55
  end
56
56
  end
57
- end
57
+ end
58
+ end
@@ -4,7 +4,7 @@ ENV['NEWRELIC_DISPATCHER'] = 'none'
4
4
 
5
5
  $LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), '..','..'))
6
6
 
7
- require 'new_relic/rack'
7
+ require 'new_relic/rack_app'
8
8
 
9
9
  # Valid options which may be present in this binding:
10
10
  # :license_key optional license key override
@@ -15,11 +15,11 @@ options ||= {}
15
15
 
16
16
  use Rack::CommonLogger unless options[:logging] == false
17
17
  use Rack::ShowExceptions
18
- map "http://localhost/metrics" do
19
- run NewRelic::Rack::MetricApp.new(options)
20
- end
21
18
  map "/" do
22
19
  run NewRelic::Rack::Status.new
23
20
  end
21
+ map "/metrics" do
22
+ run NewRelic::Rack::MetricApp.new(options)
23
+ end
24
24
 
25
25
 
@@ -4,6 +4,7 @@
4
4
  #
5
5
  common: &default_settings
6
6
  log_level: info
7
+ enabled: true
7
8
 
8
9
  # This is the key generated by script/create_admin
9
10
  license_key: 'your_license_key_here'
File without changes
@@ -15,7 +15,7 @@ make_notify_task = lambda do
15
15
  # on all deployments, notify RPM
16
16
  desc "Record a deployment in New Relic RPM (rpm.newrelic.com)"
17
17
  task :notice_deployment, :roles => :app, :except => {:no_release => true } do
18
- rails_env = fetch(:rails_env, "production")
18
+ rails_env = fetch(:newrelic_rails_env, fetch(:rails_env, "production"))
19
19
  require File.join(File.dirname(__FILE__), 'commands', 'deployments.rb')
20
20
  begin
21
21
  # Try getting the changelog from the server. Then fall back to local changelog
@@ -47,7 +47,7 @@ module NewRelic
47
47
  stats.merge! other_stats
48
48
  end
49
49
 
50
- # split into an array of timesclices whose
50
+ # split into an array of timeslices whose
51
51
  # time boundaries start on (begin_time + (n * duration)) and whose
52
52
  # end time ends on (begin_time * (n + 1) * duration), except for the
53
53
  # first and last elements, whose begin time and end time are the begin
@@ -102,13 +102,16 @@ module NewRelic
102
102
 
103
103
  def as_percentage_of(other_stats)
104
104
  return 0 if other_stats.total_call_time == 0
105
- return to_percentage(total_call_time / other_stats.total_call_time)
105
+ return (total_call_time / other_stats.total_call_time) * 100.0
106
106
  end
107
107
 
108
108
  # the stat total_call_time is a percent
109
109
  def as_percentage
110
- return 0 if call_count == 0
111
- to_percentage(total_call_time / call_count)
110
+ if call_count.zero?
111
+ 0
112
+ else
113
+ (total_call_time / call_count) * 100.0
114
+ end
112
115
  end
113
116
 
114
117
  def duration
@@ -116,16 +119,17 @@ module NewRelic
116
119
  end
117
120
 
118
121
  def calls_per_minute
119
- return 0 if duration.zero?
120
- ((call_count / duration.to_f * 6000).round).to_f / 100
121
- end
122
+ if duration.zero?
123
+ 0
124
+ else
125
+ (call_count / duration.to_f) * 60.0
126
+ end
127
+ end
122
128
 
123
- def calls_per_second
124
- round_to_2 calls_per_minute / 60
125
- end
126
129
  def total_call_time_per_minute
127
130
  60.0 * time_percentage
128
131
  end
132
+
129
133
  def standard_deviation
130
134
  return 0 if call_count < 2 || self.sum_of_squares.nil?
131
135
 
@@ -189,7 +193,8 @@ module NewRelic
189
193
  min_end = (end_time < s.end_time ? end_time : s.end_time)
190
194
  max_begin = (begin_time > s.begin_time ? begin_time : s.begin_time)
191
195
  percentage = (min_end - max_begin) / s.duration
192
-
196
+
197
+ self.total_exclusive_time = s.total_exclusive_time * percentage
193
198
  self.total_call_time = s.total_call_time * percentage
194
199
  self.min_call_time = s.min_call_time
195
200
  self.max_call_time = s.max_call_time
@@ -212,23 +217,17 @@ module NewRelic
212
217
  [@call_count, @total_call_time.to_i, @total_exclusive_time.to_i]
213
218
  end
214
219
 
215
- def apdex_score
216
- s, t, f = get_apdex
217
- (s.to_f + (t.to_f / 2)) / (s+t+f).to_f
218
- end
220
+ def apdex_score
221
+ s, t, f = get_apdex
222
+ (s.to_f + (t.to_f / 2)) / (s+t+f).to_f
223
+ end
224
+
219
225
  private
226
+
220
227
  def to_ms(number)
221
228
  (number*1000).round
222
229
  end
223
- # utility method that converts floating point percentage values
224
- # to integers as a percentage, to improve readability in ui
225
- def to_percentage(value)
226
- round_to_2(value * 100)
227
- end
228
-
229
- def round_to_2(val)
230
- (val * 100).round / 100.0
231
- end
230
+
232
231
  def round_to_3(val)
233
232
  (val * 1000).round / 1000.0
234
233
  end
@@ -321,6 +320,18 @@ module NewRelic
321
320
 
322
321
  alias trace_call record_data_point
323
322
 
323
+ def record_multiple_data_points(total_value, count=1)
324
+ return record_data_point(total_value) if count == 1
325
+ @call_count += count
326
+ @total_call_time += total_value
327
+ avg_val = total_value / count
328
+ @min_call_time = avg_val if avg_val < @min_call_time || @call_count == count
329
+ @max_call_time = avg_val if avg_val > @max_call_time
330
+ @total_exclusive_time += total_value
331
+ @sum_of_squares += (avg_val * avg_val) * count
332
+ self
333
+ end
334
+
324
335
  def increment_count(value = 1)
325
336
  @call_count += value
326
337
  end
@@ -329,14 +340,17 @@ module NewRelic
329
340
 
330
341
  class ScopedMethodTraceStats < MethodTraceStats
331
342
  def initialize(unscoped_stats)
332
- super()
343
+ super()
333
344
  @unscoped_stats = unscoped_stats
334
345
  end
335
-
336
346
  def trace_call(call_time, exclusive_time = call_time)
337
347
  @unscoped_stats.trace_call call_time, exclusive_time
338
348
  super call_time, exclusive_time
339
349
  end
350
+ def record_multiple_data_points(total_value, count=1)
351
+ @unscoped_stats.record_multiple_data_points(total_value, count)
352
+ super total_value, count
353
+ end
340
354
  def unscoped_stats
341
355
  @unscoped_stats
342
356
  end