ghazel-newrelic_rpm 3.1.0.1 → 3.4.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (175) hide show
  1. data/CHANGELOG +120 -35
  2. data/LICENSE +29 -2
  3. data/README.rdoc +2 -2
  4. data/bin/mongrel_rpm +0 -0
  5. data/bin/newrelic +0 -0
  6. data/bin/newrelic_cmd +0 -0
  7. data/lib/new_relic/agent.rb +50 -38
  8. data/lib/new_relic/agent/agent.rb +459 -337
  9. data/lib/new_relic/agent/beacon_configuration.rb +71 -11
  10. data/lib/new_relic/agent/browser_monitoring.rb +73 -14
  11. data/lib/new_relic/agent/busy_calculator.rb +11 -3
  12. data/lib/new_relic/agent/chained_call.rb +2 -2
  13. data/lib/new_relic/agent/database.rb +223 -0
  14. data/lib/new_relic/agent/error_collector.rb +231 -183
  15. data/lib/new_relic/agent/instrumentation.rb +2 -2
  16. data/lib/new_relic/agent/instrumentation/active_merchant.rb +10 -2
  17. data/lib/new_relic/agent/instrumentation/active_record.rb +138 -0
  18. data/lib/new_relic/agent/instrumentation/acts_as_solr.rb +7 -1
  19. data/lib/new_relic/agent/instrumentation/authlogic.rb +6 -0
  20. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +46 -14
  21. data/lib/new_relic/agent/instrumentation/data_mapper.rb +8 -2
  22. data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +11 -3
  23. data/lib/new_relic/agent/instrumentation/memcache.rb +49 -25
  24. data/lib/new_relic/agent/instrumentation/merb/controller.rb +7 -2
  25. data/lib/new_relic/agent/instrumentation/merb/errors.rb +7 -1
  26. data/lib/new_relic/agent/instrumentation/metric_frame.rb +31 -4
  27. data/lib/new_relic/agent/instrumentation/metric_frame/pop.rb +1 -5
  28. data/lib/new_relic/agent/instrumentation/net.rb +8 -2
  29. data/lib/new_relic/agent/instrumentation/passenger_instrumentation.rb +5 -2
  30. data/lib/new_relic/agent/instrumentation/queue_time.rb +1 -1
  31. data/lib/new_relic/agent/instrumentation/rails/action_controller.rb +66 -35
  32. data/lib/new_relic/agent/instrumentation/rails/action_web_service.rb +7 -1
  33. data/lib/new_relic/agent/instrumentation/rails/errors.rb +7 -1
  34. data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +121 -1
  35. data/lib/new_relic/agent/instrumentation/rails3/errors.rb +7 -1
  36. data/lib/new_relic/agent/instrumentation/rainbows_instrumentation.rb +21 -0
  37. data/lib/new_relic/agent/instrumentation/resque.rb +80 -0
  38. data/lib/new_relic/agent/instrumentation/sinatra.rb +46 -20
  39. data/lib/new_relic/agent/instrumentation/sunspot.rb +6 -0
  40. data/lib/new_relic/agent/instrumentation/unicorn_instrumentation.rb +7 -2
  41. data/lib/new_relic/agent/method_tracer.rb +205 -99
  42. data/lib/new_relic/agent/new_relic_service.rb +221 -0
  43. data/lib/new_relic/agent/pipe_channel_manager.rb +161 -0
  44. data/lib/new_relic/agent/pipe_service.rb +54 -0
  45. data/lib/new_relic/agent/samplers/delayed_job_sampler.rb +89 -0
  46. data/lib/new_relic/agent/samplers/memory_sampler.rb +6 -7
  47. data/lib/new_relic/agent/shim_agent.rb +5 -5
  48. data/lib/new_relic/agent/sql_sampler.rb +282 -0
  49. data/lib/new_relic/agent/stats_engine.rb +2 -0
  50. data/lib/new_relic/agent/stats_engine/gc_profiler.rb +123 -0
  51. data/lib/new_relic/agent/stats_engine/metric_stats.rb +35 -30
  52. data/lib/new_relic/agent/stats_engine/samplers.rb +10 -4
  53. data/lib/new_relic/agent/stats_engine/transactions.rb +28 -87
  54. data/lib/new_relic/agent/transaction_info.rb +74 -0
  55. data/lib/new_relic/agent/transaction_sample_builder.rb +18 -3
  56. data/lib/new_relic/agent/transaction_sampler.rb +108 -20
  57. data/lib/new_relic/agent/worker_loop.rb +14 -6
  58. data/lib/new_relic/collection_helper.rb +19 -11
  59. data/lib/new_relic/command.rb +1 -1
  60. data/lib/new_relic/commands/deployments.rb +2 -2
  61. data/lib/new_relic/commands/install.rb +2 -13
  62. data/lib/new_relic/control.rb +2 -3
  63. data/lib/new_relic/control/class_methods.rb +12 -6
  64. data/lib/new_relic/control/configuration.rb +57 -8
  65. data/lib/new_relic/control/frameworks.rb +10 -0
  66. data/lib/new_relic/control/frameworks/external.rb +4 -4
  67. data/lib/new_relic/control/frameworks/merb.rb +2 -1
  68. data/lib/new_relic/control/frameworks/rails.rb +35 -22
  69. data/lib/new_relic/control/frameworks/rails3.rb +12 -7
  70. data/lib/new_relic/control/frameworks/ruby.rb +5 -5
  71. data/lib/new_relic/control/frameworks/sinatra.rb +1 -4
  72. data/lib/new_relic/control/instance_methods.rb +38 -12
  73. data/lib/new_relic/control/instrumentation.rb +23 -4
  74. data/lib/new_relic/control/logging_methods.rb +70 -15
  75. data/lib/new_relic/control/server_methods.rb +22 -9
  76. data/lib/new_relic/delayed_job_injection.rb +16 -3
  77. data/lib/new_relic/helper.rb +21 -0
  78. data/lib/new_relic/language_support.rb +95 -0
  79. data/lib/new_relic/local_environment.rb +92 -48
  80. data/lib/new_relic/metric_data.rb +7 -2
  81. data/lib/new_relic/metric_spec.rb +12 -9
  82. data/lib/new_relic/noticed_error.rb +6 -1
  83. data/lib/new_relic/rack/browser_monitoring.rb +18 -19
  84. data/lib/new_relic/rack/developer_mode.rb +3 -2
  85. data/lib/new_relic/recipes.rb +8 -4
  86. data/lib/new_relic/stats.rb +17 -60
  87. data/lib/new_relic/transaction_analysis.rb +2 -1
  88. data/lib/new_relic/transaction_analysis/segment_summary.rb +4 -2
  89. data/lib/new_relic/transaction_sample.rb +60 -75
  90. data/lib/new_relic/transaction_sample/segment.rb +31 -79
  91. data/lib/new_relic/version.rb +2 -2
  92. data/lib/newrelic_rpm.rb +1 -1
  93. data/newrelic.yml +2 -2
  94. data/newrelic_rpm.gemspec +46 -54
  95. data/test/active_record_fixtures.rb +3 -3
  96. data/test/config/newrelic.yml +1 -1
  97. data/test/fixtures/proc_cpuinfo.txt +575 -0
  98. data/test/new_relic/agent/agent/connect_test.rb +128 -25
  99. data/test/new_relic/agent/agent/start_test.rb +9 -94
  100. data/test/new_relic/agent/agent/start_worker_thread_test.rb +2 -4
  101. data/test/new_relic/agent/agent_test.rb +51 -78
  102. data/test/new_relic/agent/agent_test_controller.rb +1 -1
  103. data/test/new_relic/agent/agent_test_controller_test.rb +49 -33
  104. data/test/new_relic/agent/beacon_configuration_test.rb +12 -5
  105. data/test/new_relic/agent/browser_monitoring_test.rb +99 -50
  106. data/test/new_relic/agent/database_test.rb +161 -0
  107. data/test/new_relic/agent/error_collector_test.rb +47 -23
  108. data/test/new_relic/agent/instrumentation/active_record_instrumentation_test.rb +96 -42
  109. data/test/new_relic/agent/instrumentation/controller_instrumentation_test.rb +0 -2
  110. data/test/new_relic/agent/instrumentation/instrumentation_test.rb +1 -1
  111. data/test/new_relic/agent/instrumentation/metric_frame/pop_test.rb +3 -11
  112. data/test/new_relic/agent/instrumentation/net_instrumentation_test.rb +9 -9
  113. data/test/new_relic/agent/instrumentation/queue_time_test.rb +6 -11
  114. data/test/new_relic/agent/memcache_instrumentation_test.rb +54 -18
  115. data/test/new_relic/agent/method_tracer/class_methods/add_method_tracer_test.rb +1 -1
  116. data/test/new_relic/agent/method_tracer/instance_methods/trace_execution_scoped_test.rb +1 -1
  117. data/test/new_relic/agent/method_tracer_test.rb +3 -2
  118. data/test/new_relic/agent/new_relic_service_test.rb +151 -0
  119. data/test/new_relic/agent/pipe_channel_manager_test.rb +114 -0
  120. data/test/new_relic/agent/pipe_service_test.rb +113 -0
  121. data/test/new_relic/agent/rpm_agent_test.rb +4 -31
  122. data/test/new_relic/agent/sql_sampler_test.rb +192 -0
  123. data/test/new_relic/agent/stats_engine/metric_stats_test.rb +19 -18
  124. data/test/new_relic/agent/stats_engine_test.rb +41 -6
  125. data/test/new_relic/agent/transaction_info_test.rb +13 -0
  126. data/test/new_relic/agent/transaction_sample_builder_test.rb +27 -4
  127. data/test/new_relic/agent/transaction_sampler_test.rb +68 -46
  128. data/test/new_relic/agent/worker_loop_test.rb +3 -3
  129. data/test/new_relic/agent_test.rb +242 -0
  130. data/test/new_relic/collection_helper_test.rb +50 -28
  131. data/test/new_relic/control/configuration_test.rb +77 -0
  132. data/test/new_relic/control/logging_methods_test.rb +49 -21
  133. data/test/new_relic/control_test.rb +115 -54
  134. data/test/new_relic/delayed_job_injection_test.rb +21 -0
  135. data/test/new_relic/fake_collector.rb +210 -0
  136. data/test/new_relic/fake_service.rb +44 -0
  137. data/test/new_relic/local_environment_test.rb +14 -1
  138. data/test/new_relic/metric_parser/metric_parser_test.rb +11 -0
  139. data/test/new_relic/rack/browser_monitoring_test.rb +84 -23
  140. data/test/new_relic/rack/developer_mode_helper_test.rb +141 -0
  141. data/test/new_relic/rack/developer_mode_test.rb +31 -0
  142. data/test/new_relic/stats_test.rb +3 -18
  143. data/test/new_relic/transaction_analysis/segment_summary_test.rb +14 -0
  144. data/test/new_relic/transaction_analysis_test.rb +3 -3
  145. data/test/new_relic/transaction_sample/segment_test.rb +15 -80
  146. data/test/new_relic/transaction_sample_test.rb +25 -18
  147. data/test/script/build_test_gem.sh +51 -0
  148. data/test/script/ci.sh +140 -0
  149. data/test/script/ci_agent-tests_runner.sh +82 -0
  150. data/test/script/ci_bench.sh +52 -0
  151. data/test/script/ci_multiverse_runner.sh +63 -0
  152. data/test/test_contexts.rb +1 -0
  153. data/test/test_helper.rb +18 -5
  154. data/ui/helpers/developer_mode_helper.rb +14 -8
  155. data/ui/helpers/google_pie_chart.rb +0 -1
  156. data/ui/views/newrelic/index.rhtml +2 -2
  157. data/vendor/gems/dependency_detection-0.0.1.build/LICENSE +4 -18
  158. data/vendor/gems/dependency_detection-0.0.1.build/lib/dependency_detection.rb +10 -0
  159. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/mem_cache.rb +11 -11
  160. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/metric_parser.rb +17 -4
  161. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/view.rb +4 -0
  162. metadata +50 -36
  163. data/lib/new_relic/agent/instrumentation/rails/active_record_instrumentation.rb +0 -108
  164. data/lib/new_relic/agent/instrumentation/rails3/active_record_instrumentation.rb +0 -112
  165. data/lib/new_relic/agent/samplers/delayed_job_lock_sampler.rb +0 -40
  166. data/lib/new_relic/data_serialization.rb +0 -84
  167. data/lib/new_relic/histogram.rb +0 -91
  168. data/lib/new_relic/rack/metric_app.rb +0 -65
  169. data/lib/new_relic/rack/mongrel_rpm.ru +0 -28
  170. data/lib/new_relic/rack/newrelic.yml +0 -27
  171. data/lib/new_relic/rack_app.rb +0 -6
  172. data/test/new_relic/data_serialization_test.rb +0 -70
  173. data/vendor/gems/dependency_detection-0.0.1.build/README +0 -0
  174. data/vendor/gems/metric_parser-0.1.0.pre1/LICENSE +0 -0
  175. data/vendor/gems/metric_parser-0.1.0.pre1/README +0 -0
@@ -0,0 +1,161 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..',
2
+ 'test_helper'))
3
+ require 'new_relic/agent/database'
4
+ class NewRelic::Agent::DatabaseTest < Test::Unit::TestCase
5
+ def teardown
6
+ NewRelic::Agent::Database::Obfuscator.instance.reset
7
+ end
8
+
9
+ def test_process_resultset
10
+ resultset = [["column"]]
11
+ assert_equal([nil, [["column"]]],
12
+ NewRelic::Agent::Database.process_resultset(resultset))
13
+ end
14
+
15
+ def test_explain_sql_select_with_mysql_connection
16
+ config = {:adapter => 'mysql'}
17
+ config.default('val')
18
+ sql = 'SELECT foo'
19
+ connection = mock('connection')
20
+ plan = {
21
+ "select_type"=>"SIMPLE", "key_len"=>nil, "table"=>"blogs", "id"=>"1",
22
+ "possible_keys"=>nil, "type"=>"ALL", "Extra"=>"", "rows"=>"2",
23
+ "ref"=>nil, "key"=>nil
24
+ }
25
+ result = mock('explain plan')
26
+ result.expects(:each_hash).yields(plan)
27
+ # two rows, two columns
28
+ connection.expects(:execute).with('EXPLAIN SELECT foo').returns(result)
29
+ NewRelic::Agent::Database.expects(:get_connection).with(config).returns(connection)
30
+
31
+ result = NewRelic::Agent::Database.explain_sql(sql, config)
32
+ assert_equal(plan.keys.sort, result[0].sort)
33
+ assert_equal(plan.values.compact.sort, result[1][0].compact.sort)
34
+ end
35
+
36
+ def test_explain_sql_one_select_with_pg_connection
37
+ config = {:adapter => 'postgresql'}
38
+ config.default('val')
39
+ sql = 'select count(id) from blogs limit 1'
40
+ connection = mock('connection')
41
+ plan = [{"QUERY PLAN"=>"Limit (cost=11.75..11.76 rows=1 width=4)"},
42
+ {"QUERY PLAN"=>" -> Aggregate (cost=11.75..11.76 rows=1 width=4)"},
43
+ {"QUERY PLAN"=>" -> Seq Scan on blogs (cost=0.00..11.40 rows=140 width=4)"}]
44
+ connection.expects(:execute).returns(plan)
45
+ NewRelic::Agent::Database.expects(:get_connection).with(config).returns(connection)
46
+ assert_equal([['QUERY PLAN'],
47
+ [["Limit (cost=11.75..11.76 rows=1 width=4)"],
48
+ [" -> Aggregate (cost=11.75..11.76 rows=1 width=4)"],
49
+ [" -> Seq Scan on blogs (cost=0.00..11.40 rows=140 width=4)"]]],
50
+ NewRelic::Agent::Database.explain_sql(sql, config))
51
+ end
52
+
53
+ def test_explain_sql_no_sql
54
+ assert_equal(nil, NewRelic::Agent::Database.explain_sql(nil, nil))
55
+ end
56
+
57
+ def test_explain_sql_no_connection_config
58
+ assert_equal(nil, NewRelic::Agent::Database.explain_sql('select foo', nil))
59
+ end
60
+
61
+ def test_explain_sql_non_select
62
+ assert_equal([], NewRelic::Agent::Database.explain_sql('foo',
63
+ mock('config')))
64
+ end
65
+
66
+ def test_explain_sql_one_select_no_connection
67
+ # NB this test raises an error in the log, much as it might if a
68
+ # user supplied a config that was not valid. This is generally
69
+ # expected behavior - the get_connection method shouldn't allow
70
+ # errors to percolate up.
71
+ config = mock('config')
72
+ config.stubs(:[]).returns(nil)
73
+ assert_equal([], NewRelic::Agent::Database.explain_sql('SELECT', config))
74
+ end
75
+
76
+ def test_handle_exception_in_explain
77
+ fake_error = StandardError.new('a message')
78
+ NewRelic::Control.instance.log.expects(:error).with('Error getting query plan: a message')
79
+ # backtrace can be basically any string, just should get logged
80
+ NewRelic::Control.instance.log.expects(:debug).with(instance_of(String))
81
+
82
+ NewRelic::Agent::Database.handle_exception_in_explain do
83
+ raise(fake_error)
84
+ end
85
+ end
86
+
87
+ def test_obfuscation_mysql_basic
88
+ insert = %q[INSERT INTO `X` values("test",0, 1 , 2, 'test')]
89
+ assert_equal("INSERT INTO `X` values(?,?, ? , ?, ?)",
90
+ NewRelic::Agent::Database.obfuscate_sql(insert))
91
+ select = %q[SELECT `table`.`column` FROM `table` WHERE `table`.`column` = 'value' AND `table`.`other_column` = "other value" LIMIT 1]
92
+ assert_equal(%q[SELECT `table`.`column` FROM `table` WHERE `table`.`column` = ? AND `table`.`other_column` = ? LIMIT ?],
93
+ NewRelic::Agent::Database.obfuscate_sql(select))
94
+ end
95
+
96
+ def test_obfuscation_postgresql_basic
97
+ insert = NewRelic::Agent::Database::Statement.new(%q[INSERT INTO "X" values('test',0, 1 , 2, 'test')])
98
+ insert.adapter = :postgresql
99
+ assert_equal('INSERT INTO "X" values(?,?, ? , ?, ?)',
100
+ NewRelic::Agent::Database.obfuscate_sql(insert))
101
+ select = NewRelic::Agent::Database::Statement.new(%q[SELECT "table"."column" FROM "table" WHERE "table"."column" = 'value' AND "table"."other_column" = 'other value' LIMIT 1])
102
+ select.adapter = :postgresql
103
+ assert_equal(%q[SELECT "table"."column" FROM "table" WHERE "table"."column" = ? AND "table"."other_column" = ? LIMIT ?],
104
+ NewRelic::Agent::Database.obfuscate_sql(select))
105
+ end
106
+
107
+ def test_obfuscation_escaped_literals
108
+ insert = %q[INSERT INTO X values('', 'jim''s ssn',0, 1 , 'jim''s son''s son', """jim''s"" hat", "\"jim''s secret\"")]
109
+ assert_equal("INSERT INTO X values(?, ?,?, ? , ?, ?, ?)",
110
+ NewRelic::Agent::Database.obfuscate_sql(insert))
111
+ end
112
+
113
+ def test_obfuscation_mysql_integers_in_identifiers
114
+ select = %q[SELECT * FROM `table_007` LIMIT 1]
115
+ assert_equal(%q[SELECT * FROM `table_007` LIMIT ?],
116
+ NewRelic::Agent::Database.obfuscate_sql(select))
117
+ end
118
+
119
+ def test_obfuscation_postgresql_integers_in_identifiers
120
+ select = NewRelic::Agent::Database::Statement.new(%q[SELECT * FROM "table_007" LIMIT 1])
121
+ select.adapter = :postgresql
122
+ assert_equal(%q[SELECT * FROM "table_007" LIMIT ?],
123
+ NewRelic::Agent::Database.obfuscate_sql(select))
124
+ end
125
+
126
+ def test_sql_obfuscation_filters
127
+ NewRelic::Agent::Database.set_sql_obfuscator(:replace) do |string|
128
+ "1" + string
129
+ end
130
+
131
+ sql = "SELECT * FROM TABLE 123 'jim'"
132
+
133
+ assert_equal "1" + sql, NewRelic::Agent::Database.obfuscate_sql(sql)
134
+
135
+ NewRelic::Agent::Database.set_sql_obfuscator(:before) do |string|
136
+ "2" + string
137
+ end
138
+
139
+ assert_equal "12" + sql, NewRelic::Agent::Database.obfuscate_sql(sql)
140
+
141
+ NewRelic::Agent::Database.set_sql_obfuscator(:after) do |string|
142
+ string + "3"
143
+ end
144
+
145
+ assert_equal "12" + sql + "3", NewRelic::Agent::Database.obfuscate_sql(sql)
146
+
147
+ NewRelic::Agent::Database::Obfuscator.instance.reset
148
+ end
149
+
150
+ def test_close_connections_closes_all_held_db_connections
151
+ foo_connection = mock('foo connection')
152
+ bar_connection = mock('bar connection')
153
+ NewRelic::Agent::Database::ConnectionManager.instance.instance_eval do
154
+ @connections = { :foo => foo_connection, :bar => bar_connection }
155
+ end
156
+ foo_connection.expects(:disconnect!)
157
+ bar_connection.expects(:disconnect!)
158
+
159
+ NewRelic::Agent::Database.close_connections
160
+ end
161
+ end
@@ -3,12 +3,12 @@ ENV['SKIP_RAILS'] = 'true'
3
3
  require File.expand_path(File.join(File.dirname(__FILE__),'..','..','test_helper'))
4
4
 
5
5
  class NewRelic::Agent::ErrorCollectorTest < Test::Unit::TestCase
6
-
7
6
  def setup
8
7
  super
9
8
  @error_collector = NewRelic::Agent::ErrorCollector.new
10
9
  @error_collector.stubs(:enabled).returns(true)
11
10
  end
11
+
12
12
  def test_empty
13
13
  @error_collector.harvest_errors([])
14
14
  @error_collector.notice_error(nil, :metric=> 'path', :request_params => {:x => 'y'})
@@ -26,10 +26,10 @@ class NewRelic::Agent::ErrorCollectorTest < Test::Unit::TestCase
26
26
  assert_equal '', err.params[:request_referer]
27
27
  assert_equal 'path', err.path
28
28
  assert_equal 'Error', err.exception_class
29
-
30
29
  end
30
+
31
31
  def test_simple
32
- @error_collector.notice_error(Exception.new("message"), :uri => '/myurl/', :metric => 'path', :referer => 'test_referer', :request_params => {:x => 'y'})
32
+ @error_collector.notice_error(StandardError.new("message"), :uri => '/myurl/', :metric => 'path', :referer => 'test_referer', :request_params => {:x => 'y'})
33
33
 
34
34
  old_errors = []
35
35
  errors = @error_collector.harvest_errors(old_errors)
@@ -42,7 +42,7 @@ class NewRelic::Agent::ErrorCollectorTest < Test::Unit::TestCase
42
42
  assert err.params[:request_uri] == '/myurl/'
43
43
  assert err.params[:request_referer] == "test_referer"
44
44
  assert err.path == 'path'
45
- assert err.exception_class == 'Exception'
45
+ assert err.exception_class == 'StandardError'
46
46
 
47
47
  # the collector should now return an empty array since nothing
48
48
  # has been added since its last harvest
@@ -53,7 +53,7 @@ class NewRelic::Agent::ErrorCollectorTest < Test::Unit::TestCase
53
53
  def test_long_message
54
54
  #yes, times 500. it's a 5000 byte string. Assuming strings are
55
55
  #still 1 byte / char.
56
- @error_collector.notice_error(Exception.new("1234567890" * 500), :uri => '/myurl/', :metric => 'path', :request_params => {:x => 'y'})
56
+ @error_collector.notice_error(StandardError.new("1234567890" * 500), :uri => '/myurl/', :metric => 'path', :request_params => {:x => 'y'})
57
57
 
58
58
  old_errors = []
59
59
  errors = @error_collector.harvest_errors(old_errors)
@@ -66,13 +66,13 @@ class NewRelic::Agent::ErrorCollectorTest < Test::Unit::TestCase
66
66
  end
67
67
 
68
68
  def test_collect_failover
69
- @error_collector.notice_error(Exception.new("message"), :metric => 'first', :request_params => {:x => 'y'})
69
+ @error_collector.notice_error(StandardError.new("message"), :metric => 'first', :request_params => {:x => 'y'})
70
70
 
71
71
  errors = @error_collector.harvest_errors([])
72
72
 
73
- @error_collector.notice_error(Exception.new("message"), :metric => 'second', :request_params => {:x => 'y'})
74
- @error_collector.notice_error(Exception.new("message"), :metric => 'path', :request_params => {:x => 'y'})
75
- @error_collector.notice_error(Exception.new("message"), :metric => 'last', :request_params => {:x => 'y'})
73
+ @error_collector.notice_error(StandardError.new("message"), :metric => 'second', :request_params => {:x => 'y'})
74
+ @error_collector.notice_error(StandardError.new("message"), :metric => 'path', :request_params => {:x => 'y'})
75
+ @error_collector.notice_error(StandardError.new("message"), :metric => 'last', :request_params => {:x => 'y'})
76
76
 
77
77
  errors = @error_collector.harvest_errors(errors)
78
78
 
@@ -80,8 +80,8 @@ class NewRelic::Agent::ErrorCollectorTest < Test::Unit::TestCase
80
80
  assert_equal 'first', errors.first.path
81
81
  assert_equal 'last', errors.last.path
82
82
 
83
- @error_collector.notice_error(Exception.new("message"), :metric => 'first', :request_params => {:x => 'y'})
84
- @error_collector.notice_error(Exception.new("message"), :metric => 'last', :request_params => {:x => 'y'})
83
+ @error_collector.notice_error(StandardError.new("message"), :metric => 'first', :request_params => {:x => 'y'})
84
+ @error_collector.notice_error(StandardError.new("message"), :metric => 'last', :request_params => {:x => 'y'})
85
85
 
86
86
  errors = @error_collector.harvest_errors(nil)
87
87
  assert_equal 2, errors.length
@@ -95,7 +95,7 @@ class NewRelic::Agent::ErrorCollectorTest < Test::Unit::TestCase
95
95
 
96
96
  silence_stream(::STDOUT) do
97
97
  (max_q_length + 5).times do |n|
98
- @error_collector.notice_error(Exception.new("exception #{n}"), :metric => "path", :request_params => {:x => n})
98
+ @error_collector.notice_error(StandardError.new("exception #{n}"), :metric => "path", :request_params => {:x => n})
99
99
  end
100
100
  end
101
101
 
@@ -120,13 +120,13 @@ class NewRelic::Agent::ErrorCollectorTest < Test::Unit::TestCase
120
120
  [1.1, '1.1'],
121
121
  ['hi', 'hi'],
122
122
  [:hi, :hi],
123
- [Exception.new("test"), "#<Exception>"],
123
+ [StandardError.new("test"), "#<StandardError>"],
124
124
  [TestClass.new, "#<NewRelic::Agent::ErrorCollectorTest::TestClass>"]
125
125
  ]
126
126
 
127
127
 
128
128
  types.each do |test|
129
- @error_collector.notice_error(Exception.new("message"), :metric => 'path', :request_params => {:x => test[0]})
129
+ @error_collector.notice_error(StandardError.new("message"), :metric => 'path', :request_params => {:x => test[0]})
130
130
 
131
131
  assert_equal test[1], @error_collector.harvest_errors([])[0].params[:request_params][:x]
132
132
  end
@@ -144,22 +144,46 @@ class NewRelic::Agent::ErrorCollectorTest < Test::Unit::TestCase
144
144
  end
145
145
 
146
146
  def test_exclude_block
147
- @error_collector.ignore_error_filter do |e|
148
- if e.is_a? IOError
149
- nil
150
- else
151
- e
152
- end
153
- end
154
-
147
+ NewRelic::Agent.logger.expects(:error).never
148
+ @error_collector.ignore_error_filter &wrapped_filter_proc
149
+
155
150
  @error_collector.notice_error(IOError.new("message"), :metric => 'path', :request_params => {:x => 'y'})
151
+ @error_collector.notice_error(StandardError.new("message"), :metric => 'path', :request_params => {:x => 'y'})
152
+
153
+ errors = @error_collector.harvest_errors([])
154
+
155
+ assert_equal 1, errors.length
156
+ end
157
+
158
+ def test_obfuscates_error_messages_when_high_security_is_set
159
+ NewRelic::Control.instance['high_security'] = true
160
+
161
+ @error_collector.notice_error(StandardError.new("YO SQL BAD: serect * flom test where foo = 'bar'"))
162
+ @error_collector.notice_error(StandardError.new("YO SQL BAD: serect * flom test where foo in (1,2,3,4,5)"))
156
163
 
164
+ old_errors = []
157
165
  errors = @error_collector.harvest_errors([])
158
166
 
159
- assert_equal 0, errors.length
167
+ assert_equal('YO SQL BAD: serect * flom test where foo = ?',
168
+ errors[0].message)
169
+ assert_equal('YO SQL BAD: serect * flom test where foo in (?,?,?,?,?)',
170
+ errors[1].message)
171
+
172
+ NewRelic::Control.instance['high_security'] = nil
160
173
  end
161
174
 
162
175
  private
176
+
177
+ def wrapped_filter_proc
178
+ Proc.new do |e|
179
+ if e.is_a? IOError
180
+ return nil
181
+ else
182
+ return e
183
+ end
184
+ end
185
+ end
186
+
163
187
  def silence_stream(*args)
164
188
  super
165
189
  rescue NoMethodError
@@ -1,19 +1,16 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__),'..','..','..','test_helper'))
2
+
2
3
  class NewRelic::Agent::Instrumentation::ActiveRecordInstrumentationTest < Test::Unit::TestCase
3
4
  require 'active_record_fixtures'
4
5
  include NewRelic::Agent::Instrumentation::ControllerInstrumentation
5
6
 
6
- @@setup = false
7
7
  def setup
8
8
  super
9
- unless @@setup
10
- NewRelic::Agent.manual_start
11
- @setup = true
12
- end
9
+ NewRelic::Agent.manual_start
13
10
  ActiveRecordFixtures.setup
14
11
  NewRelic::Agent.instance.transaction_sampler.reset!
15
12
  NewRelic::Agent.instance.stats_engine.clear_stats
16
- rescue Exception => e
13
+ rescue => e
17
14
  puts e
18
15
  puts e.backtrace.join("\n")
19
16
  end
@@ -35,7 +32,6 @@ class NewRelic::Agent::Instrumentation::ActiveRecordInstrumentationTest < Test::
35
32
 
36
33
  def test_finder
37
34
  ActiveRecordFixtures::Order.create :id => 0, :name => 'jeff'
38
-
39
35
  find_metric = "ActiveRecord/ActiveRecordFixtures::Order/find"
40
36
 
41
37
  assert_calls_metrics(find_metric) do
@@ -44,13 +40,20 @@ class NewRelic::Agent::Instrumentation::ActiveRecordInstrumentationTest < Test::
44
40
  ActiveRecordFixtures::Order.find_all_by_name "jeff"
45
41
  check_metric_count(find_metric, 2)
46
42
  end
43
+ end
47
44
 
48
- return if NewRelic::Control.instance.rails_version < "2.3.4"
45
+ def test_exists
46
+ return if NewRelic::Control.instance.rails_version < "2.3.4" ||
47
+ NewRelic::Control.instance.rails_version >= "3.0.7"
48
+
49
+ ActiveRecordFixtures::Order.create :id => 0, :name => 'jeff'
50
+
51
+ find_metric = "ActiveRecord/ActiveRecordFixtures::Order/find"
49
52
 
50
53
  assert_calls_metrics(find_metric) do
51
54
  ActiveRecordFixtures::Order.exists?(["name=?", 'jeff'])
55
+ check_metric_count(find_metric, 1)
52
56
  end
53
- check_metric_count(find_metric, 3)
54
57
  end
55
58
 
56
59
  # multiple duplicate find calls should only cause metric trigger on the first
@@ -83,7 +86,9 @@ class NewRelic::Agent::Instrumentation::ActiveRecordInstrumentationTest < Test::
83
86
  ActiveRecord/all
84
87
  ActiveRecord/find
85
88
  ActiveRecord/ActiveRecordFixtures::Order/find
86
- Database/SQL/insert]
89
+ Database/SQL/insert
90
+ RemoteService/sql/mysql/localhost
91
+ ]
87
92
 
88
93
  if NewRelic::Control.instance.rails_version < '2.1.0'
89
94
  expected += %W[ActiveRecord/save ActiveRecord/ActiveRecordFixtures::Order/save]
@@ -132,36 +137,43 @@ class NewRelic::Agent::Instrumentation::ActiveRecordInstrumentationTest < Test::
132
137
  check_metric_count("ActiveRecord/ActiveRecordFixtures::Order/create", 1)
133
138
  end
134
139
 
135
-
136
140
  def test_metric_names_standard
137
141
  # fails due to a bug in rails 3 - log does not provide the correct
138
142
  # transaction type - it returns 'SQL' instead of 'Foo Create', for example.
139
- return if rails3? || defined?(JRuby) || isSqlite?
140
-
143
+ return if defined?(JRuby) || isSqlite?
144
+
141
145
  expected = %W[
142
146
  ActiveRecord/all
143
147
  ActiveRecord/find
144
- ActiveRecord/ActiveRecordFixtures::Order/find
145
148
  ActiveRecord/create
149
+ ActiveRecord/ActiveRecordFixtures::Order/find
150
+ ActiveRecord/ActiveRecordFixtures::Order/create
146
151
  Database/SQL/other
147
- ActiveRecord/ActiveRecordFixtures::Order/create]
152
+ RemoteService/sql/mysql/localhost]
148
153
 
149
154
  if NewRelic::Control.instance.rails_version < '2.1.0'
150
- expected += %W[ActiveRecord/save ActiveRecord/ActiveRecordFixtures::Order/save]
155
+ expected += ['ActiveRecord/save',
156
+ 'ActiveRecord/ActiveRecordFixtures::Order/save']
157
+ elsif NewRelic::Control.instance.rails_version >= '3.0.0'
158
+ expected << 'Database/SQL/insert'
151
159
  end
152
160
 
153
161
  assert_calls_metrics(*expected) do
154
- m = ActiveRecordFixtures::Order.create :id => 0, :name => 'jeff'
162
+ m = ActiveRecordFixtures::Order.create :id => 0, :name => 'donkey'
155
163
  m = ActiveRecordFixtures::Order.find(m.id)
156
164
  m.id = 999
157
165
  m.save!
158
166
  end
159
167
 
160
168
  metrics = NewRelic::Agent.instance.stats_engine.metrics
161
-
169
+
162
170
  compare_metrics expected, metrics
163
171
  check_metric_count("ActiveRecord/ActiveRecordFixtures::Order/find", 1)
164
- check_metric_count("ActiveRecord/ActiveRecordFixtures::Order/create", 1)
172
+ if NewRelic::Control.instance.rails_version < '3.0.0'
173
+ check_metric_count("ActiveRecord/ActiveRecordFixtures::Order/create", 1)
174
+ else
175
+ check_metric_count("Database/SQL/insert", 1)
176
+ end
165
177
  end
166
178
 
167
179
  def test_join_metrics_jruby
@@ -174,9 +186,11 @@ class NewRelic::Agent::Instrumentation::ActiveRecordInstrumentationTest < Test::
174
186
  ActiveRecord/ActiveRecordFixtures::Order/destroy
175
187
  Database/SQL/insert
176
188
  Database/SQL/delete
189
+ Database/SQL/show
177
190
  ActiveRecord/find
178
191
  ActiveRecord/ActiveRecordFixtures::Order/find
179
192
  ActiveRecord/ActiveRecordFixtures::Shipment/find
193
+ RemoteService/sql/mysql/localhost
180
194
  ]
181
195
 
182
196
  assert_calls_metrics(*expected_metrics) do
@@ -242,6 +256,7 @@ class NewRelic::Agent::Instrumentation::ActiveRecordInstrumentationTest < Test::
242
256
 
243
257
  expected_metrics = %W[
244
258
  ActiveRecord/all
259
+ RemoteService/sql/mysql/localhost
245
260
  ActiveRecord/destroy
246
261
  ActiveRecord/ActiveRecordFixtures::Order/destroy
247
262
  Database/SQL/insert
@@ -284,6 +299,7 @@ class NewRelic::Agent::Instrumentation::ActiveRecordInstrumentationTest < Test::
284
299
  expected_metrics = %W[
285
300
  ActiveRecord/all
286
301
  Database/SQL/select
302
+ RemoteService/sql/mysql/localhost
287
303
  ]
288
304
 
289
305
  assert_calls_unscoped_metrics(*expected_metrics) do
@@ -301,6 +317,7 @@ class NewRelic::Agent::Instrumentation::ActiveRecordInstrumentationTest < Test::
301
317
  expected_metrics = %W[
302
318
  ActiveRecord/all
303
319
  Database/SQL/other
320
+ RemoteService/sql/mysql/localhost
304
321
  ]
305
322
  assert_calls_unscoped_metrics(*expected_metrics) do
306
323
  ActiveRecordFixtures::Order.connection.execute "begin"
@@ -314,8 +331,9 @@ class NewRelic::Agent::Instrumentation::ActiveRecordInstrumentationTest < Test::
314
331
 
315
332
  def test_show_sql
316
333
  return if isSqlite?
334
+ return if isPostgres?
317
335
 
318
- expected_metrics = %W[ActiveRecord/all Database/SQL/show]
336
+ expected_metrics = %W[ActiveRecord/all Database/SQL/show RemoteService/sql/mysql/localhost]
319
337
 
320
338
  assert_calls_metrics(*expected_metrics) do
321
339
  ActiveRecordFixtures::Order.connection.execute "show tables"
@@ -336,6 +354,7 @@ class NewRelic::Agent::Instrumentation::ActiveRecordInstrumentationTest < Test::
336
354
  metrics = NewRelic::Agent.instance.stats_engine.metrics
337
355
  compare_metrics [], metrics
338
356
  end
357
+
339
358
  def test_run_explains
340
359
  perform_action_with_newrelic_trace :name => 'bogosity' do
341
360
  ActiveRecordFixtures::Order.add_delay
@@ -343,10 +362,12 @@ class NewRelic::Agent::Instrumentation::ActiveRecordInstrumentationTest < Test::
343
362
  end
344
363
 
345
364
  # that's a mouthful. perhaps we should ponder our API.
346
- segment = NewRelic::Agent.instance.transaction_sampler.last_sample.root_segment.called_segments.first.called_segments.first.called_segments.first
365
+ segment = NewRelic::Agent.instance.transaction_sampler.last_sample \
366
+ .root_segment.called_segments[0].called_segments[0].called_segments[0]
347
367
  regex = /^SELECT (["`]?#{ActiveRecordFixtures::Order.table_name}["`]?.)?\* FROM ["`]?#{ActiveRecordFixtures::Order.table_name}["`]?$/
348
368
  assert_match regex, segment.params[:sql].strip
349
369
  end
370
+
350
371
  def test_prepare_to_send
351
372
  perform_action_with_newrelic_trace :name => 'bogosity' do
352
373
  ActiveRecordFixtures::Order.add_delay
@@ -367,11 +388,11 @@ class NewRelic::Agent::Instrumentation::ActiveRecordInstrumentationTest < Test::
367
388
  sample = sample.prepare_to_send(:record_sql => :raw, :explain_sql => 0.0)
368
389
  sql_segment = sample.root_segment.called_segments.first.called_segments.first.called_segments.first
369
390
  assert_match /^SELECT /, sql_segment.params[:sql]
370
- explanations = sql_segment.params[:explanation]
391
+ explanations = sql_segment.params[:explain_plan]
371
392
  if isMysql? || isPostgres?
372
393
  assert_not_nil explanations, "No explains in segment: #{sql_segment}"
373
- assert_equal 1, explanations.size,"No explains in segment: #{sql_segment}"
374
- assert_equal 1, explanations.first.size
394
+ assert_equal(2, explanations.size,
395
+ "No explains in segment: #{sql_segment}")
375
396
  end
376
397
  end
377
398
 
@@ -388,14 +409,17 @@ class NewRelic::Agent::Instrumentation::ActiveRecordInstrumentationTest < Test::
388
409
 
389
410
  sample = sample.prepare_to_send(:record_sql => :obfuscated, :explain_sql => 0.0)
390
411
  segment = sample.root_segment.called_segments.first.called_segments.first.called_segments.first
391
- explanations = segment.params[:explanation]
392
- assert_not_nil explanations, "No explains in segment: #{segment}"
393
- assert_equal 1, explanations.size,"No explains in segment: #{segment}"
394
- assert_equal 1, explanations.first.size, "should be one row of explanation"
412
+ explanation = segment.params[:explain_plan]
413
+ assert_not_nil explanation, "No explains in segment: #{segment}"
414
+ assert_equal 2, explanation.size,"No explains in segment: #{segment}"
395
415
 
396
- row = explanations.first.first
397
- assert_equal 10, row.size
398
- assert_equal ['1', 'SIMPLE', ActiveRecordFixtures::Order.table_name], row[0..2]
416
+ assert_equal 10, explanation[0].size
417
+ ['id', 'select_type', 'table'].each do |c|
418
+ assert explanation[0].include?(c)
419
+ end
420
+ ['1', 'SIMPLE', ActiveRecordFixtures::Order.table_name].each do |c|
421
+ assert explanation[1][0].include?(c)
422
+ end
399
423
 
400
424
  s = NewRelic::Agent.get_stats("ActiveRecord/ActiveRecordFixtures::Order/find")
401
425
  assert_equal 1, s.call_count
@@ -415,16 +439,14 @@ class NewRelic::Agent::Instrumentation::ActiveRecordInstrumentationTest < Test::
415
439
 
416
440
  sample = sample.prepare_to_send(:record_sql => :obfuscated, :explain_sql => 0.0)
417
441
  segment = sample.root_segment.called_segments.first.called_segments.first.called_segments.first
418
- explanations = segment.params[:explanation]
442
+ explanations = segment.params[:explain_plan]
419
443
 
420
444
  assert_not_nil explanations, "No explains in segment: #{segment}"
421
445
  assert_equal 1, explanations.size,"No explains in segment: #{segment}"
422
446
  assert_equal 1, explanations.first.size
423
447
 
424
- assert_equal Array, explanations.class
425
- assert_equal Array, explanations[0].class
426
- assert_equal Array, explanations[0][0].class
427
- assert_match /Seq Scan on test_data/, explanations[0][0].join(";")
448
+ assert_equal("Explain Plan", explanations[0][0])
449
+ assert_match /Seq Scan on test_data/, explanations[0][1].join(";")
428
450
 
429
451
  s = NewRelic::Agent.get_stats("ActiveRecord/ActiveRecordFixtures::Order/find")
430
452
  assert_equal 1, s.call_count
@@ -450,7 +472,11 @@ class NewRelic::Agent::Instrumentation::ActiveRecordInstrumentationTest < Test::
450
472
  # These are only valid for rails 2.1 and later
451
473
  if NewRelic::Control.instance.rails_version >= NewRelic::VersionNumber.new("2.1.0")
452
474
  ActiveRecordFixtures::Order.class_eval do
453
- named_scope :jeffs, :conditions => { :name => 'Jeff' }
475
+ if NewRelic::Control.instance.rails_version < NewRelic::VersionNumber.new("3.1")
476
+ named_scope :jeffs, :conditions => { :name => 'Jeff' }
477
+ else
478
+ scope :jeffs, :conditions => { :name => 'Jeff' }
479
+ end
454
480
  end
455
481
  def test_named_scope
456
482
  ActiveRecordFixtures::Order.create :name => 'Jeff'
@@ -473,7 +499,7 @@ class NewRelic::Agent::Instrumentation::ActiveRecordInstrumentationTest < Test::
473
499
  true
474
500
  end
475
501
 
476
- expected_metrics = %W[ActiveRecord/all Database/SQL/select]
502
+ expected_metrics = %W[ActiveRecord/all Database/SQL/select RemoteService/sql/mysql/localhost]
477
503
 
478
504
  assert_calls_metrics(*expected_metrics) do
479
505
  begin
@@ -487,6 +513,7 @@ class NewRelic::Agent::Instrumentation::ActiveRecordInstrumentationTest < Test::
487
513
  compare_metrics expected_metrics, metrics
488
514
  check_metric_count('Database/SQL/select', 1)
489
515
  check_metric_count('ActiveRecord/all', 1)
516
+ check_metric_count('RemoteService/sql/mysql/localhost', 1)
490
517
  end
491
518
 
492
519
  def test_rescue_handling
@@ -501,22 +528,49 @@ class NewRelic::Agent::Instrumentation::ActiveRecordInstrumentationTest < Test::
501
528
  assert_equal 'preserve-me!', e.message
502
529
  end
503
530
  end
504
-
531
+
532
+ def test_remote_service_metric_respects_dynamic_connection_config
533
+ return unless isMysql?
534
+
535
+ # puts NewRelic::Agent::Database.config.inspect
536
+
537
+ ActiveRecordFixtures::Shipment.connection.execute('SHOW TABLES');
538
+ assert(NewRelic::Agent.get_stats('RemoteService/sql/mysql/localhost').call_count != 0)
539
+
540
+ config = ActiveRecordFixtures::Shipment.connection.instance_eval { @config }
541
+ config[:host] = '127.0.0.1'
542
+ connection = ActiveRecordFixtures::Shipment.establish_connection(config)
543
+
544
+ # puts ActiveRecord::Base.connection.instance_eval { @config }.inspect
545
+ # puts NewRelic::Agent::Database.config.inspect
546
+
547
+ ActiveRecordFixtures::Shipment.connection.execute('SHOW TABLES');
548
+ assert(NewRelic::Agent.get_stats('RemoteService/sql/mysql/127.0.0.1').call_count != 0)
549
+
550
+ config[:host] = 'localhost'
551
+ ActiveRecordFixtures::Shipment.establish_connection(config)
552
+
553
+ # raise NewRelic::Agent.instance.stats_engine.inspect
554
+ end
555
+
505
556
  private
506
557
 
507
558
  def rails3?
508
559
  (defined?(Rails) && Rails.respond_to?(:version) && Rails.version.to_i == 3)
509
560
  end
510
561
 
562
+ def rails_env
563
+ rails3? ? ::Rails.env : RAILS_ENV
564
+ end
565
+
511
566
  def isPostgres?
512
- ActiveRecordFixtures::Order.configurations[RAILS_ENV]['adapter'] =~ /postgres/i
567
+ ActiveRecordFixtures::Order.configurations[rails_env]['adapter'] =~ /postgres/i
513
568
  end
514
569
  def isMysql?
515
570
  ActiveRecordFixtures::Order.connection.class.name =~ /mysql/i
516
571
  end
517
572
 
518
573
  def isSqlite?
519
- ActiveRecord::Base.configurations[RAILS_ENV]['adapter'] =~ /sqlite/i
574
+ ActiveRecord::Base.configurations[rails_env]['adapter'] =~ /sqlite/i
520
575
  end
521
-
522
576
  end