newrelic_rpm 2.13.0.beta5 → 2.13.1

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 (86) hide show
  1. data/CHANGELOG +4 -0
  2. data/lib/new_relic/agent.rb +50 -50
  3. data/lib/new_relic/agent/agent.rb +24 -19
  4. data/lib/new_relic/agent/busy_calculator.rb +22 -22
  5. data/lib/new_relic/agent/chained_call.rb +3 -3
  6. data/lib/new_relic/agent/error_collector.rb +19 -19
  7. data/lib/new_relic/agent/instrumentation/active_record_instrumentation.rb +11 -11
  8. data/lib/new_relic/agent/instrumentation/acts_as_solr.rb +2 -2
  9. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +43 -43
  10. data/lib/new_relic/agent/instrumentation/data_mapper.rb +6 -6
  11. data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +2 -2
  12. data/lib/new_relic/agent/instrumentation/memcache.rb +8 -8
  13. data/lib/new_relic/agent/instrumentation/merb/controller.rb +4 -4
  14. data/lib/new_relic/agent/instrumentation/metric_frame.rb +307 -303
  15. data/lib/new_relic/agent/instrumentation/passenger_instrumentation.rb +8 -8
  16. data/lib/new_relic/agent/instrumentation/rack.rb +2 -2
  17. data/lib/new_relic/agent/instrumentation/rails/action_controller.rb +10 -10
  18. data/lib/new_relic/agent/instrumentation/rails/action_web_service.rb +3 -3
  19. data/lib/new_relic/agent/instrumentation/rails/errors.rb +5 -5
  20. data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +5 -5
  21. data/lib/new_relic/agent/instrumentation/sinatra.rb +5 -5
  22. data/lib/new_relic/agent/instrumentation/sunspot.rb +1 -1
  23. data/lib/new_relic/agent/method_tracer.rb +55 -55
  24. data/lib/new_relic/agent/sampler.rb +42 -38
  25. data/lib/new_relic/agent/samplers/cpu_sampler.rb +4 -4
  26. data/lib/new_relic/agent/samplers/delayed_job_lock_sampler.rb +7 -7
  27. data/lib/new_relic/agent/samplers/memory_sampler.rb +11 -11
  28. data/lib/new_relic/agent/samplers/object_sampler.rb +1 -1
  29. data/lib/new_relic/agent/shim_agent.rb +20 -16
  30. data/lib/new_relic/agent/stats_engine.rb +3 -3
  31. data/lib/new_relic/agent/stats_engine/metric_stats.rb +28 -28
  32. data/lib/new_relic/agent/stats_engine/samplers.rb +16 -16
  33. data/lib/new_relic/agent/stats_engine/transactions.rb +25 -25
  34. data/lib/new_relic/agent/transaction_sampler.rb +68 -69
  35. data/lib/new_relic/agent/worker_loop.rb +13 -13
  36. data/lib/new_relic/collection_helper.rb +6 -6
  37. data/lib/new_relic/command.rb +14 -14
  38. data/lib/new_relic/commands/deployments.rb +19 -19
  39. data/lib/new_relic/commands/install.rb +25 -15
  40. data/lib/new_relic/control.rb +25 -25
  41. data/lib/new_relic/control/configuration.rb +17 -17
  42. data/lib/new_relic/control/frameworks/external.rb +3 -3
  43. data/lib/new_relic/control/frameworks/merb.rb +6 -6
  44. data/lib/new_relic/control/frameworks/rails.rb +17 -17
  45. data/lib/new_relic/control/frameworks/rails3.rb +11 -27
  46. data/lib/new_relic/control/frameworks/ruby.rb +6 -6
  47. data/lib/new_relic/control/frameworks/sinatra.rb +4 -4
  48. data/lib/new_relic/control/instrumentation.rb +8 -8
  49. data/lib/new_relic/control/logging_methods.rb +13 -13
  50. data/lib/new_relic/control/profiling.rb +2 -2
  51. data/lib/new_relic/control/server_methods.rb +17 -17
  52. data/lib/new_relic/delayed_job_injection.rb +1 -1
  53. data/lib/new_relic/histogram.rb +73 -71
  54. data/lib/new_relic/local_environment.rb +45 -45
  55. data/lib/new_relic/merbtasks.rb +1 -1
  56. data/lib/new_relic/metric_data.rb +5 -5
  57. data/lib/new_relic/metric_parser.rb +22 -22
  58. data/lib/new_relic/metric_parser/action_mailer.rb +4 -4
  59. data/lib/new_relic/metric_parser/active_merchant.rb +8 -8
  60. data/lib/new_relic/metric_parser/active_record.rb +2 -2
  61. data/lib/new_relic/metric_parser/apdex.rb +86 -51
  62. data/lib/new_relic/metric_parser/controller.rb +10 -10
  63. data/lib/new_relic/metric_parser/controller_cpu.rb +5 -5
  64. data/lib/new_relic/metric_parser/errors.rb +1 -1
  65. data/lib/new_relic/metric_parser/external.rb +3 -3
  66. data/lib/new_relic/metric_parser/mem_cache.rb +2 -2
  67. data/lib/new_relic/metric_parser/other_transaction.rb +7 -7
  68. data/lib/new_relic/metric_parser/view.rb +5 -5
  69. data/lib/new_relic/metric_parser/web_frontend.rb +1 -1
  70. data/lib/new_relic/metric_parser/web_service.rb +1 -1
  71. data/lib/new_relic/metric_spec.rb +13 -13
  72. data/lib/new_relic/noticed_error.rb +4 -4
  73. data/lib/new_relic/rack/developer_mode.rb +33 -33
  74. data/lib/new_relic/rack/metric_app.rb +2 -2
  75. data/lib/new_relic/recipes.rb +9 -9
  76. data/lib/new_relic/stats.rb +57 -57
  77. data/lib/new_relic/timer_lib.rb +2 -2
  78. data/lib/new_relic/transaction_analysis.rb +19 -19
  79. data/lib/new_relic/transaction_sample.rb +101 -101
  80. data/lib/new_relic/url_rule.rb +3 -3
  81. data/lib/new_relic/version.rb +10 -10
  82. data/lib/newrelic_rpm.rb +6 -4
  83. data/lib/tasks/all.rb +1 -1
  84. data/newrelic_rpm.gemspec +3 -3
  85. data/test/new_relic/rack/episodes_test.rb +1 -0
  86. metadata +24 -42
@@ -1,4 +1,4 @@
1
- # A Sampler is used to capture meaningful metrics in a background thread
1
+ # A Sampler is used to capture meaningful metrics in a background thread
2
2
  # periodically. They will either be invoked once a minute just before the
3
3
  # data is sent to the agent (default) or every 10 seconds, when #use_harvest_sampler?
4
4
  # returns false.
@@ -6,41 +6,45 @@
6
6
  # Samplers can be added to New Relic by subclassing NewRelic::Agent::Sampler.
7
7
  # Instances are created when the agent is enabled and installed. Subclasses
8
8
  # are registered for instantiation automatically.
9
- class NewRelic::Agent::Sampler
10
-
11
- # Exception denotes a sampler is not available and it will not be registered.
12
- class Unsupported < StandardError; end
13
-
14
- attr_accessor :stats_engine
15
- attr_reader :id
16
- @sampler_classes = []
17
-
18
- def self.inherited(subclass)
19
- @sampler_classes << subclass
9
+ module NewRelic
10
+ module Agent
11
+ class Sampler
12
+
13
+ # Exception denotes a sampler is not available and it will not be registered.
14
+ class Unsupported < StandardError; end
15
+
16
+ attr_accessor :stats_engine
17
+ attr_reader :id
18
+ @sampler_classes = []
19
+
20
+ def self.inherited(subclass)
21
+ @sampler_classes << subclass
22
+ end
23
+
24
+ # Override with check. Called before instantiating.
25
+ def self.supported_on_this_platform?
26
+ true
27
+ end
28
+
29
+ # Override to use the periodic sampler instead of running the sampler on the
30
+ # minute during harvests.
31
+ def self.use_harvest_sampler?
32
+ true
33
+ end
34
+
35
+ def self.sampler_classes
36
+ @sampler_classes
37
+ end
38
+
39
+ def initialize(id)
40
+ @id = id
41
+ end
42
+
43
+ def poll
44
+ raise "Implement in the subclass"
45
+ end
46
+
47
+
48
+ end
20
49
  end
21
-
22
- # Override with check. Called before instantiating.
23
- def self.supported_on_this_platform?
24
- true
25
- end
26
-
27
- # Override to use the periodic sampler instead of running the sampler on the
28
- # minute during harvests.
29
- def self.use_harvest_sampler?
30
- true
31
- end
32
-
33
- def self.sampler_classes
34
- @sampler_classes
35
- end
36
-
37
- def initialize(id)
38
- @id = id
39
- end
40
-
41
- def poll
42
- raise "Implement in the subclass"
43
- end
44
-
45
-
46
- end
50
+ end
@@ -7,7 +7,7 @@ module NewRelic
7
7
  super :cpu
8
8
  poll
9
9
  end
10
-
10
+
11
11
  def user_util_stats
12
12
  stats_engine.get_stats_no_scope("CPU/User/Utilization")
13
13
  end
@@ -20,11 +20,11 @@ module NewRelic
20
20
  def systemtime_stats
21
21
  stats_engine.get_stats_no_scope("CPU/System Time")
22
22
  end
23
-
23
+
24
24
  def self.supported_on_this_platform?
25
25
  not defined?(JRuby)
26
26
  end
27
-
27
+
28
28
  def poll
29
29
  now = Time.now
30
30
  t = Process.times
@@ -37,7 +37,7 @@ module NewRelic
37
37
 
38
38
  systemtime_stats.record_data_point(systemtime) if systemtime >= 0
39
39
  usertime_stats.record_data_point(usertime) if usertime >= 0
40
-
40
+
41
41
  # Calculate the true utilization by taking cpu times and dividing by
42
42
  # elapsed time X num_processors.
43
43
  user_util_stats.record_data_point usertime / (elapsed * num_processors)
@@ -4,30 +4,30 @@ module NewRelic
4
4
  class DelayedJobLockSampler < NewRelic::Agent::Sampler
5
5
  def initialize
6
6
  super :delayed_job_lock
7
- raise Unsupported, "DJ instrumentation disabled" if NewRelic::Control.instance['disable_dj']
7
+ raise Unsupported, "DJ instrumentation disabled" if NewRelic::Control.instance['disable_dj']
8
8
  raise Unsupported, "No DJ worker present" unless NewRelic::DelayedJobInjection.worker_name
9
9
  end
10
-
10
+
11
11
  def stats
12
12
  stats_engine.get_stats("Custom/DJ Locked Jobs", false)
13
13
  end
14
-
14
+
15
15
  def local_env
16
16
  NewRelic::Control.instance.local_env
17
17
  end
18
-
18
+
19
19
  def worker_name
20
20
  local_env.dispatcher_instance_id
21
21
  end
22
-
22
+
23
23
  def locked_jobs
24
24
  Delayed::Job.count(:conditions => {:locked_by => NewRelic::DelayedJobInjection.worker_name})
25
25
  end
26
-
26
+
27
27
  def self.supported_on_this_platform?
28
28
  defined?(Delayed::Job)
29
29
  end
30
-
30
+
31
31
  def poll
32
32
  stats.record_data_point locked_jobs
33
33
  end
@@ -1,10 +1,10 @@
1
1
  module NewRelic
2
2
  module Agent
3
3
  module Samplers
4
-
4
+
5
5
  class MemorySampler < NewRelic::Agent::Sampler
6
6
  attr_accessor :sampler
7
-
7
+
8
8
  def initialize
9
9
  super :memory
10
10
  # macos, linux, solaris
@@ -27,11 +27,11 @@ module Samplers
27
27
  elsif platform =~ /solaris/
28
28
  @sampler = ShellPS.new("/usr/bin/ps -o rss -p")
29
29
  end
30
-
30
+
31
31
  raise Unsupported, "Unsupported platform for getting memory: #{platform}" if @sampler.nil?
32
32
  raise Unsupported, "Unable to run #{@sampler}" unless @sampler.can_run?
33
33
  end
34
-
34
+
35
35
  def self.supported_on_this_platform?
36
36
  defined?(JRuby) or platform =~ /linux|darwin9|darwin10|freebsd|solaris/
37
37
  end
@@ -48,7 +48,7 @@ module Samplers
48
48
  end
49
49
 
50
50
  def stats
51
- stats_engine.get_stats("Memory/Physical", false)
51
+ stats_engine.get_stats("Memory/Physical", false)
52
52
  end
53
53
  def poll
54
54
  sample = @sampler.get_sample
@@ -110,18 +110,18 @@ module Samplers
110
110
  "shell command sampler: #{@command}"
111
111
  end
112
112
  end
113
-
113
+
114
114
  # ProcStatus
115
115
  #
116
116
  # A class that samples memory by reading the file /proc/$$/status, which is specific to linux
117
117
  #
118
- class ProcStatus < Base
119
-
118
+ class ProcStatus < Base
119
+
120
120
  # Returns the amount of resident memory this process is using in MB
121
121
  #
122
122
  def get_memory
123
123
  File.open(proc_status_file, "r") do |f|
124
- while !f.eof?
124
+ while !f.eof?
125
125
  if f.readline =~ /RSS:\s*(\d+) kB/i
126
126
  return $1.to_f / 1024.0
127
127
  end
@@ -136,7 +136,7 @@ module Samplers
136
136
  "proc status file sampler: #{proc_status_file}"
137
137
  end
138
138
  end
139
- end
140
- end
139
+ end
140
+ end
141
141
  end
142
142
  end
@@ -8,7 +8,7 @@ module NewRelic
8
8
  end
9
9
 
10
10
  def stats
11
- stats_engine.get_stats_no_scope("GC/objects")
11
+ stats_engine.get_stats_no_scope("GC/objects")
12
12
  end
13
13
 
14
14
  def self.supported_on_this_platform?
@@ -1,21 +1,25 @@
1
1
  # This agent is loaded by the plug when the plug-in is disabled
2
2
  # It recreates just enough of the API to not break any clients that
3
3
  # invoke the Agent.
4
- class NewRelic::Agent::ShimAgent < NewRelic::Agent::Agent
5
- def self.instance
6
- @instance ||= self.new
7
- end
8
- def initialize
9
- super
10
- @histogram.extend NewRelic::Histogram::Shim
11
- @stats_engine.extend NewRelic::Agent::StatsEngine::Shim
12
- @stats_engine.extend NewRelic::Agent::StatsEngine::Transactions::Shim
13
- @transaction_sampler.extend NewRelic::Agent::TransactionSampler::Shim
14
- @error_collector.extend NewRelic::Agent::ErrorCollector::Shim
4
+ module NewRelic
5
+ module Agent
6
+ class ShimAgent < NewRelic::Agent::Agent
7
+ def self.instance
8
+ @instance ||= self.new
9
+ end
10
+ def initialize
11
+ super
12
+ @histogram.extend NewRelic::Histogram::Shim
13
+ @stats_engine.extend NewRelic::Agent::StatsEngine::Shim
14
+ @stats_engine.extend NewRelic::Agent::StatsEngine::Transactions::Shim
15
+ @transaction_sampler.extend NewRelic::Agent::TransactionSampler::Shim
16
+ @error_collector.extend NewRelic::Agent::ErrorCollector::Shim
17
+ end
18
+ def after_fork *args; end
19
+ def start *args; end
20
+ def shutdown; end
21
+ def push_trace_execution_flag(*args); end
22
+ def pop_trace_execution_flag(*args); end
23
+ end
15
24
  end
16
- def after_fork *args; end
17
- def start *args; end
18
- def shutdown; end
19
- def push_trace_execution_flag(*args); end
20
- def pop_trace_execution_flag(*args); end
21
25
  end
@@ -8,17 +8,17 @@ module NewRelic
8
8
  include MetricStats
9
9
  include Samplers
10
10
  include Transactions
11
-
11
+
12
12
  def initialize
13
13
  # Makes the unit tests happy
14
14
  Thread::current[:newrelic_scope_stack] = nil
15
15
  start_sampler_thread
16
16
  end
17
-
17
+
18
18
  def log
19
19
  NewRelic::Control.instance.log
20
20
  end
21
-
21
+
22
22
  end
23
23
  end
24
24
  end
@@ -11,35 +11,35 @@ module Agent
11
11
  def metrics
12
12
  stats_hash.keys.map(&:to_s)
13
13
  end
14
-
14
+
15
15
  def get_stats_no_scope(metric_name)
16
- stats_hash[metric_name] ||= NewRelic::MethodTraceStats.new
16
+ stats_hash[metric_name] ||= NewRelic::MethodTraceStats.new
17
17
  end
18
-
18
+
19
19
  # This version allows a caller to pass a stat class to use
20
20
  #
21
21
  def get_custom_stats(metric_name, stat_class)
22
22
  stats_hash[metric_name] ||= stat_class.new
23
23
  end
24
-
24
+
25
25
  # If use_scope is true, two chained metrics are created, one with scope and one without
26
26
  # If scoped_metric_only is true, only a scoped metric is created (used by rendering metrics which by definition are per controller only)
27
27
  def get_stats(metric_name, use_scope = true, scoped_metric_only = false, scope = nil)
28
28
  scope ||= scope_name if use_scope
29
29
  if scoped_metric_only
30
30
  spec = NewRelic::MetricSpec.new metric_name, scope
31
- stats = stats_hash[spec] ||= NewRelic::MethodTraceStats.new
32
- else
33
- stats = stats_hash[metric_name] ||= NewRelic::MethodTraceStats.new
34
- if scope && scope != metric_name
31
+ stats = stats_hash[spec] ||= NewRelic::MethodTraceStats.new
32
+ else
33
+ stats = stats_hash[metric_name] ||= NewRelic::MethodTraceStats.new
34
+ if scope && scope != metric_name
35
35
  spec = NewRelic::MetricSpec.new metric_name, scope
36
- scoped_stats = stats_hash[spec] ||= NewRelic::ScopedMethodTraceStats.new(stats)
36
+ scoped_stats = stats_hash[spec] ||= NewRelic::ScopedMethodTraceStats.new(stats)
37
37
  stats = scoped_stats
38
38
  end
39
39
  end
40
40
  stats
41
41
  end
42
-
42
+
43
43
  def lookup_stats(metric_name, scope_name = nil)
44
44
  stats_hash[NewRelic::MetricSpec.new(metric_name, scope_name)] ||
45
45
  stats_hash[metric_name]
@@ -47,7 +47,7 @@ module Agent
47
47
  # Harvest the timeslice data. First recombine current statss
48
48
  # with any previously
49
49
  # unsent metrics, clear out stats cache, and return the current
50
- # stats.
50
+ # stats.
51
51
  # ---
52
52
  # Note: this is not synchronized. There is still some risk in this and
53
53
  # we will revisit later to see if we can make this more robust without
@@ -57,58 +57,58 @@ module Agent
57
57
  timeslice_data = {}
58
58
  poll harvest_samplers
59
59
  stats_hash.keys.each do | metric_spec |
60
-
61
-
60
+
61
+
62
62
  # get a copy of the stats collected since the last harvest, and clear
63
63
  # the stats inside our hash table for the next time slice.
64
64
  stats = stats_hash[metric_spec]
65
-
65
+
66
66
  # we have an optimization for unscoped metrics
67
67
  if !(metric_spec.is_a? NewRelic::MetricSpec)
68
68
  metric_spec = NewRelic::MetricSpec.new metric_spec
69
69
  end
70
-
71
- if stats.nil?
70
+
71
+ if stats.nil?
72
72
  raise "Nil stats for #{metric_spec.name} (#{metric_spec.scope})"
73
73
  end
74
-
74
+
75
75
  stats_copy = stats.clone
76
76
  stats.reset
77
-
77
+
78
78
  # if the previous timeslice data has not been reported (due to an error of some sort)
79
79
  # then we need to merge this timeslice with the previously accumulated - but not sent
80
80
  # data
81
81
  previous_metric_data = previous_timeslice_data[metric_spec]
82
82
  stats_copy.merge! previous_metric_data.stats unless previous_metric_data.nil?
83
83
  stats_copy.round!
84
-
84
+
85
85
  # don't bother collecting and reporting stats that have zero-values for this timeslice.
86
86
  # significant performance boost and storage savings.
87
87
  unless stats_copy.is_reset?
88
88
 
89
89
  id = metric_ids[metric_spec]
90
- metric_spec_for_transport = id ? nil : metric_spec
91
-
90
+ metric_spec_for_transport = id ? nil : metric_spec
91
+
92
92
  metric_data = NewRelic::MetricData.new(metric_spec_for_transport, stats_copy, id)
93
-
93
+
94
94
  timeslice_data[metric_spec] = metric_data
95
95
  end
96
96
  end
97
-
97
+
98
98
  timeslice_data
99
99
  end
100
-
100
+
101
101
  # Remove all stats. For test code only.
102
- def clear_stats
102
+ def clear_stats
103
103
  stats_hash.clear
104
104
  NewRelic::Agent::BusyCalculator.reset
105
105
  end
106
-
106
+
107
107
  # Reset each of the stats, such as when a new passenger instance starts up.
108
- def reset_stats
108
+ def reset_stats
109
109
  stats_hash.values.each { |s| s.reset }
110
110
  end
111
-
111
+
112
112
  def stats_hash
113
113
  @stats_hash ||= {}
114
114
  end
@@ -6,21 +6,21 @@ module Agent
6
6
  def add_harvest_sampler(*args); end
7
7
  def start_sampler_thread(*args); end
8
8
  end
9
-
9
+
10
10
  module Samplers
11
-
12
- # By default a sampler polls on harvest time, once a minute. However you can
11
+
12
+ # By default a sampler polls on harvest time, once a minute. However you can
13
13
  # override #use_harvest_sampler? to return false and it will sample
14
14
  # every POLL_PERIOD seconds on a background thread.
15
15
  POLL_PERIOD = 20
16
-
16
+
17
17
  def start_sampler_thread
18
-
18
+
19
19
  return if @sampler_thread && @sampler_thread.alive?
20
-
20
+
21
21
  # start up a thread that will periodically poll for metric samples
22
22
  return if periodic_samplers.empty?
23
-
23
+
24
24
  @sampler_thread = Thread.new do
25
25
  while true do
26
26
  begin
@@ -31,18 +31,18 @@ module Agent
31
31
  end
32
32
  @sampler_thread['newrelic_label'] = 'Sampler Tasks'
33
33
  end
34
-
34
+
35
35
  # Add an instance of Sampler to be invoked about every 10 seconds on a background
36
36
  # thread.
37
37
  def add_sampler sampler
38
38
  periodic_samplers.each do |s|
39
- raise "Sampler #{sampler.id} is already registered. Don't call add_sampler directly anymore." if s.id == sampler.id
39
+ raise "Sampler #{sampler.object_id} is already registered. Don't call add_sampler directly anymore." if s.object_id == sampler.object_id
40
40
  end
41
41
  periodic_samplers << sampler
42
42
  sampler.stats_engine = self
43
- log.debug "Adding sampler #{sampler.id.to_s}"
43
+ log.debug "Adding sampler #{sampler.object_id.to_s}"
44
44
  end
45
-
45
+
46
46
  # Add a sampler to be invoked just before each harvest.
47
47
  def add_harvest_sampler sampler
48
48
  harvest_samplers.each do |s|
@@ -51,15 +51,15 @@ module Agent
51
51
  harvest_samplers << sampler
52
52
  sampler.stats_engine = self
53
53
  log.debug "Adding harvest time sampler: #{sampler.id.to_s}"
54
- end
55
-
54
+ end
55
+
56
56
  private
57
-
57
+
58
58
  # Call poll on each of the samplers. Remove
59
59
  # the sampler if it raises.
60
60
  def poll(samplers)
61
61
  samplers.delete_if do |sampled_item|
62
- begin
62
+ begin
63
63
  sampled_item.poll
64
64
  false # it's okay. don't delete it.
65
65
  rescue Exception => e
@@ -70,7 +70,7 @@ module Agent
70
70
  end
71
71
  end
72
72
  end
73
-
73
+
74
74
  def harvest_samplers
75
75
  @harvest_samplers ||= []
76
76
  end