wd_newrelic_rpm 3.3.4.1 → 3.5.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (290) hide show
  1. data/.gitignore +20 -0
  2. data/.project +23 -0
  3. data/.travis.yml +9 -0
  4. data/CHANGELOG +317 -39
  5. data/GUIDELINES_FOR_CONTRIBUTING.md +76 -0
  6. data/Gemfile +16 -0
  7. data/LICENSE +1 -1
  8. data/{README.rdoc → README.md} +71 -55
  9. data/Rakefile +62 -0
  10. data/bin/mongrel_rpm +1 -1
  11. data/config.dot +290 -0
  12. data/config/database.yml +5 -0
  13. data/init.rb +31 -0
  14. data/lib/new_relic/agent.rb +31 -60
  15. data/lib/new_relic/agent/agent.rb +277 -502
  16. data/lib/new_relic/agent/agent_logger.rb +165 -0
  17. data/lib/new_relic/agent/audit_logger.rb +72 -0
  18. data/lib/new_relic/agent/beacon_configuration.rb +36 -50
  19. data/lib/new_relic/agent/browser_monitoring.rb +114 -61
  20. data/lib/new_relic/agent/busy_calculator.rb +14 -6
  21. data/lib/new_relic/agent/configuration.rb +74 -0
  22. data/lib/new_relic/agent/configuration/defaults.rb +126 -0
  23. data/lib/new_relic/agent/configuration/environment_source.rb +49 -0
  24. data/lib/new_relic/agent/configuration/manager.rb +136 -0
  25. data/lib/new_relic/agent/configuration/mask_defaults.rb +10 -0
  26. data/lib/new_relic/agent/configuration/server_source.rb +27 -0
  27. data/lib/new_relic/agent/configuration/yaml_source.rb +63 -0
  28. data/lib/new_relic/agent/cross_process_monitoring.rb +43 -0
  29. data/lib/new_relic/agent/database.rb +39 -26
  30. data/lib/new_relic/agent/error_collector.rb +48 -49
  31. data/lib/new_relic/agent/instrumentation/active_merchant.rb +1 -1
  32. data/lib/new_relic/agent/instrumentation/active_record.rb +4 -7
  33. data/lib/new_relic/agent/instrumentation/acts_as_solr.rb +1 -1
  34. data/lib/new_relic/agent/instrumentation/authlogic.rb +1 -1
  35. data/lib/new_relic/agent/instrumentation/browser_monitoring_timings.rb +41 -0
  36. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +35 -12
  37. data/lib/new_relic/agent/instrumentation/data_mapper.rb +4 -12
  38. data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +2 -2
  39. data/lib/new_relic/agent/instrumentation/memcache.rb +6 -6
  40. data/lib/new_relic/agent/instrumentation/merb/controller.rb +1 -1
  41. data/lib/new_relic/agent/instrumentation/merb/errors.rb +1 -1
  42. data/lib/new_relic/agent/instrumentation/metric_frame.rb +4 -14
  43. data/lib/new_relic/agent/instrumentation/metric_frame/pop.rb +1 -1
  44. data/lib/new_relic/agent/instrumentation/net.rb +1 -1
  45. data/lib/new_relic/agent/instrumentation/passenger_instrumentation.rb +6 -20
  46. data/lib/new_relic/agent/instrumentation/queue_time.rb +2 -2
  47. data/lib/new_relic/agent/instrumentation/rack.rb +1 -1
  48. data/lib/new_relic/agent/instrumentation/rails/action_controller.rb +7 -7
  49. data/lib/new_relic/agent/instrumentation/rails/action_web_service.rb +1 -1
  50. data/lib/new_relic/agent/instrumentation/rails/errors.rb +1 -1
  51. data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +5 -5
  52. data/lib/new_relic/agent/instrumentation/rails3/errors.rb +6 -2
  53. data/lib/new_relic/agent/instrumentation/resque.rb +81 -0
  54. data/lib/new_relic/agent/instrumentation/sinatra.rb +21 -10
  55. data/lib/new_relic/agent/instrumentation/sunspot.rb +1 -1
  56. data/lib/new_relic/agent/instrumentation/unicorn_instrumentation.rb +5 -4
  57. data/lib/new_relic/agent/method_tracer.rb +11 -9
  58. data/lib/new_relic/agent/new_relic_service.rb +379 -0
  59. data/lib/new_relic/agent/pipe_channel_manager.rb +175 -0
  60. data/lib/new_relic/agent/pipe_service.rb +58 -0
  61. data/lib/new_relic/agent/samplers/delayed_job_sampler.rb +86 -0
  62. data/lib/new_relic/agent/samplers/memory_sampler.rb +6 -8
  63. data/lib/new_relic/agent/sql_sampler.rb +31 -74
  64. data/lib/new_relic/agent/stats_engine.rb +0 -5
  65. data/lib/new_relic/agent/stats_engine/gc_profiler.rb +40 -24
  66. data/lib/new_relic/agent/stats_engine/metric_stats.rb +89 -14
  67. data/lib/new_relic/agent/stats_engine/samplers.rb +9 -7
  68. data/lib/new_relic/agent/stats_engine/transactions.rb +20 -12
  69. data/lib/new_relic/agent/thread.rb +32 -0
  70. data/lib/new_relic/agent/thread_profiler.rb +306 -0
  71. data/lib/new_relic/agent/transaction_info.rb +24 -4
  72. data/lib/new_relic/agent/transaction_sample_builder.rb +12 -13
  73. data/lib/new_relic/agent/transaction_sampler.rb +49 -65
  74. data/lib/new_relic/agent/worker_loop.rb +31 -25
  75. data/lib/new_relic/collection_helper.rb +1 -1
  76. data/lib/new_relic/commands/deployments.rb +19 -10
  77. data/lib/new_relic/control.rb +1 -3
  78. data/lib/new_relic/control/class_methods.rb +10 -5
  79. data/lib/new_relic/control/frameworks/merb.rb +0 -6
  80. data/lib/new_relic/control/frameworks/rails.rb +30 -45
  81. data/lib/new_relic/control/frameworks/rails3.rb +23 -18
  82. data/lib/new_relic/control/frameworks/rails4.rb +23 -0
  83. data/lib/new_relic/control/frameworks/ruby.rb +2 -23
  84. data/lib/new_relic/control/instance_methods.rb +35 -73
  85. data/lib/new_relic/control/instrumentation.rb +7 -12
  86. data/lib/new_relic/control/server_methods.rb +17 -19
  87. data/lib/new_relic/delayed_job_injection.rb +2 -2
  88. data/lib/new_relic/helper.rb +34 -0
  89. data/lib/new_relic/language_support.rb +56 -37
  90. data/lib/new_relic/local_environment.rb +32 -67
  91. data/lib/new_relic/metric_data.rb +10 -2
  92. data/lib/new_relic/metric_spec.rb +7 -3
  93. data/lib/new_relic/noticed_error.rb +32 -9
  94. data/lib/new_relic/rack.rb +4 -0
  95. data/lib/new_relic/rack/browser_monitoring.rb +34 -25
  96. data/lib/new_relic/rack/developer_mode.rb +3 -0
  97. data/lib/new_relic/rack/error_collector.rb +56 -0
  98. data/lib/new_relic/stats.rb +9 -7
  99. data/lib/new_relic/transaction_sample.rb +19 -18
  100. data/lib/new_relic/transaction_sample/segment.rb +13 -15
  101. data/lib/new_relic/version.rb +19 -3
  102. data/lib/newrelic_rpm.rb +1 -1
  103. data/lib/tasks/tests.rake +6 -8
  104. data/newrelic.yml +15 -32
  105. data/newrelic_rpm.gemspec +224 -43
  106. data/newrelic_rpm.gemspec.erb +54 -0
  107. data/test/config/newrelic.yml +4 -3
  108. data/test/config/test_control.rb +18 -18
  109. data/test/fixtures/gemspec_no_build.rb +442 -0
  110. data/test/fixtures/gemspec_with_build.rb +442 -0
  111. data/test/fixtures/gemspec_with_build_and_stage.rb +442 -0
  112. data/test/intentional_fail.rb +10 -0
  113. data/test/multiverse/.gitignore +10 -0
  114. data/test/multiverse/README.md +85 -0
  115. data/test/multiverse/lib/multiverse/color.rb +13 -0
  116. data/test/multiverse/lib/multiverse/envfile.rb +66 -0
  117. data/test/multiverse/lib/multiverse/environment.rb +16 -0
  118. data/test/multiverse/lib/multiverse/output_collector.rb +29 -0
  119. data/test/multiverse/lib/multiverse/runner.rb +44 -0
  120. data/test/multiverse/lib/multiverse/suite.rb +162 -0
  121. data/test/multiverse/script/run_one +3 -0
  122. data/test/multiverse/script/runner +9 -0
  123. data/test/multiverse/suites/active_record/Envfile +13 -0
  124. data/test/multiverse/suites/active_record/ar_method_aliasing.rb +94 -0
  125. data/test/multiverse/suites/active_record/config/newrelic.yml +22 -0
  126. data/test/multiverse/suites/active_record/encoding_test.rb +26 -0
  127. data/test/multiverse/suites/agent_only/Envfile +4 -0
  128. data/test/multiverse/suites/agent_only/audit_log_test.rb +99 -0
  129. data/test/multiverse/suites/agent_only/config/newrelic.yml +22 -0
  130. data/test/multiverse/suites/agent_only/http_response_code_test.rb +53 -0
  131. data/test/multiverse/suites/agent_only/marshaling_test.rb +109 -0
  132. data/test/multiverse/suites/agent_only/method_visibility_test.rb +98 -0
  133. data/test/multiverse/suites/agent_only/pipe_manager_test.rb +33 -0
  134. data/test/multiverse/suites/agent_only/service_timeout_test.rb +29 -0
  135. data/test/multiverse/suites/agent_only/test_trace_method_with_punctuation.rb +30 -0
  136. data/test/multiverse/suites/agent_only/test_trace_transaction_with_punctuation.rb +32 -0
  137. data/test/multiverse/suites/agent_only/thread_profiling_test.rb +80 -0
  138. data/test/multiverse/suites/config_file_loading/Envfile +7 -0
  139. data/test/multiverse/suites/config_file_loading/config_file_loading_test.rb +106 -0
  140. data/test/multiverse/suites/datamapper/Envfile +8 -0
  141. data/test/multiverse/suites/datamapper/config/newrelic.yml +22 -0
  142. data/test/multiverse/suites/datamapper/encoding_test.rb +36 -0
  143. data/test/multiverse/suites/logging/Envfile +4 -0
  144. data/test/multiverse/suites/logging/config/newrelic.yml +22 -0
  145. data/test/multiverse/suites/logging/logging_test.rb +143 -0
  146. data/test/multiverse/suites/monitor_mode_false/Envfile +2 -0
  147. data/test/multiverse/suites/monitor_mode_false/config/newrelic.yml +25 -0
  148. data/test/multiverse/suites/monitor_mode_false/no_dns_resolv.rb +29 -0
  149. data/test/multiverse/suites/no_load/Envfile +2 -0
  150. data/test/multiverse/suites/no_load/config/newrelic.yml +22 -0
  151. data/test/multiverse/suites/no_load/start_up_test.rb +14 -0
  152. data/test/multiverse/suites/rails_3_error_tracing/Envfile +15 -0
  153. data/test/multiverse/suites/rails_3_error_tracing/config/newrelic.yml +165 -0
  154. data/test/multiverse/suites/rails_3_error_tracing/error_tracing_test.rb +236 -0
  155. data/test/multiverse/suites/rails_3_gc/Envfile +8 -0
  156. data/test/multiverse/suites/rails_3_gc/config/newrelic.yml +167 -0
  157. data/test/multiverse/suites/rails_3_gc/instrumentation_test.rb +92 -0
  158. data/test/multiverse/suites/rails_3_queue_time/Envfile +15 -0
  159. data/test/multiverse/suites/rails_3_queue_time/config/newrelic.yml +165 -0
  160. data/test/multiverse/suites/rails_3_queue_time/queue_time_test.rb +75 -0
  161. data/test/multiverse/suites/rails_3_views/.gitignore +3 -0
  162. data/test/multiverse/suites/rails_3_views/Envfile +16 -0
  163. data/test/multiverse/suites/rails_3_views/app/views/foos/_foo.html.haml +1 -0
  164. data/test/multiverse/suites/rails_3_views/app/views/test/_a_partial.html.erb +1 -0
  165. data/test/multiverse/suites/rails_3_views/app/views/test/_mid_partial.html.erb +1 -0
  166. data/test/multiverse/suites/rails_3_views/app/views/test/_top_partial.html.erb +3 -0
  167. data/test/multiverse/suites/rails_3_views/app/views/test/deep_partial.html.erb +3 -0
  168. data/test/multiverse/suites/rails_3_views/app/views/test/haml_view.html.haml +6 -0
  169. data/test/multiverse/suites/rails_3_views/app/views/test/index.html.erb +4 -0
  170. data/test/multiverse/suites/rails_3_views/config/newrelic.yml +164 -0
  171. data/test/multiverse/suites/rails_3_views/view_instrumentation_test.rb +245 -0
  172. data/test/multiverse/suites/resque/Envfile +21 -0
  173. data/test/multiverse/suites/resque/config/newrelic.yml +22 -0
  174. data/test/multiverse/suites/resque/dump.rdb +0 -0
  175. data/test/multiverse/suites/resque/instrumentation_test.rb +73 -0
  176. data/test/multiverse/suites/rum_auto_instrumentation/Envfile +4 -0
  177. data/test/multiverse/suites/rum_auto_instrumentation/config/newrelic.yml +24 -0
  178. data/test/multiverse/suites/rum_auto_instrumentation/responses/worst_case_small.html +5000 -0
  179. data/test/multiverse/suites/rum_auto_instrumentation/sanity_test.rb +102 -0
  180. data/test/multiverse/suites/sinatra/Envfile +13 -0
  181. data/test/multiverse/suites/sinatra/config/newrelic.yml +24 -0
  182. data/test/multiverse/suites/sinatra/sinatra_metric_explosion_test.rb +77 -0
  183. data/test/multiverse/suites/sinatra/sinatra_routes_test.rb +46 -0
  184. data/test/multiverse/suites/sinatra/sinatra_test.rb +55 -0
  185. data/test/multiverse/test/multiverse_test.rb +55 -0
  186. data/test/multiverse/test/suite_examples/one/a/Envfile +3 -0
  187. data/test/multiverse/test/suite_examples/one/a/a_test.rb +11 -0
  188. data/test/multiverse/test/suite_examples/one/a/config/newrelic.yml +24 -0
  189. data/test/multiverse/test/suite_examples/one/b/Envfile +3 -0
  190. data/test/multiverse/test/suite_examples/one/b/b_test.rb +11 -0
  191. data/test/multiverse/test/suite_examples/one/b/config/newrelic.yml +24 -0
  192. data/test/multiverse/test/suite_examples/three/a/Envfile +2 -0
  193. data/test/multiverse/test/suite_examples/three/a/fail_test.rb +6 -0
  194. data/test/multiverse/test/suite_examples/three/b/Envfile +2 -0
  195. data/test/multiverse/test/suite_examples/three/b/win_test.rb +6 -0
  196. data/test/multiverse/test/suite_examples/two/a/Envfile +1 -0
  197. data/test/multiverse/test/suite_examples/two/a/fail_test.rb +6 -0
  198. data/test/new_relic/agent/agent/connect_test.rb +151 -227
  199. data/test/new_relic/agent/agent/start_test.rb +68 -118
  200. data/test/new_relic/agent/agent/start_worker_thread_test.rb +12 -74
  201. data/test/new_relic/agent/agent_logger_test.rb +153 -0
  202. data/test/new_relic/agent/agent_test.rb +116 -30
  203. data/test/new_relic/agent/agent_test_controller.rb +1 -1
  204. data/test/new_relic/agent/agent_test_controller_test.rb +42 -10
  205. data/test/new_relic/agent/audit_logger_test.rb +105 -0
  206. data/test/new_relic/agent/beacon_configuration_test.rb +63 -67
  207. data/test/new_relic/agent/browser_monitoring_test.rb +151 -79
  208. data/test/new_relic/agent/busy_calculator_test.rb +7 -0
  209. data/test/new_relic/agent/configuration/environment_source_test.rb +79 -0
  210. data/test/new_relic/agent/configuration/manager_test.rb +204 -0
  211. data/test/new_relic/agent/configuration/server_source_test.rb +45 -0
  212. data/test/new_relic/agent/configuration/yaml_source_test.rb +75 -0
  213. data/test/new_relic/agent/cross_process_monitoring_test.rb +77 -0
  214. data/test/new_relic/agent/database_test.rb +12 -11
  215. data/test/new_relic/agent/error_collector/notice_error_test.rb +64 -53
  216. data/test/new_relic/agent/error_collector_test.rb +33 -19
  217. data/test/new_relic/agent/instrumentation/active_record_instrumentation_test.rb +60 -30
  218. data/test/new_relic/agent/instrumentation/browser_monitoring_timings_test.rb +39 -0
  219. data/test/new_relic/agent/instrumentation/metric_frame/pop_test.rb +1 -1
  220. data/test/new_relic/agent/instrumentation/metric_frame_test.rb +6 -0
  221. data/test/new_relic/agent/instrumentation/queue_time_test.rb +14 -0
  222. data/test/new_relic/agent/instrumentation/sinatra_test.rb +25 -0
  223. data/test/new_relic/agent/instrumentation/task_instrumentation_test.rb +2 -2
  224. data/test/new_relic/agent/method_tracer/class_methods/add_method_tracer_test.rb +4 -10
  225. data/test/new_relic/agent/method_tracer/instance_methods/trace_execution_scoped_test.rb +3 -15
  226. data/test/new_relic/agent/method_tracer_test.rb +7 -6
  227. data/test/new_relic/agent/mock_scope_listener.rb +3 -0
  228. data/test/new_relic/agent/new_relic_service_test.rb +376 -0
  229. data/test/new_relic/agent/pipe_channel_manager_test.rb +131 -0
  230. data/test/new_relic/agent/pipe_service_test.rb +113 -0
  231. data/test/new_relic/agent/rpm_agent_test.rb +27 -50
  232. data/test/new_relic/agent/sql_sampler_test.rb +81 -56
  233. data/test/new_relic/agent/stats_engine/metric_stats/harvest_test.rb +3 -20
  234. data/test/new_relic/agent/stats_engine/metric_stats_test.rb +12 -1
  235. data/test/new_relic/agent/stats_engine_test.rb +17 -8
  236. data/test/new_relic/agent/thread_profiler_test.rb +537 -0
  237. data/test/new_relic/agent/thread_test.rb +89 -0
  238. data/test/new_relic/agent/threaded_test.rb +65 -0
  239. data/test/new_relic/agent/transaction_info_test.rb +45 -4
  240. data/test/new_relic/agent/transaction_sample_builder_test.rb +8 -7
  241. data/test/new_relic/agent/transaction_sampler_test.rb +193 -204
  242. data/test/new_relic/agent/worker_loop_test.rb +26 -11
  243. data/test/new_relic/agent_test.rb +113 -33
  244. data/test/new_relic/collection_helper_test.rb +7 -8
  245. data/test/new_relic/command/deployments_test.rb +18 -2
  246. data/test/new_relic/control/class_methods_test.rb +0 -18
  247. data/test/new_relic/control/frameworks/rails_test.rb +26 -0
  248. data/test/new_relic/control_test.rb +96 -137
  249. data/test/new_relic/delayed_job_injection_test.rb +6 -1
  250. data/test/new_relic/dispatcher_test.rb +54 -0
  251. data/test/new_relic/fake_collector.rb +283 -0
  252. data/test/new_relic/fake_service.rb +53 -0
  253. data/test/new_relic/fakes_sending_data.rb +30 -0
  254. data/test/new_relic/framework_test.rb +53 -0
  255. data/test/new_relic/load_test.rb +13 -0
  256. data/test/new_relic/local_environment_test.rb +11 -11
  257. data/test/new_relic/metric_data_test.rb +45 -16
  258. data/test/new_relic/noticed_error_test.rb +24 -0
  259. data/test/new_relic/rack/browser_monitoring_test.rb +20 -10
  260. data/test/new_relic/rack/developer_mode_test.rb +13 -7
  261. data/test/new_relic/rack/error_collector_test.rb +74 -0
  262. data/test/new_relic/stats_test.rb +10 -0
  263. data/test/new_relic/transaction_sample/segment_test.rb +23 -4
  264. data/test/new_relic/transaction_sample_test.rb +47 -2
  265. data/test/new_relic/version_number_test.rb +32 -0
  266. data/test/script/build_test_gem.sh +9 -3
  267. data/test/script/ci.sh +108 -35
  268. data/test/script/ci_agent-tests_runner.sh +82 -0
  269. data/test/script/ci_multiverse_runner.sh +63 -0
  270. data/test/test_contexts.rb +1 -0
  271. data/test/test_helper.rb +68 -18
  272. data/ui/helpers/developer_mode_helper.rb +21 -11
  273. data/ui/views/layouts/newrelic_default.rhtml +1 -0
  274. data/ui/views/newrelic/file/images/arrow-close.png +0 -0
  275. data/ui/views/newrelic/file/images/arrow-open.png +0 -0
  276. data/ui/views/newrelic/file/images/blue_bar.gif +0 -0
  277. data/ui/views/newrelic/file/images/file_icon.png +0 -0
  278. data/ui/views/newrelic/file/images/gray_bar.gif +0 -0
  279. data/ui/views/newrelic/show_sample.rhtml +1 -1
  280. data/ui/views/newrelic/threads.rhtml +2 -10
  281. data/vendor/gems/metric_parser-0.1.0.pre1/.specification +116 -0
  282. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/servlet_init.rb +7 -0
  283. metadata +191 -65
  284. data/lib/new_relic/agent/samplers/delayed_job_lock_sampler.rb +0 -40
  285. data/lib/new_relic/control/configuration.rb +0 -206
  286. data/lib/new_relic/control/logging_methods.rb +0 -143
  287. data/lib/new_relic/data_serialization.rb +0 -151
  288. data/test/new_relic/control/configuration_test.rb +0 -84
  289. data/test/new_relic/control/logging_methods_test.rb +0 -185
  290. data/test/new_relic/data_serialization_test.rb +0 -208
@@ -1,30 +1,13 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__),'..','..','..','..','test_helper'))
2
2
  require 'new_relic/agent/stats_engine/metric_stats'
3
+
3
4
  class NewRelic::Agent::StatsEngine::MetricStats::HarvestTest < Test::Unit::TestCase
4
5
  include NewRelic::Agent::StatsEngine::MetricStats::Harvest
5
6
 
6
7
  attr_accessor :stats_hash
7
- def test_merge_stats_trivial
8
- self.stats_hash = {}
9
- merge_stats({}, {})
10
- end
11
-
12
8
  def test_merge_stats_with_nil_stats
13
- metric_ids = mock('metric ids')
14
- mock_stats_hash = mock('stats_hash')
15
- mock_spec = mock('spec')
16
- mock_stats = mock('stats')
17
- mock_stats_hash.expects(:each).yields(mock_spec, mock_stats)
18
- self.stats_hash = mock_stats_hash
19
-
20
- self.expects(:coerce_to_metric_spec).with(mock_spec).returns(mock_spec)
21
- self.expects(:clone_and_reset_stats).with(mock_spec, mock_stats).returns(mock_stats)
22
- self.expects(:merge_old_data!).with(mock_spec, mock_stats, {})
23
- metric_ids.expects(:[]).with(mock_spec).returns('an id')
24
- self.expects(:add_data_to_send_unless_empty).with({}, mock_stats, mock_spec, 'an id')
25
-
26
-
27
- merge_stats({}, metric_ids)
9
+ self.stats_hash = NewRelic::Agent::StatsEngine::MetricStats::SynchronizedHash.new
10
+ assert_equal({}, merge_stats({}, {}))
28
11
  end
29
12
 
30
13
 
@@ -44,7 +44,7 @@ class NewRelic::Agent::MetricStatsTest < Test::Unit::TestCase
44
44
  assert_equal 4, @engine.get_stats("c").total_call_time
45
45
 
46
46
  metric_data = @engine.harvest_timeslice_data({}, {}).values
47
-
47
+
48
48
  # after harvest, all the metrics should be reset
49
49
  assert_equal 0, @engine.get_stats("a").call_count
50
50
  assert_equal 0, @engine.get_stats("a").total_call_time
@@ -78,5 +78,16 @@ class NewRelic::Agent::MetricStatsTest < Test::Unit::TestCase
78
78
  assert_equal 2, stats.call_count
79
79
  assert_equal 3, stats.total_call_time
80
80
  end
81
+
82
+ def test_rescues_from_synchronization_failure_on_write
83
+ hash = NewRelic::Agent::StatsEngine::MetricStats::SynchronizedHash.new
84
+ 10.times { |i| hash[i] = i }
85
+
86
+ assert_nothing_raised do
87
+ hash.each do |k, v|
88
+ hash[11] = 1
89
+ end
90
+ end
91
+ end
81
92
  end
82
93
 
@@ -9,7 +9,7 @@ class NewRelic::Agent::StatsEngineTest < Test::Unit::TestCase
9
9
  puts e
10
10
  puts e.backtrace.join("\n")
11
11
  end
12
-
12
+
13
13
  def teardown
14
14
  @engine.harvest_timeslice_data({},{})
15
15
  mocha_teardown
@@ -193,26 +193,35 @@ class NewRelic::Agent::StatsEngineTest < Test::Unit::TestCase
193
193
  ::Rubinius::Agent.stubs(:loopback).returns(agent)
194
194
  elsif NewRelic::LanguageSupport.using_version?('1.9')
195
195
  ::GC::Profiler.stubs(:enabled?).returns(true)
196
- ::GC::Profiler.stubs(:total_time).returns(1.0, 4.0)
197
- ::GC.stubs(:count).returns(1, 3)
198
- elsif NewRelic::LanguageSupport.using_version?('1.8')
196
+ ::GC::Profiler.stubs(:total_time).returns(1.0, 4.0)
197
+ ::GC.stubs(:count).returns(1, 3)
198
+ ::GC::Profiler.stubs(:clear).returns(nil)
199
+ elsif NewRelic::LanguageSupport.using_version?('1.8.7') &&
200
+ RUBY_DESCRIPTION =~ /Ruby Enterprise Edition/
199
201
  ::GC.stubs(:time).returns(1000000, 4000000)
200
202
  ::GC.stubs(:collections).returns(1, 3)
203
+ else
204
+ return true # no need to test if we're not collecting GC metrics
201
205
  end
202
-
206
+
203
207
  engine = NewRelic::Agent.instance.stats_engine
204
- scope = engine.push_scope "scope"
208
+ tracer = NewRelic::Agent::TransactionSampler.new
209
+ tracer.instance_variable_set(:@last_sample,
210
+ NewRelic::TransactionSample.new)
211
+ engine.transaction_sampler = tracer
205
212
  engine.start_transaction
213
+ scope = engine.push_scope "scope"
206
214
  engine.pop_scope scope, 0.01
207
215
  engine.end_transaction
208
-
216
+
209
217
  gc_stats = engine.get_stats('GC/cumulative')
210
218
  assert_equal 2, gc_stats.call_count
211
219
  assert_equal 3.0, gc_stats.total_call_time
220
+ assert_equal(3.0, tracer.last_sample.params[:custom_params][:gc_time])
212
221
  ensure
213
222
  GC.enable unless NewRelic::LanguageSupport.using_engine?('jruby')
214
223
  end
215
-
224
+
216
225
  private
217
226
  def check_time_approximate(expected, actual)
218
227
  assert((expected - actual).abs < 0.1, "Expected between #{expected - 0.1} and #{expected + 0.1}, got #{actual}")
@@ -0,0 +1,537 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__),'..','..','test_helper'))
2
+ require 'base64'
3
+ require 'thread'
4
+ require 'timeout'
5
+ require 'zlib'
6
+ require 'new_relic/agent/threaded_test'
7
+ require 'new_relic/agent/thread_profiler'
8
+
9
+ START_COMMAND = [[666,{
10
+ "name" => "start_profiler",
11
+ "arguments" => {
12
+ "profile_id" => 42,
13
+ "sample_period" => 0.02,
14
+ "duration" => 0.025,
15
+ "only_runnable_threads" => false,
16
+ "only_request_threads" => false,
17
+ "profile_agent_code" => false,
18
+ }
19
+ }]]
20
+
21
+ STOP_COMMAND = [[666,{
22
+ "name" => "stop_profiler",
23
+ "arguments" => {
24
+ "profile_id" => 42,
25
+ "report_data" => true,
26
+ }
27
+ }]]
28
+
29
+ STOP_AND_DISCARD_COMMAND = [[666,{
30
+ "name" => "stop_profiler",
31
+ "arguments" => {
32
+ "profile_id" => 42,
33
+ "report_data" => false,
34
+ }
35
+ }]]
36
+
37
+ NO_COMMAND = []
38
+
39
+ if !NewRelic::Agent::ThreadProfiler.is_supported?
40
+
41
+ class ThreadProfilerUnsupportedTest < Test::Unit::TestCase
42
+ def setup
43
+ @profiler = NewRelic::Agent::ThreadProfiler.new
44
+ end
45
+
46
+ def test_thread_profiling_isnt_supported
47
+ assert_equal false, NewRelic::Agent::ThreadProfiler.is_supported?
48
+ end
49
+
50
+ def test_wont_start_when_not_supported
51
+ @profiler.start(0, 0, 0, true)
52
+ assert_equal false, @profiler.running?
53
+ end
54
+
55
+ def test_stop_is_safe_when_not_supported
56
+ @profiler.start(0, 0, 0, true)
57
+ @profiler.stop(true)
58
+ end
59
+
60
+ def test_wont_start_and_reports_error
61
+ errors = nil
62
+ @profiler.respond_to_commands(START_COMMAND) { |_, err| errors = err }
63
+ assert_equal false, errors.nil?
64
+ assert_equal false, @profiler.running?
65
+ end
66
+
67
+ end
68
+
69
+ else
70
+
71
+ require 'json'
72
+
73
+ class ThreadProfilerTest < ThreadedTest
74
+ def setup
75
+ super
76
+ @profiler = NewRelic::Agent::ThreadProfiler.new
77
+ end
78
+
79
+ def test_is_supported
80
+ assert NewRelic::Agent::ThreadProfiler.is_supported?
81
+ end
82
+
83
+ def test_is_not_running
84
+ assert !@profiler.running?
85
+ end
86
+
87
+ def test_is_running
88
+ @profiler.start(0, 0, 0, true)
89
+ assert @profiler.running?
90
+ end
91
+
92
+ def test_is_not_finished_if_no_profile_started
93
+ assert !@profiler.finished?
94
+ end
95
+
96
+ def test_can_stop_a_running_profile
97
+ @profiler.start(0, 0, 0, true)
98
+ assert @profiler.running?
99
+
100
+ @profiler.stop(true)
101
+
102
+ assert @profiler.finished?
103
+ assert_not_nil @profiler.profile
104
+ end
105
+
106
+ def test_can_stop_a_running_profile_and_discard
107
+ @profiler.start(0, 0, 0, true)
108
+ assert @profiler.running?
109
+
110
+ @profiler.stop(false)
111
+
112
+ assert_nil @profiler.profile
113
+ end
114
+
115
+ def test_wont_crash_if_stopping_when_not_started
116
+ @profiler.stop(true)
117
+ assert_equal false, @profiler.running?
118
+ end
119
+
120
+ def test_respond_to_commands_with_no_commands_doesnt_run
121
+ @profiler.respond_to_commands(NO_COMMAND)
122
+ assert_equal false, @profiler.running?
123
+ end
124
+
125
+ def test_respond_to_commands_starts_running
126
+ @profiler.respond_to_commands(START_COMMAND) {|_, err| start_error = err}
127
+ assert_equal true, @profiler.running?
128
+ end
129
+
130
+ def test_respond_to_commands_stops
131
+ @profiler.start(0, 0, 0, true)
132
+ assert @profiler.running?
133
+
134
+ @profiler.respond_to_commands(STOP_COMMAND)
135
+ assert_equal true, @profiler.profile.finished?
136
+ end
137
+
138
+ def test_respond_to_commands_stops_and_discards
139
+ @profiler.start(0, 0, 0, true)
140
+ assert @profiler.running?
141
+
142
+ @profiler.respond_to_commands(STOP_AND_DISCARD_COMMAND)
143
+ assert_nil @profiler.profile
144
+ end
145
+
146
+ def test_respond_to_commands_wont_start_second_profile
147
+ @profiler.start(0, 0, 0, true)
148
+ original_profile = @profiler.profile
149
+
150
+ @profiler.respond_to_commands(START_COMMAND)
151
+
152
+ assert_equal original_profile, @profiler.profile
153
+ end
154
+
155
+ def test_response_to_commands_start_notifies_of_result
156
+ saw_command_id = nil
157
+ @profiler.respond_to_commands(START_COMMAND) { |id, err| saw_command_id = id }
158
+ assert_equal 666, saw_command_id
159
+ end
160
+
161
+ def test_response_to_commands_start_notifies_of_error
162
+ saw_command_id = nil
163
+ error = nil
164
+
165
+ @profiler.respond_to_commands(START_COMMAND)
166
+ @profiler.respond_to_commands(START_COMMAND) { |id, err| saw_command_id = id; error = err }
167
+
168
+ assert_equal 666, saw_command_id
169
+ assert_not_nil error
170
+ end
171
+
172
+ def test_response_to_commands_stop_notifies_of_result
173
+ saw_command_id = nil
174
+ @profiler.start(0,0, 0, true)
175
+ @profiler.respond_to_commands(STOP_COMMAND) { |id, err| saw_command_id = id }
176
+ assert_equal 666, saw_command_id
177
+ end
178
+
179
+ def test_command_attributes_passed_along
180
+ @profiler.respond_to_commands(START_COMMAND)
181
+ assert_equal 42, @profiler.profile.profile_id
182
+ assert_equal 0.02, @profiler.profile.interval
183
+ assert_equal false, @profiler.profile.profile_agent_code
184
+ end
185
+
186
+ def test_missing_name_in_command
187
+ command = [[666,{ "arguments" => {} } ]]
188
+ @profiler.respond_to_commands(command)
189
+
190
+ assert_equal false, @profiler.running?
191
+ end
192
+
193
+ def test_malformed_agent_command
194
+ command = [[666]]
195
+ @profiler.respond_to_commands(command)
196
+
197
+ assert_equal false, @profiler.running?
198
+ end
199
+
200
+ end
201
+
202
+ class ThreadProfileTest < ThreadedTest
203
+
204
+ def setup
205
+ super
206
+
207
+ @single_trace = [
208
+ "irb.rb:69:in `catch'",
209
+ "irb.rb:69:in `start'",
210
+ "irb:12:in `<main>'"
211
+ ]
212
+
213
+ @profile = NewRelic::Agent::ThreadProfile.new(-1, 0.029, 0.01, true)
214
+ end
215
+
216
+ # Running Tests
217
+ def test_profiler_collects_backtrace_from_every_thread
218
+ FakeThread.list << FakeThread.new
219
+ FakeThread.list << FakeThread.new
220
+
221
+ @profile.run
222
+
223
+ assert_equal 2, @profile.poll_count
224
+ assert_equal 4, @profile.sample_count
225
+ end
226
+
227
+ def test_profiler_collects_into_request_bucket
228
+ FakeThread.list << FakeThread.new(
229
+ :bucket => :request,
230
+ :backtrace => @single_trace)
231
+
232
+ @profile.run
233
+
234
+ assert_equal 1, @profile.traces[:request].size
235
+ end
236
+
237
+ def test_profiler_collects_into_background_bucket
238
+ FakeThread.list << FakeThread.new(
239
+ :bucket => :background,
240
+ :backtrace => @single_trace)
241
+
242
+ @profile.run
243
+
244
+ assert_equal 1, @profile.traces[:background].size
245
+ end
246
+
247
+ def test_profiler_collects_into_other_bucket
248
+ FakeThread.list << FakeThread.new(
249
+ :bucket => :other,
250
+ :backtrace => @single_trace)
251
+
252
+ @profile.run
253
+
254
+ assert_equal 1, @profile.traces[:other].size
255
+ end
256
+
257
+ def test_profiler_collects_into_agent_bucket
258
+ FakeThread.list << FakeThread.new(
259
+ :bucket => :agent,
260
+ :backtrace => @single_trace)
261
+
262
+ @profile.run
263
+
264
+ assert_equal 1, @profile.traces[:agent].size
265
+ end
266
+
267
+ def test_profiler_ignores_agent_threads_when_told_to
268
+ FakeThread.list << FakeThread.new(
269
+ :bucket => :ignore,
270
+ :backtrace => @single_trace)
271
+
272
+ @profile.run
273
+
274
+ @profile.traces.each do |key, trace|
275
+ assert trace.empty?, "Trace :#{key} should have been empty"
276
+ end
277
+ end
278
+
279
+ def test_profiler_tries_to_scrub_backtraces
280
+ FakeThread.list << FakeThread.new(
281
+ :bucket => :agent,
282
+ :backtrace => @single_trace,
283
+ :scrubbed_backtrace => @single_trace[0..0])
284
+
285
+ @profile.run
286
+
287
+ assert_equal [], @profile.traces[:agent].first.children
288
+ end
289
+
290
+ def test_profile_can_be_stopped
291
+ # Can't easily stop in middle of processing since FakeThread's synchronous
292
+ # Mark to bail immediately, then see we didn't record anything
293
+ @profile.stop
294
+
295
+ @profile.run
296
+
297
+ assert_not_nil @profile.stop_time
298
+ assert_equal true, @profile.finished?
299
+
300
+ assert_equal 0, @profile.poll_count
301
+ @profile.traces.each do |key, trace|
302
+ assert_equal [], trace, "Trace for :#{key} should have been empty"
303
+ end
304
+ end
305
+
306
+ def test_profiler_tracks_time
307
+ @profile.run
308
+
309
+ assert_not_nil @profile.start_time
310
+ assert_not_nil @profile.stop_time
311
+ end
312
+
313
+ def test_finished
314
+ assert !@profile.finished?
315
+
316
+ @profile.run.join
317
+
318
+ assert @profile.finished?
319
+ end
320
+
321
+ # Parsing and Aggregation Tests
322
+ def test_parse_backtrace
323
+ trace = [
324
+ "/Users/jclark/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/irb.rb:69:in `catch'",
325
+ "/Users/jclark/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/irb.rb:69:in `start'",
326
+ "/Users/jclark/.rbenv/versions/1.9.3/bin/irb:12:in `<main>'"
327
+ ]
328
+
329
+ result = NewRelic::Agent::ThreadProfile.parse_backtrace(trace)
330
+ assert_equal({ :method => 'catch',
331
+ :file => '/Users/jclark/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/irb.rb',
332
+ :line_no => 69 }, result[0])
333
+ assert_equal({ :method => 'start',
334
+ :file => '/Users/jclark/.rbenv/versions/1.9.3-p194/lib/ruby/1.9.1/irb.rb',
335
+ :line_no => 69 }, result[1])
336
+ assert_equal({ :method => '<main>',
337
+ :file => '/Users/jclark/.rbenv/versions/1.9.3/bin/irb',
338
+ :line_no => 12 }, result[2])
339
+ end
340
+
341
+ def test_aggregate_empty_trace
342
+ result = @profile.aggregate([])
343
+ assert_nil result
344
+ end
345
+
346
+ def test_aggregate_nil_trace
347
+ result = @profile.aggregate(nil)
348
+ assert_nil result
349
+ end
350
+
351
+ def test_aggregate_builds_tree_from_first_trace
352
+ result = @profile.aggregate(@single_trace)
353
+
354
+ tree = NewRelic::Agent::ThreadProfile::Node.new(@single_trace[-1])
355
+ child = NewRelic::Agent::ThreadProfile::Node.new(@single_trace[-2], tree)
356
+ NewRelic::Agent::ThreadProfile::Node.new(@single_trace[-3], child)
357
+
358
+ assert_equal tree, result
359
+ end
360
+
361
+ def test_aggregate_builds_tree_from_overlapping_traces
362
+ result = @profile.aggregate(@single_trace)
363
+ result = @profile.aggregate(@single_trace, [result])
364
+
365
+ tree = NewRelic::Agent::ThreadProfile::Node.new(@single_trace[-1])
366
+ tree.runnable_count += 1
367
+ child = NewRelic::Agent::ThreadProfile::Node.new(@single_trace[-2], tree)
368
+ child.runnable_count += 1
369
+ grand = NewRelic::Agent::ThreadProfile::Node.new(@single_trace[-3], child)
370
+ grand.runnable_count += 1
371
+
372
+ assert_equal tree, result
373
+ end
374
+
375
+ def test_aggregate_builds_tree_from_diverging_traces
376
+ other_trace = [
377
+ "irb.rb:69:in `catch'",
378
+ "chunky_bacon.rb:42:in `start'",
379
+ "irb:12:in `<main>'"
380
+ ]
381
+
382
+ result = @profile.aggregate(@single_trace)
383
+ result = @profile.aggregate(@single_trace, [result])
384
+
385
+ tree = NewRelic::Agent::ThreadProfile::Node.new(@single_trace[-1])
386
+ tree.runnable_count += 1
387
+
388
+ child = NewRelic::Agent::ThreadProfile::Node.new(@single_trace[-2], tree)
389
+ grand = NewRelic::Agent::ThreadProfile::Node.new(@single_trace[-3], child)
390
+
391
+ other_child = NewRelic::Agent::ThreadProfile::Node.new(other_trace[-2], tree)
392
+ other_grand = NewRelic::Agent::ThreadProfile::Node.new(other_trace[-3], other_child)
393
+
394
+ assert_equal tree, result
395
+ end
396
+
397
+ def test_prune_tree
398
+ @profile.aggregate(@single_trace)
399
+
400
+ t = @profile.prune!(1)
401
+
402
+ assert_equal 0, @profile.traces[:request].first.children.size
403
+ end
404
+
405
+ def test_prune_keeps_highest_counts
406
+ @profile.aggregate(@single_trace, @profile.traces[:request])
407
+ @profile.aggregate(@single_trace, @profile.traces[:other])
408
+ @profile.aggregate(@single_trace, @profile.traces[:other])
409
+
410
+ @profile.prune!(1)
411
+
412
+ assert_equal [], @profile.traces[:request]
413
+ assert_equal 1, @profile.traces[:other].size
414
+ assert_equal [], @profile.traces[:other][0].children
415
+ end
416
+
417
+ def test_prune_keeps_highest_count_then_depths
418
+ @profile.aggregate(@single_trace, @profile.traces[:request])
419
+ @profile.aggregate(@single_trace, @profile.traces[:other])
420
+
421
+ @profile.prune!(2)
422
+
423
+ assert_equal 1, @profile.traces[:request].size
424
+ assert_equal 1, @profile.traces[:other].size
425
+ assert_equal [], @profile.traces[:request][0].children
426
+ assert_equal [], @profile.traces[:other][0].children
427
+ end
428
+
429
+ def test_to_collector_array
430
+ @profile.instance_variable_set(:@start_time, 1350403938892.524)
431
+ @profile.instance_variable_set(:@stop_time, 1350403939904.375)
432
+ @profile.instance_variable_set(:@poll_count, 10)
433
+ @profile.instance_variable_set(:@sample_count, 2)
434
+
435
+ trace = ["thread_profiler.py:1:in `<module>'"]
436
+ 10.times { @profile.aggregate(trace, @profile.traces[:other]) }
437
+
438
+ trace = [
439
+ "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py:489:in `__bootstrap'",
440
+ "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py:512:in `__bootstrap_inner'",
441
+ "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py:480:in `run'",
442
+ "thread_profiler.py:76:in `_profiler_loop'",
443
+ "thread_profiler.py:103:in `_run_profiler'",
444
+ "thread_profiler.py:165:in `collect_thread_stacks'"]
445
+ 10.times { @profile.aggregate(trace, @profile.traces[:agent]) }
446
+
447
+ expected = [[
448
+ -1,
449
+ 1350403938892.524,
450
+ 1350403939904.375,
451
+ 10,
452
+ "eJy9klFPwjAUhf/LfW7WDQTUGBPUiYkGdAxelqXZRpGGrm1uS8xi/O924JQX\n9Un7dm77ndN7c19hlt7FCZxnWQZug7xYMYN6LSTHwDRA4KLWq53kl0CinEQh\nCUmW5zmBJH5axPPUk16MJ/E0/cGk0lLyyrGPS+uKamu943DQeX5HMtypz5In\nwv6vRCeZ1NoAGQ2PCDpvrOM1fRAlFtjQWyxq/qJxa+lj4zZaBeuuQpccrdDK\n0l4wolKU1OxftOoQLNTzIdL/EcjJafjnQYyVWjvrsDBMKNVOZBD1/jO27fPs\naBG+DoGr8fX9JJktpjftVry9A9unzGo=\n",
453
+ 2,
454
+ 0
455
+ ]]
456
+
457
+ marshaller = NewRelic::Agent::NewRelicService::JsonMarshaller.new
458
+ assert_equal expected, @profile.to_collector_array(marshaller.default_encoder)
459
+ end
460
+ end
461
+
462
+ class ThreadProfileNodeTest < Test::Unit::TestCase
463
+ SINGLE_LINE = "irb.rb:69:in `catch'"
464
+
465
+ def test_single_node_converts_to_array
466
+ line = "irb.rb:69:in `catch'"
467
+ node = NewRelic::Agent::ThreadProfile::Node.new(line)
468
+
469
+ assert_equal([
470
+ ["irb.rb", "catch", 69],
471
+ 0, 0,
472
+ []],
473
+ node.to_array)
474
+ end
475
+
476
+ def test_multiple_nodes_converts_to_array
477
+ line = "irb.rb:69:in `catch'"
478
+ child_line = "bacon.rb:42:in `yum'"
479
+ node = NewRelic::Agent::ThreadProfile::Node.new(line)
480
+ child = NewRelic::Agent::ThreadProfile::Node.new(child_line, node)
481
+
482
+ assert_equal([
483
+ ["irb.rb", "catch", 69],
484
+ 0, 0,
485
+ [
486
+ [
487
+ ['bacon.rb', 'yum', 42],
488
+ 0,0,
489
+ []
490
+ ]
491
+ ]],
492
+ node.to_array)
493
+ end
494
+
495
+ def test_add_child_twice
496
+ parent = NewRelic::Agent::ThreadProfile::Node.new(SINGLE_LINE)
497
+ child = NewRelic::Agent::ThreadProfile::Node.new(SINGLE_LINE)
498
+
499
+ parent.add_child(child)
500
+ parent.add_child(child)
501
+
502
+ assert_equal 1, parent.children.size
503
+ end
504
+
505
+ def test_prune_keeps_children
506
+ parent = NewRelic::Agent::ThreadProfile::Node.new(SINGLE_LINE)
507
+ child = NewRelic::Agent::ThreadProfile::Node.new(SINGLE_LINE, parent)
508
+
509
+ parent.prune!
510
+
511
+ assert_equal [child], parent.children
512
+ end
513
+
514
+ def test_prune_removes_children
515
+ parent = NewRelic::Agent::ThreadProfile::Node.new(SINGLE_LINE)
516
+ child = NewRelic::Agent::ThreadProfile::Node.new(SINGLE_LINE, parent)
517
+
518
+ child.to_prune = true
519
+ parent.prune!
520
+
521
+ assert_equal [], parent.children
522
+ end
523
+
524
+ def test_prune_removes_grandchildren
525
+ parent = NewRelic::Agent::ThreadProfile::Node.new(SINGLE_LINE)
526
+ child = NewRelic::Agent::ThreadProfile::Node.new(SINGLE_LINE, parent)
527
+ grandchild = NewRelic::Agent::ThreadProfile::Node.new(SINGLE_LINE, child)
528
+
529
+ grandchild.to_prune = true
530
+ parent.prune!
531
+
532
+ assert_equal [child], parent.children
533
+ assert_equal [], child.children
534
+ end
535
+
536
+ end
537
+ end