newrelic_rpm 2.8.0

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 (107) hide show
  1. data/LICENSE +37 -0
  2. data/README +93 -0
  3. data/Rakefile +38 -0
  4. data/install.rb +37 -0
  5. data/lib/new_relic/agent.rb +26 -0
  6. data/lib/new_relic/agent/agent.rb +762 -0
  7. data/lib/new_relic/agent/chained_call.rb +13 -0
  8. data/lib/new_relic/agent/collection_helper.rb +81 -0
  9. data/lib/new_relic/agent/error_collector.rb +105 -0
  10. data/lib/new_relic/agent/instrumentation/active_record_instrumentation.rb +95 -0
  11. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +151 -0
  12. data/lib/new_relic/agent/instrumentation/data_mapper.rb +90 -0
  13. data/lib/new_relic/agent/instrumentation/dispatcher_instrumentation.rb +105 -0
  14. data/lib/new_relic/agent/instrumentation/memcache.rb +18 -0
  15. data/lib/new_relic/agent/instrumentation/merb/controller.rb +17 -0
  16. data/lib/new_relic/agent/instrumentation/merb/dispatcher.rb +15 -0
  17. data/lib/new_relic/agent/instrumentation/merb/errors.rb +6 -0
  18. data/lib/new_relic/agent/instrumentation/rails/action_controller.rb +35 -0
  19. data/lib/new_relic/agent/instrumentation/rails/action_web_service.rb +27 -0
  20. data/lib/new_relic/agent/instrumentation/rails/dispatcher.rb +30 -0
  21. data/lib/new_relic/agent/instrumentation/rails/errors.rb +23 -0
  22. data/lib/new_relic/agent/instrumentation/rails/rails.rb +6 -0
  23. data/lib/new_relic/agent/method_tracer.rb +171 -0
  24. data/lib/new_relic/agent/patch_const_missing.rb +31 -0
  25. data/lib/new_relic/agent/samplers/cpu.rb +29 -0
  26. data/lib/new_relic/agent/samplers/memory.rb +55 -0
  27. data/lib/new_relic/agent/samplers/mongrel.rb +26 -0
  28. data/lib/new_relic/agent/stats_engine.rb +241 -0
  29. data/lib/new_relic/agent/synchronize.rb +40 -0
  30. data/lib/new_relic/agent/transaction_sampler.rb +281 -0
  31. data/lib/new_relic/agent/worker_loop.rb +128 -0
  32. data/lib/new_relic/api/deployments.rb +92 -0
  33. data/lib/new_relic/config.rb +194 -0
  34. data/lib/new_relic/config/merb.rb +35 -0
  35. data/lib/new_relic/config/rails.rb +113 -0
  36. data/lib/new_relic/config/ruby.rb +9 -0
  37. data/lib/new_relic/local_environment.rb +108 -0
  38. data/lib/new_relic/merbtasks.rb +6 -0
  39. data/lib/new_relic/metric_data.rb +26 -0
  40. data/lib/new_relic/metric_spec.rb +39 -0
  41. data/lib/new_relic/metrics.rb +7 -0
  42. data/lib/new_relic/noticed_error.rb +21 -0
  43. data/lib/new_relic/shim_agent.rb +95 -0
  44. data/lib/new_relic/stats.rb +359 -0
  45. data/lib/new_relic/transaction_analysis.rb +122 -0
  46. data/lib/new_relic/transaction_sample.rb +499 -0
  47. data/lib/new_relic/version.rb +111 -0
  48. data/lib/new_relic_api.rb +275 -0
  49. data/lib/newrelic_rpm.rb +27 -0
  50. data/lib/tasks/agent_tests.rake +14 -0
  51. data/lib/tasks/all.rb +4 -0
  52. data/lib/tasks/install.rake +7 -0
  53. data/newrelic.yml +137 -0
  54. data/recipes/newrelic.rb +46 -0
  55. data/test/config/newrelic.yml +26 -0
  56. data/test/config/test_config.rb +9 -0
  57. data/test/new_relic/agent/mock_ar_connection.rb +40 -0
  58. data/test/new_relic/agent/mock_scope_listener.rb +23 -0
  59. data/test/new_relic/agent/model_fixture.rb +17 -0
  60. data/test/new_relic/agent/tc_active_record.rb +91 -0
  61. data/test/new_relic/agent/tc_agent.rb +112 -0
  62. data/test/new_relic/agent/tc_collection_helper.rb +104 -0
  63. data/test/new_relic/agent/tc_controller.rb +98 -0
  64. data/test/new_relic/agent/tc_dispatcher_instrumentation.rb +52 -0
  65. data/test/new_relic/agent/tc_error_collector.rb +127 -0
  66. data/test/new_relic/agent/tc_method_tracer.rb +306 -0
  67. data/test/new_relic/agent/tc_stats_engine.rb +218 -0
  68. data/test/new_relic/agent/tc_synchronize.rb +37 -0
  69. data/test/new_relic/agent/tc_transaction_sample.rb +175 -0
  70. data/test/new_relic/agent/tc_transaction_sample_builder.rb +200 -0
  71. data/test/new_relic/agent/tc_transaction_sampler.rb +305 -0
  72. data/test/new_relic/agent/tc_worker_loop.rb +101 -0
  73. data/test/new_relic/agent/testable_agent.rb +13 -0
  74. data/test/new_relic/tc_config.rb +36 -0
  75. data/test/new_relic/tc_deployments_api.rb +37 -0
  76. data/test/new_relic/tc_environment.rb +94 -0
  77. data/test/new_relic/tc_metric_spec.rb +150 -0
  78. data/test/new_relic/tc_shim_agent.rb +9 -0
  79. data/test/new_relic/tc_stats.rb +141 -0
  80. data/test/test_helper.rb +39 -0
  81. data/test/ui/tc_newrelic_helper.rb +44 -0
  82. data/ui/controllers/newrelic_controller.rb +200 -0
  83. data/ui/helpers/google_pie_chart.rb +55 -0
  84. data/ui/helpers/newrelic_helper.rb +286 -0
  85. data/ui/views/layouts/newrelic_default.rhtml +49 -0
  86. data/ui/views/newrelic/_explain_plans.rhtml +27 -0
  87. data/ui/views/newrelic/_sample.rhtml +12 -0
  88. data/ui/views/newrelic/_segment.rhtml +28 -0
  89. data/ui/views/newrelic/_segment_row.rhtml +14 -0
  90. data/ui/views/newrelic/_show_sample_detail.rhtml +22 -0
  91. data/ui/views/newrelic/_show_sample_sql.rhtml +19 -0
  92. data/ui/views/newrelic/_show_sample_summary.rhtml +3 -0
  93. data/ui/views/newrelic/_sql_row.rhtml +11 -0
  94. data/ui/views/newrelic/_stack_trace.rhtml +30 -0
  95. data/ui/views/newrelic/_table.rhtml +12 -0
  96. data/ui/views/newrelic/explain_sql.rhtml +45 -0
  97. data/ui/views/newrelic/images/arrow-close.png +0 -0
  98. data/ui/views/newrelic/images/arrow-open.png +0 -0
  99. data/ui/views/newrelic/images/blue_bar.gif +0 -0
  100. data/ui/views/newrelic/images/gray_bar.gif +0 -0
  101. data/ui/views/newrelic/index.rhtml +37 -0
  102. data/ui/views/newrelic/javascript/transaction_sample.js +107 -0
  103. data/ui/views/newrelic/sample_not_found.rhtml +2 -0
  104. data/ui/views/newrelic/show_sample.rhtml +62 -0
  105. data/ui/views/newrelic/show_source.rhtml +3 -0
  106. data/ui/views/newrelic/stylesheets/style.css +394 -0
  107. metadata +180 -0
@@ -0,0 +1,98 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__),'..','..','test_helper'))
2
+ require 'action_controller/base'
3
+
4
+
5
+ class AgentTestController < ActionController::Base
6
+ filter_parameter_logging :social_security_number
7
+ def index
8
+ render :text => params.inspect
9
+ end
10
+ def _filter_parameters(params)
11
+ filter_parameters params
12
+ end
13
+ def action_to_render
14
+ render :text => params.inspect
15
+ end
16
+ def action_to_ignore
17
+ render :text => 'unmeasured'
18
+ end
19
+ def entry_action
20
+ perform_action_with_newrelic_trace('internal_action') do
21
+ internal_action
22
+ end
23
+ end
24
+ private
25
+ def internal_action
26
+ render :text => 'internal action'
27
+ end
28
+ end
29
+
30
+ class AgentControllerTests < ActionController::TestCase
31
+
32
+ self.controller_class = AgentTestController
33
+
34
+ attr_accessor :agent
35
+
36
+ def setup
37
+ super
38
+ Thread.current[:controller_ignored] = nil
39
+ @agent = NewRelic::Agent.instance
40
+ # @agent.instrument_app
41
+ agent.start :test, :test
42
+ agent.transaction_sampler.harvest_slowest_sample
43
+ AgentTestController.class_eval do
44
+ newrelic_ignore :only => [:action_to_ignore, :entry_action]
45
+ end
46
+ end
47
+
48
+ def teardown
49
+ NewRelic::Agent.instance.shutdown
50
+ Thread.current[:controller_ignored] = nil
51
+ super
52
+ end
53
+ def test_metric__ignore
54
+ engine = @agent.stats_engine
55
+ get :action_to_ignore
56
+ assert_equal true, Thread.current[:controller_ignored]
57
+ end
58
+ def test_metric__no_ignore
59
+ engine = @agent.stats_engine
60
+ index_stats = engine.get_stats_no_scope('Controller/agent_test/index')
61
+ assert_difference 'index_stats.call_count' do
62
+ get :index
63
+ end
64
+ assert_equal false, Thread.current[:controller_ignored]
65
+ end
66
+ def test_metric__dispatched
67
+ engine = @agent.stats_engine
68
+ get :entry_action
69
+ assert_equal false, Thread.current[:controller_ignored]
70
+ assert_nil engine.lookup_stat('Controller/agent_test/entry_action')
71
+ assert_equal 1, engine.lookup_stat('Controller/agent_test/internal_action').call_count
72
+ end
73
+ def test_action_instrumentation
74
+ get :index, :foo => 'bar'
75
+ assert_match /bar/, @response.body
76
+ end
77
+
78
+ def test_controller_params
79
+
80
+ assert agent.transaction_sampler
81
+
82
+ num_samples = NewRelic::Agent.instance.transaction_sampler.get_samples.length
83
+
84
+ assert_equal "[FILTERED]", @controller._filter_parameters({'social_security_number' => 'test'})['social_security_number']
85
+
86
+ get :index, 'social_security_number' => "001-555-1212"
87
+
88
+ samples = agent.transaction_sampler.get_samples
89
+
90
+ agent.transaction_sampler.expects(:notice_transaction).never
91
+
92
+ assert_equal num_samples + 1, samples.length
93
+
94
+ assert_equal "[FILTERED]", samples.last.params[:request_params]["social_security_number"]
95
+
96
+ end
97
+
98
+ end
@@ -0,0 +1,52 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__),'..','..','test_helper'))
2
+
3
+ class NewRelic::Agent::DispatcherInstrumentationTests < Test::Unit::TestCase
4
+
5
+ class FunnyDispatcher
6
+ include NewRelic::Agent::Instrumentation::DispatcherInstrumentation
7
+ end
8
+ def setup
9
+ @instance_busy = NewRelic::Agent.agent.stats_engine.get_stats('Instance/Busy')
10
+ @dispatch_stat = NewRelic::Agent.agent.stats_engine.get_stats 'Rails/HTTP Dispatch'
11
+ @mongrel_queue_stat = NewRelic::Agent.agent.stats_engine.get_stats 'WebFrontend/Mongrel/Average Queue Time'
12
+
13
+ NewRelic::Agent::Instrumentation::DispatcherInstrumentation::BusyCalculator.harvest_busy
14
+ @instance_busy.reset
15
+ @dispatch_stat.reset
16
+ @mongrel_queue_stat.reset
17
+
18
+ end
19
+
20
+ def test_normal_call
21
+ d = FunnyDispatcher.new
22
+ assert !NewRelic::Agent::Instrumentation::DispatcherInstrumentation::BusyCalculator.is_busy?
23
+ d.newrelic_dispatcher_start
24
+ sleep 1.0
25
+ assert NewRelic::Agent::Instrumentation::DispatcherInstrumentation::BusyCalculator.is_busy?
26
+ d.newrelic_dispatcher_finish
27
+ assert !NewRelic::Agent::Instrumentation::DispatcherInstrumentation::BusyCalculator.is_busy?
28
+ assert_nil Thread.current[:newrelic_t0]
29
+ NewRelic::Agent::Instrumentation::DispatcherInstrumentation::BusyCalculator.harvest_busy
30
+
31
+ assert_equal 1, @instance_busy.call_count
32
+ assert_equal 1, @dispatch_stat.call_count
33
+ assert_equal 0, @mongrel_queue_stat.call_count
34
+ assert @dispatch_stat.total_call_time >= 1.0, "Total call time must be at least one second"
35
+ assert @instance_busy.total_call_time > 0.9 && @instance_busy.total_call_time <= 1.0, "instance busy = #{@instance_busy.inspect}"
36
+ end
37
+ def test_recursive_call
38
+ d = FunnyDispatcher.new
39
+ assert !NewRelic::Agent::Instrumentation::DispatcherInstrumentation::BusyCalculator.is_busy?
40
+ d.newrelic_dispatcher_start
41
+ assert NewRelic::Agent::Instrumentation::DispatcherInstrumentation::BusyCalculator.is_busy?
42
+ d.newrelic_dispatcher_start
43
+ assert NewRelic::Agent::Instrumentation::DispatcherInstrumentation::BusyCalculator.is_busy?
44
+ d.newrelic_dispatcher_finish
45
+ assert !NewRelic::Agent::Instrumentation::DispatcherInstrumentation::BusyCalculator.is_busy?
46
+ d.newrelic_dispatcher_finish
47
+ assert !NewRelic::Agent::Instrumentation::DispatcherInstrumentation::BusyCalculator.is_busy?
48
+ assert_nil Thread.current[:newrelic_t0]
49
+ NewRelic::Agent::Instrumentation::DispatcherInstrumentation::BusyCalculator.harvest_busy
50
+ assert_equal 1, @instance_busy.call_count
51
+ end
52
+ end
@@ -0,0 +1,127 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__),'..','..','test_helper'))
2
+ ##require 'new_relic/agent/error_collector'
3
+ require 'test/unit'
4
+
5
+ class NewRelic::Agent::ErrorCollectorTests < Test::Unit::TestCase
6
+
7
+ def setup
8
+ @error_collector = NewRelic::Agent::ErrorCollector.new(nil)
9
+ end
10
+
11
+ def test_simple
12
+ @error_collector.notice_error('path', '/myurl/', {:x => 'y'}, Exception.new("message"))
13
+
14
+ old_errors = []
15
+ errors = @error_collector.harvest_errors(old_errors)
16
+
17
+ assert_equal errors.length, 1
18
+
19
+ err = errors.first
20
+ assert_equal 'message', err.message
21
+ assert_equal 'y', err.params[:request_params][:x]
22
+ assert err.params[:request_uri] == '/myurl/'
23
+ assert err.path == 'path'
24
+ assert err.exception_class == 'Exception'
25
+
26
+ # the collector should now return an empty array since nothing
27
+ # has been added since its last harvest
28
+ errors = @error_collector.harvest_errors(nil)
29
+ assert errors.length == 0
30
+ end
31
+
32
+ def test_collect_failover
33
+ @error_collector.notice_error('first', nil, {:x => 'y'}, Exception.new("message"))
34
+
35
+ errors = @error_collector.harvest_errors([])
36
+
37
+ @error_collector.notice_error('second', nil, {:x => 'y'}, Exception.new("message"))
38
+ @error_collector.notice_error('path', nil, {:x => 'y'}, Exception.new("message"))
39
+ @error_collector.notice_error('path', nil, {:x => 'y'}, Exception.new("message"))
40
+
41
+ errors = @error_collector.harvest_errors(errors)
42
+
43
+ assert_equal 1, errors.length
44
+ assert_equal 'first', errors.first.path
45
+
46
+ # add two more
47
+ @error_collector.notice_error('path', nil, {:x => 'y'}, Exception.new("message"))
48
+ @error_collector.notice_error('last', nil, {:x => 'y'}, Exception.new("message"))
49
+
50
+ errors = @error_collector.harvest_errors(nil)
51
+ assert_equal 5, errors.length
52
+ assert_equal 'second', errors.first.path
53
+ assert_equal 'last', errors.last.path
54
+
55
+ end
56
+
57
+ def test_queue_overflow
58
+
59
+ max_q_length = 20 # for some reason I can't read the constant in ErrorCollector
60
+
61
+ silence_stream(::STDERR) do
62
+ (max_q_length + 5).times do |n|
63
+ @error_collector.notice_error("path", nil, {:x => n}, Exception.new("exception #{n}"))
64
+ end
65
+ end
66
+
67
+ errors = @error_collector.harvest_errors([])
68
+ assert errors.length == max_q_length
69
+ errors.each_index do |i|
70
+ err = errors.shift
71
+ assert_equal i.to_s, err.params[:request_params][:x], err.params.inspect
72
+ end
73
+ end
74
+
75
+ # Why would anyone undef these methods?
76
+ class TestClass
77
+ undef to_s
78
+ undef inspect
79
+ end
80
+
81
+
82
+ def test_supported_param_types
83
+
84
+ types = [[1, '1'],
85
+ [1.1, '1.1'],
86
+ ['hi', 'hi'],
87
+ [:hi, :hi],
88
+ [Exception.new("test"), "#<Exception: test>"],
89
+ [TestClass.new, "#<NewRelic::Agent::ErrorCollectorTests::TestClass>"]
90
+ ]
91
+
92
+
93
+ types.each do |test|
94
+ @error_collector.notice_error('path', nil, {:x => test[0]}, Exception.new("message"))
95
+
96
+ assert_equal test[1], @error_collector.harvest_errors([])[0].params[:request_params][:x]
97
+ end
98
+ end
99
+
100
+
101
+ def test_exclude
102
+ @error_collector.ignore(["ActionController::RoutingError"])
103
+
104
+ @error_collector.notice_error('path', nil, {:x => 'y'}, ActionController::RoutingError.new("message"))
105
+
106
+ errors = @error_collector.harvest_errors([])
107
+
108
+ assert_equal 0, errors.length
109
+ end
110
+
111
+ def test_exclude_block
112
+ @error_collector.ignore_error_filter do |e|
113
+ if e.is_a? ActionController::RoutingError
114
+ nil
115
+ else
116
+ e
117
+ end
118
+ end
119
+
120
+ @error_collector.notice_error('path', nil, {:x => 'y'}, ActionController::RoutingError.new("message"))
121
+
122
+ errors = @error_collector.harvest_errors([])
123
+
124
+ assert_equal 0, errors.length
125
+ end
126
+
127
+ end
@@ -0,0 +1,306 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__),'..','..','test_helper'))
2
+ require 'new_relic/agent/mock_scope_listener'
3
+
4
+ ::RPM_TRACERS_ENABLED = true unless defined? ::RPM_TRACERS_ENABLED
5
+
6
+ class Module
7
+ def method_traced?(method_name, metric_name)
8
+ traced_method_prefix = _traced_method_name(method_name, metric_name)
9
+
10
+ method_defined? traced_method_prefix
11
+ end
12
+ end
13
+
14
+ class Insider
15
+ def initialize(stats_engine)
16
+ @stats_engine = stats_engine
17
+ end
18
+ def catcher(level=0)
19
+ thrower(level) if level>0
20
+ end
21
+ def thrower(level)
22
+ if level == 0
23
+ # don't use a real sampler because we can't instantiate one
24
+ # sampler = NewRelic::Agent::TransactionSampler.new(NewRelic::Agent.instance)
25
+ sampler = "<none>"
26
+ begin
27
+ @stats_engine.add_scope_stack_listener sampler
28
+ fail "This should not have worked."
29
+ rescue; end
30
+ else
31
+ thrower(level-1)
32
+ end
33
+ end
34
+ end
35
+
36
+ module NewRelic
37
+ module Agent
38
+
39
+ # for testing, enable the stats engine to clear itself
40
+ class StatsEngine
41
+ def reset
42
+ scope_stack.clear
43
+ @stats_hash.clear
44
+ end
45
+ end
46
+
47
+ extend self
48
+ def module_method_to_be_traced (x, testcase)
49
+ testcase.assert x == "x"
50
+ testcase.assert testcase.stats_engine.peek_scope.name == "x"
51
+ end
52
+ end
53
+ end
54
+
55
+ class NewRelic::Agent::MethodTracerTests < Test::Unit::TestCase
56
+ attr_reader :stats_engine
57
+
58
+ def setup
59
+ NewRelic::Agent::Agent.instance.shutdown
60
+ NewRelic::Agent::Agent.instance.start 'rake', 'test'
61
+ @stats_engine = NewRelic::Agent::Agent.instance.stats_engine
62
+ @stats_engine.reset
63
+ @scope_listener = NewRelic::Agent::MockScopeListener.new
64
+
65
+ @stats_engine.add_scope_stack_listener(@scope_listener)
66
+ end
67
+
68
+ def teardown
69
+ self.class.remove_method_tracer :method_to_be_traced, @metric_name if @metric_name
70
+ @metric_name = nil
71
+ NewRelic::Agent::Agent.instance.shutdown
72
+ end
73
+
74
+ def test_basic
75
+ metric = "hello"
76
+ t1 = Time.now
77
+ self.class.trace_method_execution_with_scope metric, true, true do
78
+ sleep 1
79
+ assert metric == @stats_engine.peek_scope.name
80
+ end
81
+ elapsed = Time.now - t1
82
+
83
+ stats = @stats_engine.get_stats(metric)
84
+ check_time stats.total_call_time, elapsed
85
+ assert stats.call_count == 1
86
+ end
87
+
88
+ def test_basic__original_api
89
+ metric = "hello"
90
+ t1 = Time.now
91
+ self.class.trace_method_execution metric, true, true, true do
92
+ sleep 1
93
+ assert metric == @stats_engine.peek_scope.name
94
+ end
95
+ elapsed = Time.now - t1
96
+
97
+ stats = @stats_engine.get_stats(metric)
98
+ check_time stats.total_call_time, elapsed
99
+ assert stats.call_count == 1
100
+ end
101
+
102
+ METRIC = "metric"
103
+ def test_add_method_tracer
104
+ @metric_name = METRIC
105
+ assert ::RPM_TRACERS_ENABLED
106
+ self.class.add_method_tracer :method_to_be_traced, METRIC
107
+
108
+ t1 = Time.now
109
+ method_to_be_traced 1,2,3,true,METRIC
110
+ elapsed = Time.now - t1
111
+
112
+ stats = @stats_engine.get_stats(METRIC)
113
+ check_time stats.total_call_time, elapsed
114
+ assert stats.call_count == 1
115
+ end
116
+
117
+
118
+ def test_method_traced?
119
+ assert !self.class.method_traced?(:method_to_be_traced, METRIC)
120
+ self.class.add_method_tracer :method_to_be_traced, METRIC
121
+ assert self.class.method_traced?(:method_to_be_traced, METRIC)
122
+ end
123
+
124
+ def test_tt_only
125
+
126
+ assert_nil @scope_listener.scope["c2"]
127
+ self.class.add_method_tracer :method_c1, "c1", true
128
+
129
+ self.class.add_method_tracer :method_c2, "c2", :metric => false
130
+ self.class.add_method_tracer :method_c3, "c3", false
131
+
132
+ method_c1
133
+
134
+ assert_not_nil @stats_engine.lookup_stat("c1")
135
+ assert_nil @stats_engine.lookup_stat("c2")
136
+ assert_not_nil @stats_engine.lookup_stat("c3")
137
+
138
+ assert_not_nil @scope_listener.scope["c2"]
139
+ end
140
+
141
+ def test_nested_scope_tracer
142
+ Insider.add_method_tracer :catcher, "catcher", :push_scope => true
143
+ Insider.add_method_tracer :thrower, "thrower", :push_scope => true
144
+ sampler = NewRelic::Agent::Agent.instance.transaction_sampler
145
+ mock = Insider.new(@stats_engine)
146
+ mock.catcher(0)
147
+ mock.catcher(5)
148
+ stats = @stats_engine.get_stats("catcher")
149
+ assert_equal 2, stats.call_count
150
+ stats = @stats_engine.get_stats("thrower")
151
+ assert_equal 6, stats.call_count
152
+ sample = sampler.harvest_slowest_sample
153
+ assert_not_nil sample
154
+ end
155
+
156
+ def test_add_same_tracer_twice
157
+ @metric_name = METRIC
158
+ self.class.add_method_tracer :method_to_be_traced, METRIC
159
+ self.class.add_method_tracer :method_to_be_traced, METRIC
160
+
161
+ t1 = Time.now
162
+ method_to_be_traced 1,2,3,true,METRIC
163
+ elapsed = Time.now - t1
164
+
165
+ stats = @stats_engine.get_stats(METRIC)
166
+ check_time stats.total_call_time, elapsed
167
+ assert stats.call_count == 1
168
+ end
169
+
170
+ def test_add_tracer_with_dynamic_metric
171
+ metric_code = '#{args[0]}.#{args[1]}'
172
+ @metric_name = metric_code
173
+ expected_metric = "1.2"
174
+ self.class.add_method_tracer :method_to_be_traced, metric_code
175
+
176
+ t1 = Time.now
177
+ method_to_be_traced 1,2,3,true,expected_metric
178
+ elapsed = Time.now - t1
179
+
180
+ stats = @stats_engine.get_stats(expected_metric)
181
+ check_time stats.total_call_time, elapsed
182
+ assert stats.call_count == 1
183
+ end
184
+
185
+ def test_trace_method_with_block
186
+ self.class.add_method_tracer :method_with_block, METRIC
187
+
188
+ t1 = Time.now
189
+ method_with_block(1,2,3,true,METRIC) do |scope|
190
+ assert scope == METRIC
191
+ end
192
+ elapsed = Time.now - t1
193
+
194
+ stats = @stats_engine.get_stats(METRIC)
195
+ check_time stats.total_call_time, elapsed
196
+ assert stats.call_count == 1
197
+ end
198
+
199
+ def test_trace_module_method
200
+ NewRelic::Agent.add_method_tracer :module_method_to_be_traced, '#{args[0]}'
201
+ NewRelic::Agent.module_method_to_be_traced "x", self
202
+ NewRelic::Agent.remove_method_tracer :module_method_to_be_traced, '#{args[0]}'
203
+ end
204
+
205
+ def test_remove
206
+ self.class.add_method_tracer :method_to_be_traced, METRIC
207
+ self.class.remove_method_tracer :method_to_be_traced, METRIC
208
+
209
+ t1 = Time.now
210
+ method_to_be_traced 1,2,3,false,METRIC
211
+ elapsed = Time.now - t1
212
+
213
+ stats = @stats_engine.get_stats(METRIC)
214
+ assert stats.call_count == 0
215
+ end
216
+
217
+ def self.static_method(x, testcase, is_traced)
218
+ testcase.assert x == "x"
219
+ testcase.assert((testcase.stats_engine.peek_scope.name == "x") == is_traced)
220
+ end
221
+
222
+ def trace_trace_static_method
223
+ self.add_method_tracer :static_method, '#{args[0]}'
224
+ self.class.static_method "x", self, true
225
+ self.remove_method_tracer :static_method, '#{args[0]}'
226
+ self.class.static_method "x", self, false
227
+ end
228
+
229
+ def test_exception
230
+ begin
231
+ metric = "hey there"
232
+ self.class.trace_method_execution_with_scope metric, true, true do
233
+ assert @stats_engine.peek_scope.name == metric
234
+ throw Exception.new
235
+ end
236
+
237
+ assert false # should never get here
238
+ rescue Exception
239
+ # make sure the scope gets popped
240
+ assert @stats_engine.peek_scope == nil
241
+ end
242
+
243
+ stats = @stats_engine.get_stats metric
244
+ assert stats.call_count == 1
245
+ end
246
+
247
+ def test_add_multiple_tracers
248
+ self.class.add_method_tracer :method_to_be_traced, 'X', :push_scope => false
249
+ method_to_be_traced 1,2,3,true,nil
250
+ self.class.add_method_tracer :method_to_be_traced, 'Y'
251
+ method_to_be_traced 1,2,3,true,'Y'
252
+ self.class.remove_method_tracer :method_to_be_traced, 'Y'
253
+ method_to_be_traced 1,2,3,true,nil
254
+ self.class.remove_method_tracer :method_to_be_traced, 'X'
255
+ method_to_be_traced 1,2,3,false,'X'
256
+ end
257
+
258
+ def trace_no_push_scope
259
+ self.class.add_method_tracer :method_to_be_traced, 'X', :push_scope => false
260
+ method_to_be_traced 1,2,3,true,nil
261
+ self.class.remove_method_tracer :method_to_be_traced, 'X'
262
+ method_to_be_traced 1,2,3,false,'X'
263
+ end
264
+
265
+ def check_time (t1, t2)
266
+ assert((t2-t1).abs < 0.01)
267
+ end
268
+
269
+ # =======================================================
270
+ # test methods to be traced
271
+ def method_to_be_traced(x, y, z, is_traced, expected_metric)
272
+ sleep 0.1
273
+ assert x == 1
274
+ assert y == 2
275
+ assert z == 3
276
+ scope_name = @stats_engine.peek_scope ? @stats_engine.peek_scope.name : nil
277
+ if is_traced
278
+ assert_equal expected_metric, scope_name
279
+ else
280
+ assert_not_equal expected_metric, scope_name
281
+ end
282
+ end
283
+
284
+ def method_with_block(x, y, z, is_traced, expected_metric, &block)
285
+ sleep 0.1
286
+ assert x == 1
287
+ assert y == 2
288
+ assert z == 3
289
+ block.call(@stats_engine.peek_scope.name)
290
+
291
+ scope_name = @stats_engine.peek_scope ? @stats_engine.peek_scope.name : nil
292
+ assert((expected_metric == scope_name) == is_traced)
293
+ end
294
+
295
+ def method_c1
296
+ method_c2
297
+ end
298
+
299
+ def method_c2
300
+ method_c3
301
+ end
302
+
303
+ def method_c3
304
+ end
305
+
306
+ end