sundawg_newrelic_rpm 3.5.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (409) hide show
  1. data/.gitignore +22 -0
  2. data/.project +23 -0
  3. data/.travis.yml +9 -0
  4. data/CHANGELOG +969 -0
  5. data/GUIDELINES_FOR_CONTRIBUTING.md +76 -0
  6. data/Gemfile +20 -0
  7. data/LICENSE +87 -0
  8. data/README.md +195 -0
  9. data/Rakefile +58 -0
  10. data/bin/mongrel_rpm +33 -0
  11. data/bin/newrelic +13 -0
  12. data/bin/newrelic_cmd +5 -0
  13. data/cert/cacert.pem +118 -0
  14. data/cert/oldsite.pem +28 -0
  15. data/cert/site.pem +27 -0
  16. data/config.dot +290 -0
  17. data/config/database.yml +5 -0
  18. data/gem-public_cert.pem +20 -0
  19. data/init.rb +31 -0
  20. data/install.rb +9 -0
  21. data/lib/conditional_vendored_dependency_detection.rb +3 -0
  22. data/lib/conditional_vendored_metric_parser.rb +5 -0
  23. data/lib/new_relic/agent.rb +488 -0
  24. data/lib/new_relic/agent/agent.rb +1069 -0
  25. data/lib/new_relic/agent/agent_logger.rb +173 -0
  26. data/lib/new_relic/agent/audit_logger.rb +72 -0
  27. data/lib/new_relic/agent/beacon_configuration.rb +107 -0
  28. data/lib/new_relic/agent/browser_monitoring.rb +195 -0
  29. data/lib/new_relic/agent/busy_calculator.rb +112 -0
  30. data/lib/new_relic/agent/chained_call.rb +13 -0
  31. data/lib/new_relic/agent/configuration.rb +74 -0
  32. data/lib/new_relic/agent/configuration/defaults.rb +132 -0
  33. data/lib/new_relic/agent/configuration/environment_source.rb +49 -0
  34. data/lib/new_relic/agent/configuration/manager.rb +148 -0
  35. data/lib/new_relic/agent/configuration/mask_defaults.rb +11 -0
  36. data/lib/new_relic/agent/configuration/server_source.rb +31 -0
  37. data/lib/new_relic/agent/configuration/yaml_source.rb +67 -0
  38. data/lib/new_relic/agent/cross_app_monitor.rb +239 -0
  39. data/lib/new_relic/agent/cross_app_tracing.rb +281 -0
  40. data/lib/new_relic/agent/database.rb +254 -0
  41. data/lib/new_relic/agent/error_collector.rb +266 -0
  42. data/lib/new_relic/agent/event_listener.rb +43 -0
  43. data/lib/new_relic/agent/instrumentation.rb +9 -0
  44. data/lib/new_relic/agent/instrumentation/active_merchant.rb +29 -0
  45. data/lib/new_relic/agent/instrumentation/active_record.rb +134 -0
  46. data/lib/new_relic/agent/instrumentation/acts_as_solr.rb +68 -0
  47. data/lib/new_relic/agent/instrumentation/authlogic.rb +19 -0
  48. data/lib/new_relic/agent/instrumentation/browser_monitoring_timings.rb +51 -0
  49. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +485 -0
  50. data/lib/new_relic/agent/instrumentation/data_mapper.rb +230 -0
  51. data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +52 -0
  52. data/lib/new_relic/agent/instrumentation/memcache.rb +80 -0
  53. data/lib/new_relic/agent/instrumentation/merb/controller.rb +41 -0
  54. data/lib/new_relic/agent/instrumentation/merb/errors.rb +29 -0
  55. data/lib/new_relic/agent/instrumentation/metric_frame.rb +356 -0
  56. data/lib/new_relic/agent/instrumentation/metric_frame/pop.rb +80 -0
  57. data/lib/new_relic/agent/instrumentation/net.rb +31 -0
  58. data/lib/new_relic/agent/instrumentation/passenger_instrumentation.rb +23 -0
  59. data/lib/new_relic/agent/instrumentation/queue_time.rb +68 -0
  60. data/lib/new_relic/agent/instrumentation/rack.rb +98 -0
  61. data/lib/new_relic/agent/instrumentation/rails/action_controller.rb +114 -0
  62. data/lib/new_relic/agent/instrumentation/rails/action_web_service.rb +42 -0
  63. data/lib/new_relic/agent/instrumentation/rails/errors.rb +42 -0
  64. data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +180 -0
  65. data/lib/new_relic/agent/instrumentation/rails3/errors.rb +41 -0
  66. data/lib/new_relic/agent/instrumentation/rails4/action_controller.rb +145 -0
  67. data/lib/new_relic/agent/instrumentation/rails4/errors.rb +45 -0
  68. data/lib/new_relic/agent/instrumentation/resque.rb +81 -0
  69. data/lib/new_relic/agent/instrumentation/sinatra.rb +107 -0
  70. data/lib/new_relic/agent/instrumentation/sunspot.rb +29 -0
  71. data/lib/new_relic/agent/instrumentation/unicorn_instrumentation.rb +22 -0
  72. data/lib/new_relic/agent/method_tracer.rb +530 -0
  73. data/lib/new_relic/agent/new_relic_service.rb +513 -0
  74. data/lib/new_relic/agent/pipe_channel_manager.rb +175 -0
  75. data/lib/new_relic/agent/pipe_service.rb +63 -0
  76. data/lib/new_relic/agent/rules_engine.rb +72 -0
  77. data/lib/new_relic/agent/sampler.rb +50 -0
  78. data/lib/new_relic/agent/samplers/cpu_sampler.rb +58 -0
  79. data/lib/new_relic/agent/samplers/delayed_job_sampler.rb +86 -0
  80. data/lib/new_relic/agent/samplers/memory_sampler.rb +141 -0
  81. data/lib/new_relic/agent/samplers/object_sampler.rb +26 -0
  82. data/lib/new_relic/agent/shim_agent.rb +28 -0
  83. data/lib/new_relic/agent/sql_sampler.rb +251 -0
  84. data/lib/new_relic/agent/stats.rb +149 -0
  85. data/lib/new_relic/agent/stats_engine.rb +30 -0
  86. data/lib/new_relic/agent/stats_engine/gc_profiler.rb +116 -0
  87. data/lib/new_relic/agent/stats_engine/metric_stats.rb +161 -0
  88. data/lib/new_relic/agent/stats_engine/samplers.rb +97 -0
  89. data/lib/new_relic/agent/stats_engine/stats_hash.rb +58 -0
  90. data/lib/new_relic/agent/stats_engine/transactions.rb +145 -0
  91. data/lib/new_relic/agent/thread.rb +32 -0
  92. data/lib/new_relic/agent/thread_profiler.rb +319 -0
  93. data/lib/new_relic/agent/transaction_info.rb +119 -0
  94. data/lib/new_relic/agent/transaction_sample_builder.rb +126 -0
  95. data/lib/new_relic/agent/transaction_sampler.rb +459 -0
  96. data/lib/new_relic/agent/worker_loop.rb +96 -0
  97. data/lib/new_relic/coerce.rb +37 -0
  98. data/lib/new_relic/collection_helper.rb +77 -0
  99. data/lib/new_relic/command.rb +85 -0
  100. data/lib/new_relic/commands/deployments.rb +114 -0
  101. data/lib/new_relic/commands/install.rb +80 -0
  102. data/lib/new_relic/control.rb +44 -0
  103. data/lib/new_relic/control/class_methods.rb +58 -0
  104. data/lib/new_relic/control/frameworks.rb +10 -0
  105. data/lib/new_relic/control/frameworks/external.rb +16 -0
  106. data/lib/new_relic/control/frameworks/merb.rb +25 -0
  107. data/lib/new_relic/control/frameworks/rails.rb +173 -0
  108. data/lib/new_relic/control/frameworks/rails3.rb +71 -0
  109. data/lib/new_relic/control/frameworks/rails4.rb +23 -0
  110. data/lib/new_relic/control/frameworks/ruby.rb +21 -0
  111. data/lib/new_relic/control/frameworks/sinatra.rb +20 -0
  112. data/lib/new_relic/control/instance_methods.rb +145 -0
  113. data/lib/new_relic/control/instrumentation.rb +95 -0
  114. data/lib/new_relic/control/profiling.rb +25 -0
  115. data/lib/new_relic/control/server_methods.rb +80 -0
  116. data/lib/new_relic/delayed_job_injection.rb +51 -0
  117. data/lib/new_relic/helper.rb +66 -0
  118. data/lib/new_relic/language_support.rb +92 -0
  119. data/lib/new_relic/latest_changes.rb +31 -0
  120. data/lib/new_relic/local_environment.rb +385 -0
  121. data/lib/new_relic/merbtasks.rb +6 -0
  122. data/lib/new_relic/metric_data.rb +70 -0
  123. data/lib/new_relic/metric_spec.rb +80 -0
  124. data/lib/new_relic/metrics.rb +9 -0
  125. data/lib/new_relic/noticed_error.rb +59 -0
  126. data/lib/new_relic/okjson.rb +599 -0
  127. data/lib/new_relic/rack.rb +4 -0
  128. data/lib/new_relic/rack/agent_hooks.rb +20 -0
  129. data/lib/new_relic/rack/browser_monitoring.rb +85 -0
  130. data/lib/new_relic/rack/developer_mode.rb +271 -0
  131. data/lib/new_relic/rack/error_collector.rb +66 -0
  132. data/lib/new_relic/recipes.rb +99 -0
  133. data/lib/new_relic/timer_lib.rb +27 -0
  134. data/lib/new_relic/transaction_analysis.rb +77 -0
  135. data/lib/new_relic/transaction_analysis/segment_summary.rb +49 -0
  136. data/lib/new_relic/transaction_sample.rb +272 -0
  137. data/lib/new_relic/transaction_sample/composite_segment.rb +27 -0
  138. data/lib/new_relic/transaction_sample/fake_segment.rb +9 -0
  139. data/lib/new_relic/transaction_sample/segment.rb +205 -0
  140. data/lib/new_relic/transaction_sample/summary_segment.rb +21 -0
  141. data/lib/new_relic/url_rule.rb +14 -0
  142. data/lib/new_relic/version.rb +66 -0
  143. data/lib/newrelic_rpm.rb +49 -0
  144. data/lib/tasks/all.rb +4 -0
  145. data/lib/tasks/install.rake +7 -0
  146. data/lib/tasks/tests.rake +17 -0
  147. data/newrelic.yml +227 -0
  148. data/newrelic_rpm.gemspec +50 -0
  149. data/recipes/newrelic.rb +6 -0
  150. data/test/active_record_fixtures.rb +77 -0
  151. data/test/config/newrelic.yml +49 -0
  152. data/test/config/test_control.rb +48 -0
  153. data/test/fixtures/proc_cpuinfo.txt +575 -0
  154. data/test/intentional_fail.rb +10 -0
  155. data/test/multiverse/.gitignore +11 -0
  156. data/test/multiverse/README.md +85 -0
  157. data/test/multiverse/lib/multiverse/color.rb +13 -0
  158. data/test/multiverse/lib/multiverse/envfile.rb +66 -0
  159. data/test/multiverse/lib/multiverse/environment.rb +16 -0
  160. data/test/multiverse/lib/multiverse/output_collector.rb +29 -0
  161. data/test/multiverse/lib/multiverse/runner.rb +44 -0
  162. data/test/multiverse/lib/multiverse/suite.rb +164 -0
  163. data/test/multiverse/script/run_one +3 -0
  164. data/test/multiverse/script/runner +9 -0
  165. data/test/multiverse/suites/active_record/Envfile +13 -0
  166. data/test/multiverse/suites/active_record/ar_method_aliasing.rb +94 -0
  167. data/test/multiverse/suites/active_record/config/newrelic.yml +22 -0
  168. data/test/multiverse/suites/active_record/encoding_test.rb +26 -0
  169. data/test/multiverse/suites/agent_only/Envfile +9 -0
  170. data/test/multiverse/suites/agent_only/audit_log_test.rb +97 -0
  171. data/test/multiverse/suites/agent_only/config/newrelic.yml +23 -0
  172. data/test/multiverse/suites/agent_only/cross_application_tracing_test.rb +56 -0
  173. data/test/multiverse/suites/agent_only/http_response_code_test.rb +53 -0
  174. data/test/multiverse/suites/agent_only/key_transactions_test.rb +66 -0
  175. data/test/multiverse/suites/agent_only/logging_test.rb +163 -0
  176. data/test/multiverse/suites/agent_only/marshaling_test.rb +96 -0
  177. data/test/multiverse/suites/agent_only/method_visibility_test.rb +98 -0
  178. data/test/multiverse/suites/agent_only/no_dns_resolv.rb +17 -0
  179. data/test/multiverse/suites/agent_only/pipe_manager_test.rb +33 -0
  180. data/test/multiverse/suites/agent_only/rename_rule_test.rb +57 -0
  181. data/test/multiverse/suites/agent_only/rum_instrumentation_test.rb +81 -0
  182. data/test/multiverse/suites/agent_only/service_timeout_test.rb +32 -0
  183. data/test/multiverse/suites/agent_only/ssl_test.rb +22 -0
  184. data/test/multiverse/suites/agent_only/start_up_test.rb +21 -0
  185. data/test/multiverse/suites/agent_only/test_trace_method_with_punctuation.rb +30 -0
  186. data/test/multiverse/suites/agent_only/test_trace_transaction_with_punctuation.rb +32 -0
  187. data/test/multiverse/suites/agent_only/testing_app.rb +17 -0
  188. data/test/multiverse/suites/agent_only/thread_profiling_test.rb +92 -0
  189. data/test/multiverse/suites/config_file_loading/Envfile +7 -0
  190. data/test/multiverse/suites/config_file_loading/config_file_loading_test.rb +106 -0
  191. data/test/multiverse/suites/datamapper/Envfile +8 -0
  192. data/test/multiverse/suites/datamapper/config/newrelic.yml +22 -0
  193. data/test/multiverse/suites/datamapper/encoding_test.rb +36 -0
  194. data/test/multiverse/suites/rails/Envfile +18 -0
  195. data/test/multiverse/suites/rails/app.rb +49 -0
  196. data/test/multiverse/suites/rails/app/views/foos/_foo.html.haml +1 -0
  197. data/test/multiverse/suites/rails/app/views/views/_a_partial.html.erb +1 -0
  198. data/test/multiverse/suites/rails/app/views/views/_mid_partial.html.erb +1 -0
  199. data/test/multiverse/suites/rails/app/views/views/_top_partial.html.erb +3 -0
  200. data/test/multiverse/suites/rails/app/views/views/deep_partial.html.erb +3 -0
  201. data/test/multiverse/suites/rails/app/views/views/haml_view.html.haml +6 -0
  202. data/test/multiverse/suites/rails/app/views/views/index.html.erb +4 -0
  203. data/test/multiverse/suites/rails/config/newrelic.yml +32 -0
  204. data/test/multiverse/suites/rails/error_tracing_test.rb +211 -0
  205. data/test/multiverse/suites/rails/gc_instrumentation_test.rb +79 -0
  206. data/test/multiverse/suites/rails/queue_time_test.rb +55 -0
  207. data/test/multiverse/suites/rails/view_instrumentation_test.rb +205 -0
  208. data/test/multiverse/suites/resque/Envfile +24 -0
  209. data/test/multiverse/suites/resque/Rakefile +8 -0
  210. data/test/multiverse/suites/resque/config/newrelic.yml +22 -0
  211. data/test/multiverse/suites/resque/instrumentation_test.rb +151 -0
  212. data/test/multiverse/suites/resque/resque_setup.rb +15 -0
  213. data/test/multiverse/suites/sinatra/Envfile +15 -0
  214. data/test/multiverse/suites/sinatra/config/newrelic.yml +24 -0
  215. data/test/multiverse/suites/sinatra/sinatra_error_tracing_test.rb +38 -0
  216. data/test/multiverse/suites/sinatra/sinatra_metric_explosion_test.rb +77 -0
  217. data/test/multiverse/suites/sinatra/sinatra_routes_test.rb +46 -0
  218. data/test/multiverse/suites/sinatra/sinatra_test.rb +139 -0
  219. data/test/multiverse/test/multiverse_test.rb +55 -0
  220. data/test/multiverse/test/suite_examples/one/a/Envfile +3 -0
  221. data/test/multiverse/test/suite_examples/one/a/a_test.rb +11 -0
  222. data/test/multiverse/test/suite_examples/one/a/config/newrelic.yml +24 -0
  223. data/test/multiverse/test/suite_examples/one/b/Envfile +3 -0
  224. data/test/multiverse/test/suite_examples/one/b/b_test.rb +11 -0
  225. data/test/multiverse/test/suite_examples/one/b/config/newrelic.yml +24 -0
  226. data/test/multiverse/test/suite_examples/three/a/Envfile +2 -0
  227. data/test/multiverse/test/suite_examples/three/a/fail_test.rb +6 -0
  228. data/test/multiverse/test/suite_examples/three/b/Envfile +2 -0
  229. data/test/multiverse/test/suite_examples/three/b/win_test.rb +6 -0
  230. data/test/multiverse/test/suite_examples/two/a/Envfile +1 -0
  231. data/test/multiverse/test/suite_examples/two/a/fail_test.rb +6 -0
  232. data/test/new_relic/agent/agent/connect_test.rb +295 -0
  233. data/test/new_relic/agent/agent/start_test.rb +205 -0
  234. data/test/new_relic/agent/agent/start_worker_thread_test.rb +88 -0
  235. data/test/new_relic/agent/agent_logger_test.rb +153 -0
  236. data/test/new_relic/agent/agent_test.rb +301 -0
  237. data/test/new_relic/agent/agent_test_controller.rb +77 -0
  238. data/test/new_relic/agent/agent_test_controller_test.rb +381 -0
  239. data/test/new_relic/agent/apdex_from_server_test.rb +9 -0
  240. data/test/new_relic/agent/audit_logger_test.rb +105 -0
  241. data/test/new_relic/agent/beacon_configuration_test.rb +107 -0
  242. data/test/new_relic/agent/browser_monitoring_test.rb +395 -0
  243. data/test/new_relic/agent/busy_calculator_test.rb +96 -0
  244. data/test/new_relic/agent/configuration/environment_source_test.rb +79 -0
  245. data/test/new_relic/agent/configuration/manager_test.rb +232 -0
  246. data/test/new_relic/agent/configuration/server_source_test.rb +50 -0
  247. data/test/new_relic/agent/configuration/yaml_source_test.rb +85 -0
  248. data/test/new_relic/agent/cross_app_monitor_test.rb +237 -0
  249. data/test/new_relic/agent/database_test.rb +194 -0
  250. data/test/new_relic/agent/error_collector/notice_error_test.rb +268 -0
  251. data/test/new_relic/agent/error_collector_test.rb +246 -0
  252. data/test/new_relic/agent/event_listener_test.rb +67 -0
  253. data/test/new_relic/agent/instrumentation/active_record_instrumentation_test.rb +606 -0
  254. data/test/new_relic/agent/instrumentation/browser_monitoring_timings_test.rb +66 -0
  255. data/test/new_relic/agent/instrumentation/controller_instrumentation_test.rb +107 -0
  256. data/test/new_relic/agent/instrumentation/instrumentation_test.rb +11 -0
  257. data/test/new_relic/agent/instrumentation/metric_frame/pop_test.rb +171 -0
  258. data/test/new_relic/agent/instrumentation/metric_frame_test.rb +151 -0
  259. data/test/new_relic/agent/instrumentation/net_instrumentation_test.rb +461 -0
  260. data/test/new_relic/agent/instrumentation/queue_time_test.rb +97 -0
  261. data/test/new_relic/agent/instrumentation/rack_test.rb +35 -0
  262. data/test/new_relic/agent/instrumentation/sinatra_test.rb +25 -0
  263. data/test/new_relic/agent/instrumentation/task_instrumentation_test.rb +182 -0
  264. data/test/new_relic/agent/memcache_instrumentation_test.rb +143 -0
  265. data/test/new_relic/agent/method_tracer/class_methods/add_method_tracer_test.rb +158 -0
  266. data/test/new_relic/agent/method_tracer/instance_methods/trace_execution_scoped_test.rb +222 -0
  267. data/test/new_relic/agent/method_tracer_test.rb +389 -0
  268. data/test/new_relic/agent/mock_scope_listener.rb +26 -0
  269. data/test/new_relic/agent/new_relic_service_test.rb +571 -0
  270. data/test/new_relic/agent/pipe_channel_manager_test.rb +131 -0
  271. data/test/new_relic/agent/pipe_service_test.rb +133 -0
  272. data/test/new_relic/agent/rpm_agent_test.rb +115 -0
  273. data/test/new_relic/agent/rules_engine_test.rb +82 -0
  274. data/test/new_relic/agent/sampler_test.rb +19 -0
  275. data/test/new_relic/agent/shim_agent_test.rb +16 -0
  276. data/test/new_relic/agent/sql_sampler_test.rb +244 -0
  277. data/test/new_relic/agent/stats_engine/gc_profiler_test.rb +85 -0
  278. data/test/new_relic/agent/stats_engine/metric_stats_test.rb +180 -0
  279. data/test/new_relic/agent/stats_engine/samplers_test.rb +99 -0
  280. data/test/new_relic/agent/stats_engine_test.rb +184 -0
  281. data/test/new_relic/agent/stats_hash_test.rb +93 -0
  282. data/test/new_relic/agent/stats_test.rb +197 -0
  283. data/test/new_relic/agent/thread_profiler_test.rb +582 -0
  284. data/test/new_relic/agent/thread_test.rb +89 -0
  285. data/test/new_relic/agent/threaded_test.rb +65 -0
  286. data/test/new_relic/agent/transaction_info_test.rb +106 -0
  287. data/test/new_relic/agent/transaction_sample_builder_test.rb +227 -0
  288. data/test/new_relic/agent/transaction_sampler_test.rb +968 -0
  289. data/test/new_relic/agent/worker_loop_test.rb +84 -0
  290. data/test/new_relic/agent_test.rb +296 -0
  291. data/test/new_relic/coerce_test.rb +65 -0
  292. data/test/new_relic/collection_helper_test.rb +148 -0
  293. data/test/new_relic/command/deployments_test.rb +84 -0
  294. data/test/new_relic/control/class_methods_test.rb +44 -0
  295. data/test/new_relic/control/frameworks/rails_test.rb +26 -0
  296. data/test/new_relic/control_test.rb +194 -0
  297. data/test/new_relic/delayed_job_injection_test.rb +21 -0
  298. data/test/new_relic/dispatcher_test.rb +54 -0
  299. data/test/new_relic/fake_collector.rb +389 -0
  300. data/test/new_relic/framework_test.rb +53 -0
  301. data/test/new_relic/helper_test.rb +24 -0
  302. data/test/new_relic/load_test.rb +13 -0
  303. data/test/new_relic/local_environment_test.rb +85 -0
  304. data/test/new_relic/metric_data_test.rb +183 -0
  305. data/test/new_relic/metric_parser/metric_parser_test.rb +11 -0
  306. data/test/new_relic/metric_spec_test.rb +95 -0
  307. data/test/new_relic/noticed_error_test.rb +32 -0
  308. data/test/new_relic/rack/agent_hooks_test.rb +30 -0
  309. data/test/new_relic/rack/all_test.rb +11 -0
  310. data/test/new_relic/rack/browser_monitoring_test.rb +152 -0
  311. data/test/new_relic/rack/developer_mode_helper_test.rb +141 -0
  312. data/test/new_relic/rack/developer_mode_test.rb +80 -0
  313. data/test/new_relic/rack/error_collector_test.rb +90 -0
  314. data/test/new_relic/transaction_analysis/segment_summary_test.rb +91 -0
  315. data/test/new_relic/transaction_analysis_test.rb +121 -0
  316. data/test/new_relic/transaction_sample/composite_segment_test.rb +35 -0
  317. data/test/new_relic/transaction_sample/fake_segment_test.rb +17 -0
  318. data/test/new_relic/transaction_sample/segment_test.rb +415 -0
  319. data/test/new_relic/transaction_sample/summary_segment_test.rb +31 -0
  320. data/test/new_relic/transaction_sample_subtest_test.rb +56 -0
  321. data/test/new_relic/transaction_sample_test.rb +250 -0
  322. data/test/new_relic/version_number_test.rb +97 -0
  323. data/test/script/build_test_gem.sh +57 -0
  324. data/test/script/ci.sh +168 -0
  325. data/test/script/ci_agent-tests_runner.sh +82 -0
  326. data/test/script/ci_bench.sh +52 -0
  327. data/test/script/ci_multiverse_runner.sh +63 -0
  328. data/test/test_contexts.rb +30 -0
  329. data/test/test_helper.rb +240 -0
  330. data/ui/helpers/developer_mode_helper.rb +367 -0
  331. data/ui/helpers/google_pie_chart.rb +49 -0
  332. data/ui/views/layouts/newrelic_default.rhtml +48 -0
  333. data/ui/views/newrelic/_explain_plans.rhtml +27 -0
  334. data/ui/views/newrelic/_sample.rhtml +20 -0
  335. data/ui/views/newrelic/_segment.rhtml +28 -0
  336. data/ui/views/newrelic/_segment_limit_message.rhtml +1 -0
  337. data/ui/views/newrelic/_segment_row.rhtml +12 -0
  338. data/ui/views/newrelic/_show_sample_detail.rhtml +24 -0
  339. data/ui/views/newrelic/_show_sample_sql.rhtml +24 -0
  340. data/ui/views/newrelic/_show_sample_summary.rhtml +3 -0
  341. data/ui/views/newrelic/_sql_row.rhtml +16 -0
  342. data/ui/views/newrelic/_stack_trace.rhtml +15 -0
  343. data/ui/views/newrelic/_table.rhtml +12 -0
  344. data/ui/views/newrelic/explain_sql.rhtml +43 -0
  345. data/ui/views/newrelic/file/images/arrow-close.png +0 -0
  346. data/ui/views/newrelic/file/images/arrow-open.png +0 -0
  347. data/ui/views/newrelic/file/images/blue_bar.gif +0 -0
  348. data/ui/views/newrelic/file/images/file_icon.png +0 -0
  349. data/ui/views/newrelic/file/images/gray_bar.gif +0 -0
  350. data/ui/views/newrelic/file/images/new-relic-rpm-desktop.gif +0 -0
  351. data/ui/views/newrelic/file/images/new_relic_rpm_desktop.gif +0 -0
  352. data/ui/views/newrelic/file/images/textmate.png +0 -0
  353. data/ui/views/newrelic/file/javascript/jquery-1.4.2.js +6240 -0
  354. data/ui/views/newrelic/file/javascript/transaction_sample.js +120 -0
  355. data/ui/views/newrelic/file/stylesheets/style.css +490 -0
  356. data/ui/views/newrelic/index.rhtml +71 -0
  357. data/ui/views/newrelic/sample_not_found.rhtml +2 -0
  358. data/ui/views/newrelic/show_sample.rhtml +80 -0
  359. data/ui/views/newrelic/show_source.rhtml +3 -0
  360. data/ui/views/newrelic/threads.rhtml +45 -0
  361. data/vendor/gems/dependency_detection-0.0.1.build/LICENSE +5 -0
  362. data/vendor/gems/dependency_detection-0.0.1.build/lib/dependency_detection.rb +67 -0
  363. data/vendor/gems/dependency_detection-0.0.1.build/lib/dependency_detection/version.rb +3 -0
  364. data/vendor/gems/metric_parser-0.1.0.pre1/.specification +116 -0
  365. data/vendor/gems/metric_parser-0.1.0.pre1/lib/metric_parser.rb +1 -0
  366. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser.rb +64 -0
  367. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/action_mailer.rb +14 -0
  368. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/active_merchant.rb +31 -0
  369. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/active_record.rb +33 -0
  370. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/apdex.rb +89 -0
  371. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/background_transaction.rb +7 -0
  372. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/client.rb +46 -0
  373. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/controller.rb +67 -0
  374. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/controller_cpu.rb +43 -0
  375. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/controller_ext.rb +17 -0
  376. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/database.rb +48 -0
  377. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/database_pool.rb +24 -0
  378. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/dot_net.rb +28 -0
  379. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/dot_net_parser.rb +17 -0
  380. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/errors.rb +11 -0
  381. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/external.rb +55 -0
  382. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/frontend.rb +40 -0
  383. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/gc.rb +20 -0
  384. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/hibernate_session.rb +7 -0
  385. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/java.rb +31 -0
  386. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/java_parser.rb +17 -0
  387. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/jsp.rb +34 -0
  388. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/jsp_tag.rb +7 -0
  389. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/mem_cache.rb +55 -0
  390. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/metric_parser.rb +135 -0
  391. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/orm.rb +27 -0
  392. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/other_transaction.rb +40 -0
  393. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/servlet.rb +7 -0
  394. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/servlet_context_listener.rb +7 -0
  395. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/servlet_filter.rb +7 -0
  396. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/servlet_init.rb +7 -0
  397. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/solr.rb +27 -0
  398. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/solr_request_handler.rb +15 -0
  399. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/spring.rb +54 -0
  400. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/spring_controller.rb +6 -0
  401. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/spring_view.rb +6 -0
  402. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/struts_action.rb +20 -0
  403. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/struts_result.rb +20 -0
  404. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/version.rb +5 -0
  405. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/view.rb +70 -0
  406. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/web_frontend.rb +18 -0
  407. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/web_service.rb +14 -0
  408. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/web_transaction.rb +133 -0
  409. metadata +494 -0
@@ -0,0 +1,1069 @@
1
+ require 'socket'
2
+ require 'net/https'
3
+ require 'net/http'
4
+ require 'logger'
5
+ require 'zlib'
6
+ require 'stringio'
7
+ require 'new_relic/agent/new_relic_service'
8
+ require 'new_relic/agent/pipe_service'
9
+ require 'new_relic/agent/configuration/manager'
10
+ require 'new_relic/agent/database'
11
+ require 'new_relic/agent/thread_profiler'
12
+ require 'new_relic/agent/event_listener'
13
+ require 'new_relic/agent/cross_app_monitor'
14
+
15
+ module NewRelic
16
+ module Agent
17
+
18
+ # The Agent is a singleton that is instantiated when the plugin is
19
+ # activated. It collects performance data from ruby applications
20
+ # in realtime as the application runs, and periodically sends that
21
+ # data to the NewRelic server.
22
+ class Agent
23
+ extend NewRelic::Agent::Configuration::Instance
24
+
25
+ def initialize
26
+ @launch_time = Time.now
27
+
28
+ @events = NewRelic::Agent::EventListener.new
29
+ @stats_engine = NewRelic::Agent::StatsEngine.new
30
+ @transaction_sampler = NewRelic::Agent::TransactionSampler.new
31
+ @sql_sampler = NewRelic::Agent::SqlSampler.new
32
+ @thread_profiler = NewRelic::Agent::ThreadProfiler.new
33
+ @cross_app_monitor = NewRelic::Agent::CrossAppMonitor.new(@events)
34
+ @error_collector = NewRelic::Agent::ErrorCollector.new
35
+ @transaction_rules = NewRelic::Agent::RulesEngine.new
36
+ @metric_rules = NewRelic::Agent::RulesEngine.new
37
+
38
+ @connect_state = :pending
39
+ @connect_attempts = 0
40
+
41
+ @last_harvest_time = Time.now
42
+ @obfuscator = lambda {|sql| NewRelic::Agent::Database.default_sql_obfuscator(sql) }
43
+ @forked = false
44
+
45
+ # FIXME: temporary work around for RUBY-839
46
+ if Agent.config[:monitor_mode]
47
+ @service = NewRelic::Agent::NewRelicService.new
48
+ end
49
+
50
+ txn_tracer_enabler = Proc.new do
51
+ if NewRelic::Agent.config[:'transaction_tracer.enabled'] ||
52
+ NewRelic::Agent.config[:developer_mode]
53
+ @stats_engine.transaction_sampler = @transaction_sampler
54
+ else
55
+ @stats_engine.transaction_sampler = nil
56
+ end
57
+ end
58
+ Agent.config.register_callback(:'transaction_tracer.enabled', &txn_tracer_enabler)
59
+ Agent.config.register_callback(:developer_mode, &txn_tracer_enabler)
60
+ end
61
+
62
+ # contains all the class-level methods for NewRelic::Agent::Agent
63
+ module ClassMethods
64
+ # Should only be called by NewRelic::Control - returns a
65
+ # memoized singleton instance of the agent, creating one if needed
66
+ def instance
67
+ @instance ||= self.new
68
+ end
69
+ end
70
+
71
+ # Holds all the methods defined on NewRelic::Agent::Agent
72
+ # instances
73
+ module InstanceMethods
74
+
75
+ # holds a proc that is used to obfuscate sql statements
76
+ attr_reader :obfuscator
77
+ # the statistics engine that holds all the timeslice data
78
+ attr_reader :stats_engine
79
+ # the transaction sampler that handles recording transactions
80
+ attr_reader :transaction_sampler
81
+ attr_reader :sql_sampler
82
+ # begins a thread profile session when instructed by agent commands
83
+ attr_reader :thread_profiler
84
+ # error collector is a simple collection of recorded errors
85
+ attr_reader :error_collector
86
+ # whether we should record raw, obfuscated, or no sql
87
+ attr_reader :record_sql
88
+ # a configuration for the Real User Monitoring system -
89
+ # handles things like static setup of the header for inclusion
90
+ # into pages
91
+ attr_reader :beacon_configuration
92
+ # cross application tracing ids and encoding
93
+ attr_reader :cross_process_id
94
+ attr_reader :cross_app_encoding_bytes
95
+ # service for communicating with collector
96
+ attr_accessor :service
97
+ # Global events dispatcher. This will provides our primary mechanism
98
+ # for agent-wide events, such as finishing configuration, error notification
99
+ # and request before/after from Rack.
100
+ attr_reader :events
101
+ # Transaction and metric renaming rules as provided by the
102
+ # collector on connect. The former are applied during txns,
103
+ # the latter during harvest.
104
+ attr_reader :transaction_rules
105
+ attr_reader :metric_rules
106
+
107
+ # Returns the length of the unsent errors array, if it exists,
108
+ # otherwise nil
109
+ def unsent_errors_size
110
+ @unsent_errors.length if @unsent_errors
111
+ end
112
+
113
+ # Returns the length of the traces array, if it exists,
114
+ # otherwise nil
115
+ def unsent_traces_size
116
+ @traces.length if @traces
117
+ end
118
+
119
+ # Initializes the unsent timeslice data hash, if needed, and
120
+ # returns the number of keys it contains
121
+ def unsent_timeslice_data
122
+ @unsent_timeslice_data ||= {}
123
+ @unsent_timeslice_data.keys.length
124
+ end
125
+
126
+ # fakes out a transaction that did not happen in this process
127
+ # by creating apdex, summary metrics, and recording statistics
128
+ # for the transaction
129
+ #
130
+ # This method is *deprecated* - it may be removed in future
131
+ # versions of the agent
132
+ def record_transaction(duration_seconds, options={})
133
+ is_error = options['is_error'] || options['error_message'] || options['exception']
134
+ metric = options['metric']
135
+ metric ||= options['uri'] # normalize this with url rules
136
+ raise "metric or uri arguments required" unless metric
137
+ metric_info = NewRelic::MetricParser::MetricParser.for_metric_named(metric)
138
+
139
+ if metric_info.is_web_transaction?
140
+ NewRelic::Agent::Instrumentation::MetricFrame.record_apdex(metric_info, duration_seconds, duration_seconds, is_error)
141
+ end
142
+ metrics = metric_info.summary_metrics
143
+
144
+ metrics << metric
145
+ metrics.each do |name|
146
+ stats = stats_engine.get_stats_no_scope(name)
147
+ stats.record_data_point(duration_seconds)
148
+ end
149
+
150
+ if is_error
151
+ if options['exception']
152
+ e = options['exception']
153
+ elsif options['error_message']
154
+ e = StandardError.new options['error_message']
155
+ else
156
+ e = StandardError.new 'Unknown Error'
157
+ end
158
+ error_collector.notice_error e, :uri => options['uri'], :metric => metric
159
+ end
160
+ # busy time ?
161
+ end
162
+
163
+ # This method should be called in a forked process after a fork.
164
+ # It assumes the parent process initialized the agent, but does
165
+ # not assume the agent started.
166
+ #
167
+ # The call is idempotent, but not re-entrant.
168
+ #
169
+ # * It clears any metrics carried over from the parent process
170
+ # * Restarts the sampler thread if necessary
171
+ # * Initiates a new agent run and worker loop unless that was done
172
+ # in the parent process and +:force_reconnect+ is not true
173
+ #
174
+ # Options:
175
+ # * <tt>:force_reconnect => true</tt> to force the spawned process to
176
+ # establish a new connection, such as when forking a long running process.
177
+ # The default is false--it will only connect to the server if the parent
178
+ # had not connected.
179
+ # * <tt>:keep_retrying => false</tt> if we try to initiate a new
180
+ # connection, this tells me to only try it once so this method returns
181
+ # quickly if there is some kind of latency with the server.
182
+ def after_fork(options={})
183
+ @forked = true
184
+ Agent.config.apply_config(NewRelic::Agent::Configuration::ManualSource.new(options), 1)
185
+
186
+ if channel_id = options[:report_to_channel]
187
+ @service = NewRelic::Agent::PipeService.new(channel_id)
188
+ if connected?
189
+ @connected_pid = $$
190
+ else
191
+ ::NewRelic::Agent.logger.debug("Child process #{$$} not reporting to non-connected parent.")
192
+ @service.shutdown(Time.now)
193
+ disconnect
194
+ end
195
+ end
196
+
197
+ return if !Agent.config[:agent_enabled] ||
198
+ !Agent.config[:monitor_mode] ||
199
+ disconnected? ||
200
+ @worker_thread && @worker_thread.alive?
201
+
202
+ ::NewRelic::Agent.logger.debug "Starting the worker thread in #{$$} after forking."
203
+
204
+ # Clear out stats that are left over from parent process
205
+ reset_stats
206
+
207
+ # Don't ever check to see if this is a spawner. If we're in a forked process
208
+ # I'm pretty sure we're not also forking new instances.
209
+ start_worker_thread(options)
210
+ @stats_engine.start_sampler_thread
211
+ end
212
+
213
+ def forked?
214
+ @forked
215
+ end
216
+
217
+ # True if we have initialized and completed 'start'
218
+ def started?
219
+ @started
220
+ end
221
+
222
+ # Attempt a graceful shutdown of the agent, running the worker
223
+ # loop if it exists and is running.
224
+ #
225
+ # Options:
226
+ # :force_send => (true/false) # force the agent to send data
227
+ def shutdown(options={})
228
+ run_loop_before_exit = Agent.config[:force_send]
229
+ return if not started?
230
+ if @worker_loop
231
+ @worker_loop.run_task if run_loop_before_exit
232
+ @worker_loop.stop
233
+ end
234
+
235
+ ::NewRelic::Agent.logger.info "Starting Agent shutdown"
236
+
237
+ # if litespeed, then ignore all future SIGUSR1 - it's
238
+ # litespeed trying to shut us down
239
+ if Agent.config[:dispatcher] == :litespeed
240
+ Signal.trap("SIGUSR1", "IGNORE")
241
+ Signal.trap("SIGTERM", "IGNORE")
242
+ end
243
+
244
+ begin
245
+ NewRelic::Agent.disable_all_tracing do
246
+ graceful_disconnect
247
+ end
248
+ rescue => e
249
+ ::NewRelic::Agent.logger.error e
250
+ end
251
+ NewRelic::Agent.config.remove_config do |config|
252
+ config.class == NewRelic::Agent::Configuration::ManualSource ||
253
+ config.class == NewRelic::Agent::Configuration::ServerSource
254
+ end
255
+ @started = nil
256
+ Control.reset
257
+ end
258
+
259
+ # Tells the statistics engine we are starting a new transaction
260
+ def start_transaction
261
+ @stats_engine.start_transaction
262
+ end
263
+
264
+ # Tells the statistics engine we are ending a transaction
265
+ def end_transaction
266
+ @stats_engine.end_transaction
267
+ end
268
+
269
+ # Sets a thread local variable as to whether we should or
270
+ # should not record sql in the current thread. Returns the
271
+ # previous value, if there is one
272
+ def set_record_sql(should_record)
273
+ prev = Thread::current[:record_sql]
274
+ Thread::current[:record_sql] = should_record
275
+ prev.nil? || prev
276
+ end
277
+
278
+ # Sets a thread local variable as to whether we should or
279
+ # should not record transaction traces in the current
280
+ # thread. Returns the previous value, if there is one
281
+ def set_record_tt(should_record)
282
+ prev = Thread::current[:record_tt]
283
+ Thread::current[:record_tt] = should_record
284
+ prev.nil? || prev
285
+ end
286
+
287
+ # Push flag indicating whether we should be tracing in this
288
+ # thread. This uses a stack which allows us to disable tracing
289
+ # children of a transaction without affecting the tracing of
290
+ # the whole transaction
291
+ def push_trace_execution_flag(should_trace=false)
292
+ value = Thread.current[:newrelic_untraced]
293
+ if (value.nil?)
294
+ Thread.current[:newrelic_untraced] = []
295
+ end
296
+
297
+ Thread.current[:newrelic_untraced] << should_trace
298
+ end
299
+
300
+ # Pop the current trace execution status. Restore trace execution status
301
+ # to what it was before we pushed the current flag.
302
+ def pop_trace_execution_flag
303
+ Thread.current[:newrelic_untraced].pop if Thread.current[:newrelic_untraced]
304
+ end
305
+
306
+ # Herein lies the corpse of the former 'start' method. May
307
+ # its unmatched flog score rest in pieces.
308
+ module Start
309
+ # Check whether we have already started, which is an error condition
310
+ def already_started?
311
+ if started?
312
+ ::NewRelic::Agent.logger.error("Agent Started Already!")
313
+ true
314
+ end
315
+ end
316
+
317
+ # The agent is disabled when it is not force enabled by the
318
+ # 'agent_enabled' option (e.g. in a manual start), or
319
+ # enabled normally through the configuration file
320
+ def disabled?
321
+ !Agent.config[:agent_enabled]
322
+ end
323
+
324
+ # Log startup information that we almost always want to know
325
+ def log_startup
326
+ log_environment
327
+ log_dispatcher
328
+ log_app_names
329
+ end
330
+
331
+ # Log the environment the app thinks it's running in.
332
+ # Useful in debugging, as this is the key for config YAML lookups.
333
+ def log_environment
334
+ ::NewRelic::Agent.logger.info "Environment: #{NewRelic::Control.instance.env}"
335
+ end
336
+
337
+ # Logs the dispatcher to the log file to assist with
338
+ # debugging. When no debugger is present, logs this fact to
339
+ # assist with proper dispatcher detection
340
+ def log_dispatcher
341
+ dispatcher_name = Agent.config[:dispatcher].to_s
342
+ return if log_if(dispatcher_name.empty?, :warn, "No dispatcher detected.")
343
+ ::NewRelic::Agent.logger.info "Dispatcher: #{dispatcher_name}"
344
+ end
345
+
346
+ # Logs the configured application names
347
+ def log_app_names
348
+ names = Agent.config.app_names
349
+ if names.respond_to?(:any?) && names.any?
350
+ ::NewRelic::Agent.logger.info "Application: #{names.join(", ")}"
351
+ else
352
+ ::NewRelic::Agent.logger.error 'Unable to determine application name. Please set the application name in your newrelic.yml or in a NEW_RELIC_APP_NAME environment variable.'
353
+ end
354
+ end
355
+
356
+ # Connecting in the foreground blocks further startup of the
357
+ # agent until we have a connection - useful in cases where
358
+ # you're trying to log a very-short-running process and want
359
+ # to get statistics from before a server connection
360
+ # (typically 20 seconds) exists
361
+ def connect_in_foreground
362
+ NewRelic::Agent.disable_all_tracing { connect(:keep_retrying => false) }
363
+ end
364
+
365
+ # If we're using sinatra, old versions run in an at_exit
366
+ # block so we should probably know that
367
+ def using_sinatra?
368
+ defined?(Sinatra::Application)
369
+ end
370
+
371
+ # we should not set an at_exit block if people are using
372
+ # these as they don't do standard at_exit behavior per MRI/YARV
373
+ def weird_ruby?
374
+ NewRelic::LanguageSupport.using_engine?('rbx') ||
375
+ NewRelic::LanguageSupport.using_engine?('jruby') ||
376
+ using_sinatra?
377
+ end
378
+
379
+ # Installs our exit handler, which exploits the weird
380
+ # behavior of at_exit blocks to make sure it runs last, by
381
+ # doing an at_exit within an at_exit block.
382
+ def install_exit_handler
383
+ if Agent.config[:send_data_on_exit] && !weird_ruby?
384
+ at_exit do
385
+ # Workaround for MRI 1.9 bug that loses exit codes in at_exit blocks.
386
+ # This is necessary to get correct exit codes for the agent's
387
+ # test suites.
388
+ # http://bugs.ruby-lang.org/issues/5218
389
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE == "ruby" && RUBY_VERSION.match(/^1\.9/)
390
+ exit_status = $!.status if $!.is_a?(SystemExit)
391
+ shutdown
392
+ exit exit_status if exit_status
393
+ else
394
+ shutdown
395
+ end
396
+ end
397
+ end
398
+ end
399
+
400
+ # Classy logging of the agent version and the current pid,
401
+ # so we can disambiguate processes in the log file and make
402
+ # sure they're running a reasonable version
403
+ def log_version_and_pid
404
+ ::NewRelic::Agent.logger.debug "New Relic Ruby Agent #{NewRelic::VERSION::STRING} Initialized: pid = #{$$}"
405
+ end
406
+
407
+ # A helper method that logs a condition if that condition is
408
+ # true. Mentally cleaner than having every method set a
409
+ # local and log if it is true
410
+ def log_if(boolean, level, message)
411
+ ::NewRelic::Agent.logger.send(level, message) if boolean
412
+ boolean
413
+ end
414
+
415
+ # A helper method that logs a condition unless that
416
+ # condition is true. Mentally cleaner than having every
417
+ # method set a local and log unless it is true
418
+ def log_unless(boolean, level, message)
419
+ ::NewRelic::Agent.logger.send(level, message) unless boolean
420
+ boolean
421
+ end
422
+
423
+ # Warn the user if they have configured their agent not to
424
+ # send data, that way we can see this clearly in the log file
425
+ def monitoring?
426
+ log_unless(Agent.config[:monitor_mode], :warn,
427
+ "Agent configured not to send data in this environment.")
428
+ end
429
+
430
+ # Tell the user when the license key is missing so they can
431
+ # fix it by adding it to the file
432
+ def has_license_key?
433
+ log_unless(Agent.config[:license_key], :warn,
434
+ "No license key found in newrelic.yml config. " +
435
+ "This often means your newrelic.yml is missing a section for the running environment '#{NewRelic::Control.instance.env}'")
436
+ end
437
+
438
+ # A correct license key exists and is of the proper length
439
+ def has_correct_license_key?
440
+ has_license_key? && correct_license_length
441
+ end
442
+
443
+ # A license key is an arbitrary 40 character string,
444
+ # usually looks something like a SHA1 hash
445
+ def correct_license_length
446
+ key = Agent.config[:license_key]
447
+ log_unless((key.length == 40), :error, "Invalid license key: #{key}")
448
+ end
449
+
450
+ # If we're using a dispatcher that forks before serving
451
+ # requests, we need to wait until the children are forked
452
+ # before connecting, otherwise the parent process sends odd data
453
+ def using_forking_dispatcher?
454
+ log_if([:passenger, :unicorn].include?(Agent.config[:dispatcher]),
455
+ :info, "Connecting workers after forking.")
456
+ end
457
+
458
+ # Return true if we're using resque and it hasn't had a chance to (potentially)
459
+ # daemonize itself. This avoids hanging when there's a Thread started
460
+ # before Resque calls Process.daemon (Jira RUBY-857)
461
+ def defer_for_resque?
462
+ NewRelic::Agent.config[:dispatcher] == :resque &&
463
+ !NewRelic::Agent::PipeChannelManager.listener.started?
464
+ end
465
+
466
+ # Sanity-check the agent configuration and start the agent,
467
+ # setting up the worker thread and the exit handler to shut
468
+ # down the agent
469
+ def check_config_and_start_agent
470
+ return unless monitoring? && has_correct_license_key?
471
+ return if using_forking_dispatcher?
472
+ connect_in_foreground if Agent.config[:sync_startup]
473
+ start_worker_thread
474
+ install_exit_handler
475
+ end
476
+ end
477
+
478
+ include Start
479
+
480
+ # Logs a bunch of data and starts the agent, if needed
481
+ def start
482
+ return if already_started? || disabled?
483
+
484
+ if defer_for_resque?
485
+ ::NewRelic::Agent.logger.debug "Deferring startup for Resque in case it daemonizes"
486
+ return
487
+ end
488
+
489
+ @started = true
490
+ @local_host = determine_host
491
+ log_startup
492
+ check_config_and_start_agent
493
+ log_version_and_pid
494
+ end
495
+
496
+ # Clear out the metric data, errors, and transaction traces,
497
+ # making sure the agent is in a fresh state
498
+ def reset_stats
499
+ @stats_engine.reset_stats
500
+ @unsent_errors = []
501
+ @traces = nil
502
+ @unsent_timeslice_data = {}
503
+ @last_harvest_time = Time.now
504
+ @launch_time = Time.now
505
+ end
506
+
507
+ private
508
+
509
+ # All of this module used to be contained in the
510
+ # start_worker_thread method - this is an artifact of
511
+ # refactoring and can be moved, renamed, etc at will
512
+ module StartWorkerThread
513
+ # logs info about the worker loop so users can see when the
514
+ # agent actually begins running in the background
515
+ def log_worker_loop_start
516
+ ::NewRelic::Agent.logger.debug "Reporting performance data every #{Agent.config[:data_report_period]} seconds."
517
+ ::NewRelic::Agent.logger.debug "Running worker loop"
518
+ end
519
+
520
+ # Creates the worker loop and loads it with the instructions
521
+ # it should run every @report_period seconds
522
+ def create_and_run_worker_loop
523
+ @worker_loop = WorkerLoop.new
524
+ @worker_loop.run(Agent.config[:data_report_period]) do
525
+ transmit_data
526
+ end
527
+ end
528
+
529
+ # Handles the case where the server tells us to restart -
530
+ # this clears the data, clears connection attempts, and
531
+ # waits a while to reconnect.
532
+ def handle_force_restart(error)
533
+ ::NewRelic::Agent.logger.debug error.message
534
+ reset_stats
535
+ @service.reset_metric_id_cache if @service
536
+ @connect_state = :pending
537
+ sleep 30
538
+ end
539
+
540
+ # when a disconnect is requested, stop the current thread, which
541
+ # is the worker thread that gathers data and talks to the
542
+ # server.
543
+ def handle_force_disconnect(error)
544
+ ::NewRelic::Agent.logger.warn "New Relic forced this agent to disconnect (#{error.message})"
545
+ disconnect
546
+ end
547
+
548
+ # there is a problem with connecting to the server, so we
549
+ # stop trying to connect and shut down the agent
550
+ def handle_server_connection_problem(error)
551
+ ::NewRelic::Agent.logger.error "Unable to establish connection with the server.", error
552
+ disconnect
553
+ end
554
+
555
+ # Handles an unknown error in the worker thread by logging
556
+ # it and disconnecting the agent, since we are now in an
557
+ # unknown state
558
+ def handle_other_error(error)
559
+ ::NewRelic::Agent.logger.error "Terminating worker loop.", error
560
+ disconnect
561
+ end
562
+
563
+ # a wrapper method to handle all the errors that can happen
564
+ # in the connection and worker thread system. This
565
+ # guarantees a no-throw from the background thread.
566
+ def catch_errors
567
+ yield
568
+ rescue NewRelic::Agent::ForceRestartException => e
569
+ handle_force_restart(e)
570
+ retry
571
+ rescue NewRelic::Agent::ForceDisconnectException => e
572
+ handle_force_disconnect(e)
573
+ rescue NewRelic::Agent::ServerConnectionException => e
574
+ handle_server_connection_problem(e)
575
+ rescue => e
576
+ handle_other_error(e)
577
+ end
578
+
579
+ # This is the method that is run in a new thread in order to
580
+ # background the harvesting and sending of data during the
581
+ # normal operation of the agent.
582
+ #
583
+ # Takes connection options that determine how we should
584
+ # connect to the server, and loops endlessly - typically we
585
+ # never return from this method unless we're shutting down
586
+ # the agent
587
+ def deferred_work!(connection_options)
588
+ catch_errors do
589
+ NewRelic::Agent.disable_all_tracing do
590
+ # We try to connect. If this returns false that means
591
+ # the server rejected us for a licensing reason and we should
592
+ # just exit the thread. If it returns nil
593
+ # that means it didn't try to connect because we're in the master.
594
+ connect(connection_options)
595
+ if connected?
596
+ log_worker_loop_start
597
+ create_and_run_worker_loop
598
+ # never reaches here unless there is a problem or
599
+ # the agent is exiting
600
+ else
601
+ ::NewRelic::Agent.logger.debug "No connection. Worker thread ending."
602
+ end
603
+ end
604
+ end
605
+ end
606
+ end
607
+ include StartWorkerThread
608
+
609
+ # Try to launch the worker thread and connect to the server.
610
+ #
611
+ # See #connect for a description of connection_options.
612
+ def start_worker_thread(connection_options = {})
613
+ ::NewRelic::Agent.logger.debug "Creating Ruby Agent worker thread."
614
+ @worker_thread = NewRelic::Agent::AgentThread.new('Worker Loop') do
615
+ deferred_work!(connection_options)
616
+ end
617
+ end
618
+
619
+ # A shorthand for NewRelic::Control.instance
620
+ def control
621
+ NewRelic::Control.instance
622
+ end
623
+
624
+ # This module is an artifact of a refactoring of the connect
625
+ # method - all of its methods are used in that context, so it
626
+ # can be refactored at will. It should be fully tested
627
+ module Connect
628
+ # number of attempts we've made to contact the server
629
+ attr_accessor :connect_attempts
630
+
631
+ # Disconnect just sets connected to false, which prevents
632
+ # the agent from trying to connect again
633
+ def disconnect
634
+ @connect_state = :disconnected
635
+ true
636
+ end
637
+
638
+ def connected?
639
+ @connect_state == :connected
640
+ end
641
+
642
+ def disconnected?
643
+ @connect_state == :disconnected
644
+ end
645
+
646
+ # Don't connect if we're already connected, or if we tried to connect
647
+ # and were rejected with prejudice because of a license issue, unless
648
+ # we're forced to by force_reconnect.
649
+ def should_connect?(force=false)
650
+ force || (!connected? && !disconnected?)
651
+ end
652
+
653
+ # Retry period is a minute for each failed attempt that
654
+ # we've made. This should probably do some sort of sane TCP
655
+ # backoff to prevent hammering the server, but a minute for
656
+ # each attempt seems to work reasonably well.
657
+ def connect_retry_period
658
+ [600, connect_attempts * 60].min
659
+ end
660
+
661
+ def note_connect_failure
662
+ self.connect_attempts += 1
663
+ end
664
+
665
+ # When we have a problem connecting to the server, we need
666
+ # to tell the user what happened, since this is not an error
667
+ # we can handle gracefully.
668
+ def log_error(error)
669
+ ::NewRelic::Agent.logger.error "Error establishing connection with New Relic Service at #{control.server}:", error
670
+ end
671
+
672
+ # When the server sends us an error with the license key, we
673
+ # want to tell the user that something went wrong, and let
674
+ # them know where to go to get a valid license key
675
+ #
676
+ # After this runs, it disconnects the agent so that it will
677
+ # no longer try to connect to the server, saving the
678
+ # application and the server load
679
+ def handle_license_error(error)
680
+ ::NewRelic::Agent.logger.error( \
681
+ error.message, \
682
+ "Visit NewRelic.com to obtain a valid license key, or to upgrade your account.")
683
+ disconnect
684
+ end
685
+
686
+ def handle_unrecoverable_agent_error(error)
687
+ ::NewRelic::Agent.logger.error(error.message)
688
+ disconnect
689
+ shutdown
690
+ end
691
+
692
+ # Checks whether we should send environment info, and if so,
693
+ # returns the snapshot from the local environment
694
+ def environment_for_connect
695
+ Agent.config[:send_environment_info] ? Control.instance.local_env.snapshot : []
696
+ end
697
+
698
+ # Initializes the hash of settings that we send to the
699
+ # server. Returns a literal hash containing the options
700
+ def connect_settings
701
+ {
702
+ :pid => $$,
703
+ :host => @local_host,
704
+ :app_name => Agent.config.app_names,
705
+ :language => 'ruby',
706
+ :agent_version => NewRelic::VERSION::STRING,
707
+ :environment => environment_for_connect,
708
+ :settings => Agent.config.to_collector_hash,
709
+ }
710
+ end
711
+
712
+ # Returns connect data passed back from the server
713
+ def connect_to_server
714
+ @service.connect(connect_settings)
715
+ end
716
+
717
+ # apdex_f is always 4 times the apdex_t
718
+ def apdex_f
719
+ (4 * Agent.config[:apdex_t]).to_f
720
+ end
721
+
722
+ # Sets the collector host and connects to the server, then
723
+ # invokes the final configuration with the returned data
724
+ def query_server_for_configuration
725
+ finish_setup(connect_to_server)
726
+ end
727
+
728
+ # Takes a hash of configuration data returned from the
729
+ # server and uses it to set local variables and to
730
+ # initialize various parts of the agent that are configured
731
+ # separately.
732
+ #
733
+ # Can accommodate most arbitrary data - anything extra is
734
+ # ignored unless we say to do something with it here.
735
+ def finish_setup(config_data)
736
+ return if config_data == nil
737
+
738
+ @service.agent_id = config_data['agent_run_id'] if @service
739
+
740
+ if config_data['agent_config']
741
+ ::NewRelic::Agent.logger.debug "Using config from server"
742
+ end
743
+
744
+ ::NewRelic::Agent.logger.debug "Server provided config: #{config_data.inspect}"
745
+ server_config = NewRelic::Agent::Configuration::ServerSource.new(config_data)
746
+ Agent.config.apply_config(server_config, 1)
747
+ log_connection!(config_data) if @service
748
+
749
+ add_rules_to_engine(config_data['transaction_name_rules'],
750
+ NewRelic::Agent.instance.transaction_rules)
751
+ add_rules_to_engine(config_data['metric_name_rules'],
752
+ NewRelic::Agent.instance.metric_rules)
753
+
754
+ # If you're adding something else here to respond to the server-side config,
755
+ # use Agent.instance.events.subscribe(:finished_configuring) callback instead!
756
+
757
+ @beacon_configuration = BeaconConfiguration.new
758
+ end
759
+
760
+ def add_rules_to_engine(rule_specifications, rules_engine)
761
+ return unless rule_specifications && rule_specifications.any?
762
+ rule_specifications.each do |rule_spec|
763
+ rules_engine << NewRelic::Agent::RulesEngine::Rule.new(rule_spec)
764
+ end
765
+ end
766
+
767
+ # Logs when we connect to the server, for debugging purposes
768
+ # - makes sure we know if an agent has not connected
769
+ def log_connection!(config_data)
770
+ ::NewRelic::Agent.logger.debug "Connected to NewRelic Service at #{@service.collector.name}"
771
+ ::NewRelic::Agent.logger.debug "Agent Run = #{@service.agent_id}."
772
+ ::NewRelic::Agent.logger.debug "Connection data = #{config_data.inspect}"
773
+ if config_data['messages'] && config_data['messages'].any?
774
+ log_collector_messages(config_data['messages'])
775
+ end
776
+ end
777
+
778
+ def log_collector_messages(messages)
779
+ messages.each do |message|
780
+ ::NewRelic::Agent.logger.send(message['level'].downcase, message['message'])
781
+ end
782
+ end
783
+ end
784
+ include Connect
785
+
786
+ # Accepts an array of (metrics, transaction_traces, errors) and merges
787
+ # it into our current collection of data to send. Can be
788
+ # dangerous if we re-merge the same data more than once - it
789
+ # will be sent multiple times.
790
+ def merge_data_from(data)
791
+ metrics, transaction_traces, errors = data
792
+ @stats_engine.merge!(metrics) if metrics
793
+ if transaction_traces && transaction_traces.respond_to?(:any?) &&
794
+ transaction_traces.any?
795
+ if @traces
796
+ @traces += transaction_traces
797
+ else
798
+ @traces = transaction_traces
799
+ end
800
+ end
801
+ if errors && errors.respond_to?(:each)
802
+ errors.each do |err|
803
+ @error_collector.add_to_error_queue(err)
804
+ end
805
+ end
806
+ end
807
+
808
+ public :merge_data_from
809
+
810
+ # Connect to the server and validate the license. If successful,
811
+ # connected? returns true when finished. If not successful, you can
812
+ # keep calling this. Return false if we could not establish a
813
+ # connection with the server and we should not retry, such as if
814
+ # there's a bad license key.
815
+ #
816
+ # Set keep_retrying=false to disable retrying and return asap, such as when
817
+ # invoked in the foreground. Otherwise this runs until a successful
818
+ # connection is made, or the server rejects us.
819
+ #
820
+ # * <tt>:keep_retrying => false</tt> to only try to connect once, and
821
+ # return with the connection set to nil. This ensures we may try again
822
+ # later (default true).
823
+ # * <tt>force_reconnect => true</tt> if you want to establish a new connection
824
+ # to the server before running the worker loop. This means you get a separate
825
+ # agent run and New Relic sees it as a separate instance (default is false).
826
+ def connect(options={})
827
+ defaults = {
828
+ :keep_retrying => Agent.config[:keep_retrying],
829
+ :force_reconnect => Agent.config[:force_reconnect]
830
+ }
831
+ opts = defaults.merge(options)
832
+
833
+ return unless should_connect?(opts[:force_reconnect])
834
+
835
+ ::NewRelic::Agent.logger.debug "Connecting Process to New Relic: #$0"
836
+ query_server_for_configuration
837
+ @connected_pid = $$
838
+ @connect_state = :connected
839
+ rescue NewRelic::Agent::LicenseException => e
840
+ handle_license_error(e)
841
+ rescue NewRelic::Agent::UnrecoverableAgentException => e
842
+ handle_unrecoverable_agent_error(e)
843
+ rescue Timeout::Error, StandardError => e
844
+ log_error(e)
845
+ if opts[:keep_retrying]
846
+ note_connect_failure
847
+ ::NewRelic::Agent.logger.warn "Will re-attempt in #{connect_retry_period} seconds"
848
+ sleep connect_retry_period
849
+ retry
850
+ else
851
+ disconnect
852
+ end
853
+ end
854
+
855
+ # Who am I? Well, this method can tell you your hostname.
856
+ def determine_host
857
+ Socket.gethostname
858
+ end
859
+
860
+ # Delegates to the control class to determine the root
861
+ # directory of this project
862
+ def determine_home_directory
863
+ control.root
864
+ end
865
+
866
+ # calls the busy harvester and collects timeslice data to
867
+ # send later
868
+ def harvest_timeslice_data(time=Time.now)
869
+ # this creates timeslices that are harvested below
870
+ NewRelic::Agent::BusyCalculator.harvest_busy
871
+
872
+ @unsent_timeslice_data ||= {}
873
+ @unsent_timeslice_data = @stats_engine.harvest_timeslice_data(@unsent_timeslice_data,
874
+ @metric_rules)
875
+ @unsent_timeslice_data
876
+ end
877
+
878
+ # note - exceptions are logged in invoke_remote. If an exception is encountered here,
879
+ # then the metric data is downsampled for another
880
+ # transmission later
881
+ def harvest_and_send_timeslice_data
882
+ now = Time.now
883
+ NewRelic::Agent.instance.stats_engine.get_stats_no_scope('Supportability/invoke_remote').record_data_point(0.0)
884
+ NewRelic::Agent.instance.stats_engine.get_stats_no_scope('Supportability/invoke_remote/metric_data').record_data_point(0.0)
885
+ harvest_timeslice_data(now)
886
+ begin
887
+ @service.metric_data(@last_harvest_time.to_f,
888
+ now.to_f,
889
+ @unsent_timeslice_data)
890
+ rescue UnrecoverableServerException => e
891
+ ::NewRelic::Agent.logger.debug e.message
892
+ end
893
+
894
+ ::NewRelic::Agent.logger.debug "#{now}: sent #{@unsent_timeslice_data.length} timeslices (#{@service.agent_id}) in #{Time.now - now} seconds"
895
+
896
+ # if we successfully invoked this web service, then clear the unsent message cache.
897
+ @unsent_timeslice_data = {}
898
+ @last_harvest_time = now
899
+ end
900
+
901
+ # Fills the traces array with the harvested transactions from
902
+ # the transaction sampler, subject to the setting for slowest
903
+ # transaction threshold
904
+ def harvest_transaction_traces
905
+ @traces = @transaction_sampler.harvest(@traces)
906
+ @traces
907
+ end
908
+
909
+ def harvest_and_send_slowest_sql
910
+ # FIXME add the code to try to resend if our connection is down
911
+ sql_traces = @sql_sampler.harvest
912
+ unless sql_traces.empty?
913
+ ::NewRelic::Agent.logger.debug "Sending (#{sql_traces.size}) sql traces"
914
+ begin
915
+ @service.sql_trace_data(sql_traces)
916
+ rescue UnrecoverableServerException => e
917
+ ::NewRelic::Agent.logger.debug e.message
918
+ rescue => e
919
+ ::NewRelic::Agent.logger.debug "Remerging SQL traces after #{e.class.name}: #{e.message}"
920
+ @sql_sampler.merge sql_traces
921
+ end
922
+ end
923
+ end
924
+
925
+ # This handles getting the transaction traces and then sending
926
+ # them across the wire. This includes gathering SQL
927
+ # explanations, stripping out stack traces, and normalizing
928
+ # SQL. note that we explain only the sql statements whose
929
+ # segments' execution times exceed our threshold (to avoid
930
+ # unnecessary overhead of running explains on fast queries.)
931
+ def harvest_and_send_slowest_sample
932
+ harvest_transaction_traces
933
+ unless @traces.empty?
934
+ now = Time.now
935
+ ::NewRelic::Agent.logger.debug "Sending (#{@traces.length}) transaction traces"
936
+
937
+ begin
938
+ options = { :keep_backtraces => true }
939
+ if !(NewRelic::Agent::Database.record_sql_method == :off)
940
+ options[:record_sql] = NewRelic::Agent::Database.record_sql_method
941
+ end
942
+ if Agent.config[:'transaction_tracer.explain_enabled']
943
+ options[:explain_sql] = Agent.config[:'transaction_tracer.explain_threshold']
944
+ end
945
+ traces = @traces.map {|trace| trace.prepare_to_send(options) }
946
+ @service.transaction_sample_data(traces)
947
+ ::NewRelic::Agent.logger.debug "Sent slowest sample (#{@service.agent_id}) in #{Time.now - now} seconds"
948
+ rescue UnrecoverableServerException => e
949
+ ::NewRelic::Agent.logger.debug e.message
950
+ end
951
+ end
952
+
953
+ # if we succeed sending this sample, then we don't need to keep
954
+ # the slowest sample around - it has been sent already and we
955
+ # can clear the collection and move on
956
+ @traces = nil
957
+ end
958
+
959
+ def harvest_and_send_thread_profile(disconnecting=false)
960
+ @thread_profiler.stop(true) if disconnecting
961
+
962
+ if @thread_profiler.finished?
963
+ profile = @thread_profiler.harvest
964
+
965
+ ::NewRelic::Agent.logger.debug "Sending thread profile #{profile.profile_id}"
966
+ @service.profile_data(profile)
967
+ end
968
+ end
969
+
970
+ # Gets the collection of unsent errors from the error
971
+ # collector. We pass back in an existing array of errors that
972
+ # may be left over from a previous send
973
+ def harvest_errors
974
+ @unsent_errors = @error_collector.harvest_errors(@unsent_errors)
975
+ @unsent_errors
976
+ end
977
+
978
+ # Handles getting the errors from the error collector and
979
+ # sending them to the server, and any error cases like trying
980
+ # to send very large errors - we drop the oldest error on the
981
+ # floor and try again
982
+ def harvest_and_send_errors
983
+ harvest_errors
984
+ if @unsent_errors && @unsent_errors.length > 0
985
+ ::NewRelic::Agent.logger.debug "Sending #{@unsent_errors.length} errors"
986
+ begin
987
+ @service.error_data(@unsent_errors)
988
+ rescue UnrecoverableServerException => e
989
+ ::NewRelic::Agent.logger.debug e.message
990
+ end
991
+ # if the remote invocation fails, then we never clear
992
+ # @unsent_errors, and therefore we can re-attempt to send on
993
+ # the next heartbeat. Note the error collector maxes out at
994
+ # 20 instances to prevent leakage
995
+ @unsent_errors = []
996
+ end
997
+ end
998
+
999
+ def check_for_agent_commands
1000
+ commands = @service.get_agent_commands
1001
+ ::NewRelic::Agent.logger.debug "Received get_agent_commands = #{commands.inspect}"
1002
+
1003
+ @thread_profiler.respond_to_commands(commands) do |command_id, error|
1004
+ @service.agent_command_results(command_id, error)
1005
+ end
1006
+ end
1007
+
1008
+ def transmit_data(disconnecting=false)
1009
+ now = Time.now
1010
+ ::NewRelic::Agent.logger.debug "Sending data to New Relic Service"
1011
+
1012
+ @service.session do # use http keep-alive
1013
+ harvest_and_send_errors
1014
+ harvest_and_send_slowest_sample
1015
+ harvest_and_send_slowest_sql
1016
+ harvest_and_send_timeslice_data
1017
+ harvest_and_send_thread_profile(disconnecting)
1018
+
1019
+ check_for_agent_commands
1020
+ end
1021
+ rescue => e
1022
+ retry_count ||= 0
1023
+ retry_count += 1
1024
+ if retry_count <= 1
1025
+ ::NewRelic::Agent.logger.debug "retrying transmit_data after #{e}"
1026
+ retry
1027
+ end
1028
+ raise e
1029
+ ensure
1030
+ NewRelic::Agent::Database.close_connections unless forked?
1031
+ @stats_engine.get_stats_no_scope('Supportability/Harvest') \
1032
+ .record_data_point((Time.now - now).to_f)
1033
+ end
1034
+
1035
+ # This method contacts the server to send remaining data and
1036
+ # let the server know that the agent is shutting down - this
1037
+ # allows us to do things like accurately set the end of the
1038
+ # lifetime of the process
1039
+ #
1040
+ # If this process comes from a parent process, it will not
1041
+ # disconnect, so that the parent process can continue to send data
1042
+ def graceful_disconnect
1043
+ if connected?
1044
+ begin
1045
+ @service.request_timeout = 10
1046
+ transmit_data(true)
1047
+
1048
+ if @connected_pid == $$ && !@service.kind_of?(NewRelic::Agent::NewRelicService)
1049
+ ::NewRelic::Agent.logger.debug "Sending New Relic service agent run shutdown message"
1050
+ @service.shutdown(Time.now.to_f)
1051
+ else
1052
+ ::NewRelic::Agent.logger.debug "This agent connected from parent process #{@connected_pid}--not sending shutdown"
1053
+ end
1054
+ ::NewRelic::Agent.logger.debug "Graceful disconnect complete"
1055
+ rescue Timeout::Error, StandardError => e
1056
+ ::NewRelic::Agent.logger.debug "Error when disconnecting #{e.class.name}: #{e.message}"
1057
+ end
1058
+ else
1059
+ ::NewRelic::Agent.logger.debug "Bypassing graceful disconnect - agent not connected"
1060
+ end
1061
+ end
1062
+ end
1063
+
1064
+ extend ClassMethods
1065
+ include InstanceMethods
1066
+ include BrowserMonitoring
1067
+ end
1068
+ end
1069
+ end