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
@@ -0,0 +1,5 @@
1
+ # This config is used when setting up a basic rails environment for running the
2
+ # unit tests.
3
+ test:
4
+ database: ':memory:'
5
+ adapter: 'sqlite3'
data/init.rb ADDED
@@ -0,0 +1,31 @@
1
+ # This is the initialization for the New Relic Ruby Agent when used as
2
+ # a plugin
3
+ require 'new_relic/control'
4
+
5
+ # If you are having problems seeing data, be sure and check the
6
+ # newrelic_agent.log files in the log diretory of your application
7
+ #
8
+ # If you can't find any log files and you don't see anything in your
9
+ # application log files, try uncommenting the two lines at the
10
+ # bottom of this file to verify the plugin is being loaded,
11
+ # then send the output to support@newrelic.com if you are unable to
12
+ # resolve the issue.
13
+
14
+ # Initializer for the NewRelic Ruby Agent
15
+
16
+ # After verison 2.0 of Rails we can access the configuration directly.
17
+ # We need it to add dev mode routes after initialization finished.
18
+
19
+ begin
20
+
21
+ current_config = if defined?(config)
22
+ config
23
+ elsif defined?(Rails.configuration)
24
+ Rails.configuration
25
+ end
26
+
27
+ NewRelic::Control.instance.init_plugin :config => current_config
28
+
29
+ rescue => e
30
+ ::NewRelic::Agent.logger.error "Error initializing New Relic plugin. Agent is disabled.", e
31
+ end
@@ -1,5 +1,6 @@
1
+ require 'forwardable'
1
2
  require 'new_relic/control'
2
- require 'new_relic/data_serialization'
3
+
3
4
  # = New Relic Ruby Agent
4
5
  #
5
6
  # New Relic is a performance monitoring application for applications
@@ -58,7 +59,8 @@ module NewRelic
58
59
  # support at New Relic for help.
59
60
  module Agent
60
61
  extend self
61
-
62
+ extend Forwardable
63
+
62
64
  require 'new_relic/version'
63
65
  require 'new_relic/local_environment'
64
66
  require 'new_relic/stats'
@@ -75,6 +77,7 @@ module NewRelic
75
77
  require 'new_relic/agent'
76
78
  require 'new_relic/agent/chained_call'
77
79
  require 'new_relic/agent/browser_monitoring'
80
+ require 'new_relic/agent/cross_process_monitoring'
78
81
  require 'new_relic/agent/agent'
79
82
  require 'new_relic/agent/shim_agent'
80
83
  require 'new_relic/agent/method_tracer'
@@ -82,22 +85,27 @@ module NewRelic
82
85
  require 'new_relic/agent/stats_engine'
83
86
  require 'new_relic/agent/transaction_sampler'
84
87
  require 'new_relic/agent/sql_sampler'
88
+ require 'new_relic/agent/thread_profiler'
85
89
  require 'new_relic/agent/error_collector'
86
90
  require 'new_relic/agent/busy_calculator'
87
91
  require 'new_relic/agent/sampler'
88
92
  require 'new_relic/agent/database'
93
+ require 'new_relic/agent/pipe_channel_manager'
89
94
  require 'new_relic/agent/transaction_info'
95
+ require 'new_relic/agent/configuration'
90
96
 
91
97
  require 'new_relic/agent/instrumentation/controller_instrumentation'
92
98
 
93
99
  require 'new_relic/agent/samplers/cpu_sampler'
94
100
  require 'new_relic/agent/samplers/memory_sampler'
95
101
  require 'new_relic/agent/samplers/object_sampler'
96
- require 'new_relic/agent/samplers/delayed_job_lock_sampler'
102
+ require 'new_relic/agent/samplers/delayed_job_sampler'
97
103
  require 'set'
98
104
  require 'thread'
99
105
  require 'resolv'
100
106
 
107
+ extend NewRelic::Agent::Configuration::Instance
108
+
101
109
  # An exception that is thrown by the server if the agent license is invalid.
102
110
  class LicenseException < StandardError; end
103
111
 
@@ -111,9 +119,9 @@ module NewRelic
111
119
  # failures.
112
120
  class ServerConnectionException < StandardError; end
113
121
 
114
- # Used for when a transaction trace or error report has too much
115
- # data, so we reset the queue to clear the extra-large item
116
- class PostTooBigException < ServerConnectionException; end
122
+ # When a post is either too large or poorly formatted we should
123
+ # drop it and not try to resend
124
+ class UnrecoverableServerException < ServerConnectionException; end
117
125
 
118
126
  # Reserved for future use. Meant to represent a problem on the server side.
119
127
  class ServerError < StandardError; end
@@ -133,6 +141,16 @@ module NewRelic
133
141
 
134
142
  alias instance agent #:nodoc:
135
143
 
144
+ # Primary interface to logging is fronted by this accessor
145
+ # Access via ::NewRelic::Agent.logger
146
+ def logger
147
+ @logger || StartupLogger.instance
148
+ end
149
+
150
+ def logger=(log)
151
+ @logger = log
152
+ end
153
+
136
154
  # Get or create a statistics gatherer that will aggregate numerical data
137
155
  # under a metric name.
138
156
  #
@@ -147,19 +165,6 @@ module NewRelic
147
165
 
148
166
  alias get_stats_no_scope get_stats
149
167
 
150
- # Get the logger for the agent. Available after the agent has initialized.
151
- # This sends output to the agent log file. If the agent has not initialized
152
- # a standard output logger is returned.
153
- def logger
154
- control = NewRelic::Control.instance(false)
155
- if control
156
- control.log
157
- else
158
- require 'logger'
159
- @stdoutlog ||= Logger.new $stdout
160
- end
161
- end
162
-
163
168
  # Call this to manually start the Agent in situations where the Agent does
164
169
  # not auto-start.
165
170
  #
@@ -177,6 +182,9 @@ module NewRelic
177
182
  #
178
183
  def manual_start(options={})
179
184
  raise "Options must be a hash" unless Hash === options
185
+ if options[:start_channel_listener]
186
+ NewRelic::Agent::PipeChannelManager.listener.start
187
+ end
180
188
  NewRelic::Control.instance.init_plugin({ :agent_enabled => true, :sync_startup => true }.merge(options))
181
189
  end
182
190
 
@@ -216,45 +224,6 @@ module NewRelic
216
224
  def shutdown(options={})
217
225
  agent.shutdown(options)
218
226
  end
219
-
220
- # a method used to serialize short-running processes to disk, so
221
- # we don't incur the overhead of reporting to the server for every
222
- # fork/invocation of a small job.
223
- #
224
- # Functionally, this loads the data from the file into the agent
225
- # (to avoid losing data by overwriting) and then serializes the
226
- # agent data to the file again. See also #load_data
227
- def save_data
228
- NewRelic::DataSerialization.read_and_write_to_file do |old_data|
229
- agent.merge_data_from(old_data)
230
- agent.serialize
231
- end
232
- end
233
-
234
- # used to load data from the disk during the harvest cycle to send
235
- # it. This method also clears the file so data should never be
236
- # sent more than once.
237
-
238
- # Note that only one transaction trace will be sent even if many
239
- # are serialized, since the slowest is sent.
240
- #
241
- # See also the complement to this method, #save_data - used when a
242
- # process is shutting down
243
- def load_data
244
- if !NewRelic::Control.instance['disable_serialization']
245
- NewRelic::DataSerialization.read_and_write_to_file do |old_data|
246
- agent.merge_data_from(old_data)
247
- nil # return nil so nothing is written to the file
248
- end
249
- NewRelic::DataSerialization.update_last_sent!
250
- end
251
-
252
- {
253
- :metrics => agent.stats_engine.metrics.length,
254
- :traces => agent.unsent_traces_size,
255
- :errors => agent.unsent_errors_size
256
- }
257
- end
258
227
 
259
228
  # Add instrumentation files to the agent. The argument should be
260
229
  # a glob matching ruby scripts which will be executed at the time
@@ -335,7 +304,8 @@ module NewRelic
335
304
 
336
305
  # Check to see if we are capturing metrics currently on this thread.
337
306
  def is_execution_traced?
338
- Thread.current[:newrelic_untraced].nil? || Thread.current[:newrelic_untraced].last != false
307
+ untraced = Thread.current[:newrelic_untraced]
308
+ untraced.nil? || untraced.last != false
339
309
  end
340
310
 
341
311
  # helper method to check the thread local to determine whether the
@@ -462,6 +432,7 @@ module NewRelic
462
432
  def browser_timing_footer
463
433
  agent.browser_timing_footer
464
434
  end
465
-
435
+
436
+ def_delegator :'NewRelic::Agent::PipeChannelManager', :register_report_channel
466
437
  end
467
438
  end
@@ -4,7 +4,11 @@ require 'net/http'
4
4
  require 'logger'
5
5
  require 'zlib'
6
6
  require 'stringio'
7
- require 'new_relic/data_serialization'
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'
8
12
 
9
13
  module NewRelic
10
14
  module Agent
@@ -14,38 +18,40 @@ module NewRelic
14
18
  # in realtime as the application runs, and periodically sends that
15
19
  # data to the NewRelic server.
16
20
  class Agent
17
-
18
- # Specifies the version of the agent's communication protocol with
19
- # the NewRelic hosted site.
20
-
21
- PROTOCOL_VERSION = 8
22
- # 14105: v8 (tag 2.10.3)
23
- # (no v7)
24
- # 10379: v6 (not tagged)
25
- # 4078: v5 (tag 2.5.4)
26
- # 2292: v4 (tag 2.3.6)
27
- # 1754: v3 (tag 2.3.0)
28
- # 534: v2 (shows up in 2.1.0, our first tag)
29
-
21
+ extend NewRelic::Agent::Configuration::Instance
30
22
 
31
23
  def initialize
32
-
33
24
  @launch_time = Time.now
34
25
 
35
26
  @metric_ids = {}
36
27
  @stats_engine = NewRelic::Agent::StatsEngine.new
37
28
  @transaction_sampler = NewRelic::Agent::TransactionSampler.new
38
29
  @sql_sampler = NewRelic::Agent::SqlSampler.new
39
- @stats_engine.transaction_sampler = @transaction_sampler
30
+ @thread_profiler = NewRelic::Agent::ThreadProfiler.new
40
31
  @error_collector = NewRelic::Agent::ErrorCollector.new
41
32
  @connect_attempts = 0
42
33
 
43
- @request_timeout = NewRelic::Control.instance.fetch('timeout', 2 * 60)
44
-
45
34
  @last_harvest_time = Time.now
46
35
  @obfuscator = lambda {|sql| NewRelic::Agent::Database.default_sql_obfuscator(sql) }
36
+ @forked = false
37
+
38
+ # FIXME: temporary work around for RUBY-839
39
+ if Agent.config[:monitor_mode]
40
+ @service = NewRelic::Agent::NewRelicService.new
41
+ end
42
+
43
+ txn_tracer_enabler = Proc.new do
44
+ if NewRelic::Agent.config[:'transaction_tracer.enabled'] ||
45
+ NewRelic::Agent.config[:developer_mode]
46
+ @stats_engine.transaction_sampler = @transaction_sampler
47
+ else
48
+ @stats_engine.transaction_sampler = nil
49
+ end
50
+ end
51
+ Agent.config.register_callback(:'transaction_tracer.enabled', &txn_tracer_enabler)
52
+ Agent.config.register_callback(:developer_mode, &txn_tracer_enabler)
47
53
  end
48
-
54
+
49
55
  # contains all the class-level methods for NewRelic::Agent::Agent
50
56
  module ClassMethods
51
57
  # Should only be called by NewRelic::Control - returns a
@@ -54,11 +60,11 @@ module NewRelic
54
60
  @instance ||= self.new
55
61
  end
56
62
  end
57
-
63
+
58
64
  # Holds all the methods defined on NewRelic::Agent::Agent
59
65
  # instances
60
66
  module InstanceMethods
61
-
67
+
62
68
  # holds a proc that is used to obfuscate sql statements
63
69
  attr_reader :obfuscator
64
70
  # the statistics engine that holds all the timeslice data
@@ -66,6 +72,8 @@ module NewRelic
66
72
  # the transaction sampler that handles recording transactions
67
73
  attr_reader :transaction_sampler
68
74
  attr_reader :sql_sampler
75
+ # begins a thread profile session when instructed by agent commands
76
+ attr_reader :thread_profiler
69
77
  # error collector is a simple collection of recorded errors
70
78
  attr_reader :error_collector
71
79
  # whether we should record raw, obfuscated, or no sql
@@ -81,19 +89,25 @@ module NewRelic
81
89
  # handles things like static setup of the header for inclusion
82
90
  # into pages
83
91
  attr_reader :beacon_configuration
84
-
92
+ # cross process id's and encoding
93
+ attr_reader :cross_process_id
94
+ attr_reader :cross_process_encoding_bytes
95
+ # service for communicating with collector
96
+ attr_accessor :service
97
+
98
+
85
99
  # Returns the length of the unsent errors array, if it exists,
86
100
  # otherwise nil
87
101
  def unsent_errors_size
88
102
  @unsent_errors.length if @unsent_errors
89
103
  end
90
-
104
+
91
105
  # Returns the length of the traces array, if it exists,
92
106
  # otherwise nil
93
107
  def unsent_traces_size
94
108
  @traces.length if @traces
95
109
  end
96
-
110
+
97
111
  # Initializes the unsent timeslice data hash, if needed, and
98
112
  # returns the number of keys it contains
99
113
  def unsent_timeslice_data
@@ -104,7 +118,7 @@ module NewRelic
104
118
  # fakes out a transaction that did not happen in this process
105
119
  # by creating apdex, summary metrics, and recording statistics
106
120
  # for the transaction
107
- #
121
+ #
108
122
  # This method is *deprecated* - it may be removed in future
109
123
  # versions of the agent
110
124
  def record_transaction(duration_seconds, options={})
@@ -158,18 +172,25 @@ module NewRelic
158
172
  # connection, this tells me to only try it once so this method returns
159
173
  # quickly if there is some kind of latency with the server.
160
174
  def after_fork(options={})
175
+ @forked = true
176
+ Agent.config.apply_config(NewRelic::Agent::Configuration::ManualSource.new(options), 1)
161
177
 
162
178
  # @connected gets false after we fail to connect or have an error
163
179
  # connecting. @connected has nil if we haven't finished trying to connect.
164
180
  # or we didn't attempt a connection because this is the master process
165
181
 
166
- # log.debug "Agent received after_fork notice in #$$: [#{control.agent_enabled?}; monitor=#{control.monitor_mode?}; connected: #{@connected.inspect}; thread=#{@worker_thread.inspect}]"
167
- return if !control.agent_enabled? or
168
- !control.monitor_mode? or
169
- @connected == false or
182
+ if channel_id = options[:report_to_channel]
183
+ @service = NewRelic::Agent::PipeService.new(channel_id)
184
+ @connected_pid = $$
185
+ @metric_ids = {}
186
+ end
187
+
188
+ return if !Agent.config[:agent_enabled] ||
189
+ !Agent.config[:monitor_mode] ||
190
+ @connected == false ||
170
191
  @worker_thread && @worker_thread.alive?
171
192
 
172
- log.info "Starting the worker thread in #$$ after forking."
193
+ ::NewRelic::Agent.logger.debug "Starting the worker thread in #{$$} after forking."
173
194
 
174
195
  # Clear out stats that are left over from parent process
175
196
  reset_stats
@@ -180,6 +201,10 @@ module NewRelic
180
201
  @stats_engine.start_sampler_thread
181
202
  end
182
203
 
204
+ def forked?
205
+ @forked
206
+ end
207
+
183
208
  # True if we have initialized and completed 'start'
184
209
  def started?
185
210
  @started
@@ -198,32 +223,36 @@ module NewRelic
198
223
  # :force_send => (true/false) # force the agent to send data
199
224
  # before shutting down
200
225
  def shutdown(options={})
201
- run_loop_before_exit = options.fetch(:force_send, false)
226
+ run_loop_before_exit = Agent.config[:force_send]
202
227
  return if not started?
203
228
  if @worker_loop
204
229
  @worker_loop.run_task if run_loop_before_exit
205
230
  @worker_loop.stop
231
+ end
206
232
 
207
- log.debug "Starting Agent shutdown"
233
+ ::NewRelic::Agent.logger.info "Starting Agent shutdown"
208
234
 
209
- # if litespeed, then ignore all future SIGUSR1 - it's
210
- # litespeed trying to shut us down
235
+ # if litespeed, then ignore all future SIGUSR1 - it's
236
+ # litespeed trying to shut us down
211
237
 
212
- if control.dispatcher == :litespeed
213
- Signal.trap("SIGUSR1", "IGNORE")
214
- Signal.trap("SIGTERM", "IGNORE")
215
- end
238
+ if Agent.config[:dispatcher] == :litespeed
239
+ Signal.trap("SIGUSR1", "IGNORE")
240
+ Signal.trap("SIGTERM", "IGNORE")
241
+ end
216
242
 
217
- begin
218
- NewRelic::Agent.disable_all_tracing do
219
- graceful_disconnect
220
- end
221
- rescue => e
222
- log.error e
223
- log.error e.backtrace.join("\n")
243
+ begin
244
+ NewRelic::Agent.disable_all_tracing do
245
+ graceful_disconnect
224
246
  end
247
+ rescue => e
248
+ ::NewRelic::Agent.logger.error e
249
+ end
250
+ NewRelic::Agent.config.remove_config do |config|
251
+ config.class == NewRelic::Agent::Configuration::ManualSource ||
252
+ config.class == NewRelic::Agent::Configuration::ServerSource
225
253
  end
226
254
  @started = nil
255
+ Control.reset
227
256
  end
228
257
 
229
258
  # Tells the statistics engine we are starting a new transaction
@@ -273,18 +302,13 @@ module NewRelic
273
302
  Thread.current[:newrelic_untraced].pop if Thread.current[:newrelic_untraced]
274
303
  end
275
304
 
276
- # Shorthand to the NewRelic::Agent.logger method
277
- def log
278
- NewRelic::Agent.logger
279
- end
280
-
281
305
  # Herein lies the corpse of the former 'start' method. May
282
- # it's unmatched flog score rest in pieces.
306
+ # its unmatched flog score rest in pieces.
283
307
  module Start
284
308
  # Check whether we have already started, which is an error condition
285
309
  def already_started?
286
310
  if started?
287
- control.log!("Agent Started Already!", :error)
311
+ ::NewRelic::Agent.logger.error("Agent Started Already!")
288
312
  true
289
313
  end
290
314
  end
@@ -293,23 +317,41 @@ module NewRelic
293
317
  # 'agent_enabled' option (e.g. in a manual start), or
294
318
  # enabled normally through the configuration file
295
319
  def disabled?
296
- !control.agent_enabled?
320
+ !Agent.config[:agent_enabled]
321
+ end
322
+
323
+ # Log startup information that we almost always want to know
324
+ def log_startup
325
+ log_environment
326
+ log_dispatcher
327
+ log_app_names
328
+ end
329
+
330
+ # Log the environment the app thinks it's running in.
331
+ # Useful in debugging, as this is the key for config YAML lookups.
332
+ def log_environment
333
+ ::NewRelic::Agent.logger.info "Environment: #{NewRelic::Control.instance.env}"
297
334
  end
298
335
 
299
336
  # Logs the dispatcher to the log file to assist with
300
337
  # debugging. When no debugger is present, logs this fact to
301
338
  # assist with proper dispatcher detection
302
339
  def log_dispatcher
303
- dispatcher_name = control.dispatcher.to_s
304
- return if log_if(dispatcher_name.empty?, :info, "No dispatcher detected.")
305
- log.info "Dispatcher: #{dispatcher_name}"
340
+ dispatcher_name = Agent.config[:dispatcher].to_s
341
+ return if log_if(dispatcher_name.empty?, :warn, "No dispatcher detected.")
342
+ ::NewRelic::Agent.logger.info "Dispatcher: #{dispatcher_name}"
306
343
  end
307
344
 
308
345
  # Logs the configured application names
309
346
  def log_app_names
310
- log.info "Application: #{control.app_names.join(", ")}"
347
+ names = Agent.config.app_names
348
+ if names.respond_to?(:any?) && names.any?
349
+ ::NewRelic::Agent.logger.info "Application: #{names.join(", ")}"
350
+ else
351
+ ::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.'
352
+ end
311
353
  end
312
-
354
+
313
355
  # Connecting in the foreground blocks further startup of the
314
356
  # agent until we have a connection - useful in cases where
315
357
  # you're trying to log a very-short-running process and want
@@ -337,34 +379,35 @@ module NewRelic
337
379
  # behavior of at_exit blocks to make sure it runs last, by
338
380
  # doing an at_exit within an at_exit block.
339
381
  def install_exit_handler
340
- if control.send_data_on_exit && !weird_ruby?
341
- # Our shutdown handler needs to run after other shutdown handlers
342
- at_exit { at_exit { shutdown } }
382
+ if Agent.config[:send_data_on_exit] && !weird_ruby?
383
+ at_exit do
384
+ # Workaround for MRI 1.9 bug that loses exit codes in at_exit blocks.
385
+ # This is necessary to get correct exit codes for the agent's
386
+ # test suites.
387
+ # http://bugs.ruby-lang.org/issues/5218
388
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE == "ruby" && RUBY_VERSION.match(/^1\.9/)
389
+ exit_status = $!.status if $!.is_a?(SystemExit)
390
+ shutdown
391
+ exit exit_status if exit_status
392
+ else
393
+ shutdown
394
+ end
395
+ end
343
396
  end
344
397
  end
345
398
 
346
- # Tells us in the log file where the log file is
347
- # located. This seems redundant, but can come in handy when
348
- # we have some log file path set by the user which parses
349
- # incorrectly, sending the log file to who-knows-where
350
- def notify_log_file_location
351
- log_file = NewRelic::Control.instance.log_file
352
- log_if(File.exists?(log_file.to_s), :info,
353
- "Agent Log at #{log_file}")
354
- end
355
-
356
399
  # Classy logging of the agent version and the current pid,
357
400
  # so we can disambiguate processes in the log file and make
358
401
  # sure they're running a reasonable version
359
402
  def log_version_and_pid
360
- log.info "New Relic Ruby Agent #{NewRelic::VERSION::STRING} Initialized: pid = #{$$}"
403
+ ::NewRelic::Agent.logger.debug "New Relic Ruby Agent #{NewRelic::VERSION::STRING} Initialized: pid = #{$$}"
361
404
  end
362
405
 
363
406
  # A helper method that logs a condition if that condition is
364
407
  # true. Mentally cleaner than having every method set a
365
408
  # local and log if it is true
366
409
  def log_if(boolean, level, message)
367
- self.log.send(level, message) if boolean
410
+ ::NewRelic::Agent.logger.send(level, message) if boolean
368
411
  boolean
369
412
  end
370
413
 
@@ -372,20 +415,23 @@ module NewRelic
372
415
  # condition is true. Mentally cleaner than having every
373
416
  # method set a local and log unless it is true
374
417
  def log_unless(boolean, level, message)
375
- self.log.send(level, message) unless boolean
418
+ ::NewRelic::Agent.logger.send(level, message) unless boolean
376
419
  boolean
377
420
  end
378
421
 
379
422
  # Warn the user if they have configured their agent not to
380
423
  # send data, that way we can see this clearly in the log file
381
424
  def monitoring?
382
- log_unless(control.monitor_mode?, :warn, "Agent configured not to send data in this environment - edit newrelic.yml to change this")
425
+ log_unless(Agent.config[:monitor_mode], :warn,
426
+ "Agent configured not to send data in this environment.")
383
427
  end
384
428
 
385
429
  # Tell the user when the license key is missing so they can
386
430
  # fix it by adding it to the file
387
431
  def has_license_key?
388
- log_unless(control.license_key, :error, "No license key found. Please edit your newrelic.yml file and insert your license key.")
432
+ log_unless(Agent.config[:license_key], :warn,
433
+ "No license key found in newrelic.yml config. " +
434
+ "This often means your newrelic.yml is missing a section for the running environment '#{NewRelic::Control.instance.env}'")
389
435
  end
390
436
 
391
437
  # A correct license key exists and is of the proper length
@@ -396,7 +442,7 @@ module NewRelic
396
442
  # A license key is an arbitrary 40 character string,
397
443
  # usually looks something like a SHA1 hash
398
444
  def correct_license_length
399
- key = control.license_key
445
+ key = Agent.config[:license_key]
400
446
  log_unless((key.length == 40), :error, "Invalid license key: #{key}")
401
447
  end
402
448
 
@@ -404,7 +450,8 @@ module NewRelic
404
450
  # requests, we need to wait until the children are forked
405
451
  # before connecting, otherwise the parent process sends odd data
406
452
  def using_forking_dispatcher?
407
- log_if([:passenger, :unicorn].include?(control.dispatcher), :info, "Connecting workers after forking.")
453
+ log_if([:passenger, :unicorn].include?(Agent.config[:dispatcher]),
454
+ :info, "Connecting workers after forking.")
408
455
  end
409
456
 
410
457
  # Sanity-check the agent configuration and start the agent,
@@ -413,7 +460,7 @@ module NewRelic
413
460
  def check_config_and_start_agent
414
461
  return unless monitoring? && has_correct_license_key?
415
462
  return if using_forking_dispatcher?
416
- connect_in_foreground if control.sync_startup
463
+ connect_in_foreground if Agent.config[:sync_startup]
417
464
  start_worker_thread
418
465
  install_exit_handler
419
466
  end
@@ -426,12 +473,9 @@ module NewRelic
426
473
  return if already_started? || disabled?
427
474
  @started = true
428
475
  @local_host = determine_host
429
- log_dispatcher
430
- log_app_names
431
- config_transaction_tracer
476
+ log_startup
432
477
  check_config_and_start_agent
433
478
  log_version_and_pid
434
- notify_log_file_location
435
479
  end
436
480
 
437
481
  # Clear out the metric data, errors, and transaction traces,
@@ -446,48 +490,24 @@ module NewRelic
446
490
  end
447
491
 
448
492
  private
449
- def collector
450
- @collector ||= control.server
451
- end
452
-
493
+
453
494
  # All of this module used to be contained in the
454
495
  # start_worker_thread method - this is an artifact of
455
496
  # refactoring and can be moved, renamed, etc at will
456
497
  module StartWorkerThread
457
-
458
- # disable transaction sampling if disabled by the server
459
- # and we're not in dev mode
460
- def check_transaction_sampler_status
461
- if control.developer_mode? || @should_send_samples
462
- @transaction_sampler.enable
463
- else
464
- @transaction_sampler.disable
465
- end
466
- end
467
-
468
- def check_sql_sampler_status
469
- # disable sql sampling if disabled by the server
470
- # and we're not in dev mode
471
- if @sql_sampler.config.fetch('enabled', true) && ['raw', 'obfuscated'].include?(@sql_sampler.config.fetch('record_sql', 'obfuscated').to_s) && @transaction_sampler.config.fetch('enabled', true)
472
- @sql_sampler.enable
473
- else
474
- @sql_sampler.disable
475
- end
476
- end
477
-
478
498
  # logs info about the worker loop so users can see when the
479
499
  # agent actually begins running in the background
480
500
  def log_worker_loop_start
481
- log.info "Reporting performance data every #{@report_period} seconds."
482
- log.debug "Running worker loop"
501
+ ::NewRelic::Agent.logger.debug "Reporting performance data every #{Agent.config[:data_report_period]} seconds."
502
+ ::NewRelic::Agent.logger.debug "Running worker loop"
483
503
  end
484
504
 
485
505
  # Creates the worker loop and loads it with the instructions
486
506
  # it should run every @report_period seconds
487
507
  def create_and_run_worker_loop
488
508
  @worker_loop = WorkerLoop.new
489
- @worker_loop.run(@report_period) do
490
- save_or_transmit_data
509
+ @worker_loop.run(Agent.config[:data_report_period]) do
510
+ transmit_data
491
511
  end
492
512
  end
493
513
 
@@ -495,7 +515,7 @@ module NewRelic
495
515
  # this clears the data, clears connection attempts, and
496
516
  # waits a while to reconnect.
497
517
  def handle_force_restart(error)
498
- log.info error.message
518
+ ::NewRelic::Agent.logger.debug error.message
499
519
  reset_stats
500
520
  @metric_ids = {}
501
521
  @connected = nil
@@ -506,15 +526,14 @@ module NewRelic
506
526
  # is the worker thread that gathers data and talks to the
507
527
  # server.
508
528
  def handle_force_disconnect(error)
509
- log.error "New Relic forced this agent to disconnect (#{error.message})"
529
+ ::NewRelic::Agent.logger.warn "New Relic forced this agent to disconnect (#{error.message})"
510
530
  disconnect
511
531
  end
512
532
 
513
533
  # there is a problem with connecting to the server, so we
514
534
  # stop trying to connect and shut down the agent
515
535
  def handle_server_connection_problem(error)
516
- log.error "Unable to establish connection with the server. Run with log level set to debug for more information."
517
- log.debug("#{error.class.name}: #{error.message}\n#{error.backtrace.first}")
536
+ ::NewRelic::Agent.logger.error "Unable to establish connection with the server.", error
518
537
  disconnect
519
538
  end
520
539
 
@@ -522,7 +541,7 @@ module NewRelic
522
541
  # it and disconnecting the agent, since we are now in an
523
542
  # unknown state
524
543
  def handle_other_error(error)
525
- log.error "Terminating worker loop: #{error.class.name}: #{error.message}\n #{error.backtrace.join("\n ")}"
544
+ ::NewRelic::Agent.logger.error "Terminating worker loop.", error
526
545
  disconnect
527
546
  end
528
547
 
@@ -559,14 +578,12 @@ module NewRelic
559
578
  # that means it didn't try to connect because we're in the master.
560
579
  connect(connection_options)
561
580
  if @connected
562
- check_transaction_sampler_status
563
- check_sql_sampler_status
564
581
  log_worker_loop_start
565
582
  create_and_run_worker_loop
566
583
  # never reaches here unless there is a problem or
567
584
  # the agent is exiting
568
585
  else
569
- log.debug "No connection. Worker thread ending."
586
+ ::NewRelic::Agent.logger.debug "No connection. Worker thread ending."
570
587
  end
571
588
  end
572
589
  end
@@ -578,18 +595,17 @@ module NewRelic
578
595
  #
579
596
  # See #connect for a description of connection_options.
580
597
  def start_worker_thread(connection_options = {})
581
- log.debug "Creating Ruby Agent worker thread."
582
- @worker_thread = Thread.new do
598
+ ::NewRelic::Agent.logger.debug "Creating Ruby Agent worker thread."
599
+ @worker_thread = NewRelic::Agent::AgentThread.new('Worker Loop') do
583
600
  deferred_work!(connection_options)
584
- end # thread new
585
- @worker_thread['newrelic_label'] = 'Worker Loop'
601
+ end
586
602
  end
587
603
 
588
604
  # A shorthand for NewRelic::Control.instance
589
605
  def control
590
606
  NewRelic::Control.instance
591
607
  end
592
-
608
+
593
609
  # This module is an artifact of a refactoring of the connect
594
610
  # method - all of its methods are used in that context, so it
595
611
  # can be refactored at will. It should be fully tested
@@ -642,7 +658,7 @@ module NewRelic
642
658
  if @keep_retrying
643
659
  self.connect_attempts=(connect_attempts + 1)
644
660
  increment_retry_period!
645
- log.info "Will re-attempt in #{connect_retry_period} seconds"
661
+ ::NewRelic::Agent.logger.warn "Will re-attempt in #{connect_retry_period} seconds"
646
662
  true
647
663
  else
648
664
  disconnect
@@ -654,8 +670,7 @@ module NewRelic
654
670
  # to tell the user what happened, since this is not an error
655
671
  # we can handle gracefully.
656
672
  def log_error(error)
657
- log.error "Error establishing connection with New Relic Service at #{control.server}: #{error.message}"
658
- log.debug error.backtrace.join("\n")
673
+ ::NewRelic::Agent.logger.error "Error establishing connection with New Relic Service at #{control.server}:", error
659
674
  end
660
675
 
661
676
  # When the server sends us an error with the license key, we
@@ -666,35 +681,16 @@ module NewRelic
666
681
  # no longer try to connect to the server, saving the
667
682
  # application and the server load
668
683
  def handle_license_error(error)
669
- log.error error.message
670
- log.info "Visit NewRelic.com to obtain a valid license key, or to upgrade your account."
684
+ ::NewRelic::Agent.logger.error( \
685
+ error.message, \
686
+ "Visit NewRelic.com to obtain a valid license key, or to upgrade your account.")
671
687
  disconnect
672
688
  end
673
689
 
674
- # If we are using a seed and token to validate the agent, we
675
- # should debug log that fact so that debug logs include a
676
- # clue that token authentication is what will be used
677
- def log_seed_token
678
- if control.validate_seed
679
- log.debug "Connecting with validation seed/token: #{control.validate_seed}/#{control.validate_token}"
680
- end
681
- end
682
-
683
690
  # Checks whether we should send environment info, and if so,
684
691
  # returns the snapshot from the local environment
685
692
  def environment_for_connect
686
- control['send_environment_info'] != false ? control.local_env.snapshot : []
687
- end
688
-
689
- # These validation settings are used for cases where a
690
- # dynamic server is spun up for clients - partners can
691
- # include a seed and token to indicate that the host is
692
- # allowed to connect, rather than setting a unique hostname
693
- def validate_settings
694
- {
695
- :seed => control.validate_seed,
696
- :token => control.validate_token
697
- }
693
+ Agent.config[:send_environment_info] ? Control.instance.local_env.snapshot : []
698
694
  end
699
695
 
700
696
  # Initializes the hash of settings that we send to the
@@ -703,149 +699,27 @@ module NewRelic
703
699
  {
704
700
  :pid => $$,
705
701
  :host => @local_host,
706
- :app_name => control.app_names,
702
+ :app_name => Agent.config.app_names,
707
703
  :language => 'ruby',
708
704
  :agent_version => NewRelic::VERSION::STRING,
709
705
  :environment => environment_for_connect,
710
- :settings => control.settings,
711
- :validate => validate_settings
706
+ :settings => Agent.config.to_collector_hash,
712
707
  }
713
708
  end
714
709
 
715
- # Does some simple logging to make sure that our seed and
716
- # token for verification are correct, then returns the
717
- # connect data passed back from the server
710
+ # Returns connect data passed back from the server
718
711
  def connect_to_server
719
- log_seed_token
720
- connect_data = invoke_remote(:connect, connect_settings)
721
- end
722
-
723
- # Configures the error collector if the server says that we
724
- # are allowed to send errors. Pretty simple, and logs at
725
- # debug whether errors will or will not be sent.
726
- def configure_error_collector!(server_enabled)
727
- # Reinitialize the error collector
728
- @error_collector = NewRelic::Agent::ErrorCollector.new
729
- # Ask for permission to collect error data
730
- enabled = if error_collector.config_enabled && server_enabled
731
- error_collector.enabled = true
732
- else
733
- error_collector.enabled = false
734
- end
735
- log.debug "Errors will #{enabled ? '' : 'not '}be sent to the New Relic service."
736
- end
737
-
738
- # Random sampling is enabled based on a sample rate, which
739
- # is the n in "every 1/n transactions is added regardless of
740
- # its length".
741
- #
742
- # uses a sane default for sampling rate if the sampling rate
743
- # is zero, since the collector currently sends '0' as a
744
- # sampling rate for all accounts, which is probably for
745
- # legacy reasons
746
- def enable_random_samples!(sample_rate)
747
- sample_rate = 10 unless sample_rate.to_i > 0
748
- @transaction_sampler.random_sampling = true
749
- @transaction_sampler.sampling_rate = sample_rate
750
- log.info "Transaction sampling enabled, rate = #{@transaction_sampler.sampling_rate}"
751
- end
752
-
753
- # this entire method should be done on the transaction
754
- # sampler object, rather than here. We should pass in the
755
- # sampler config.
756
- def config_transaction_tracer
757
- # Reconfigure the transaction tracer
758
- @transaction_sampler.configure!
759
- @sql_sampler.configure!
760
- @should_send_samples = @config_should_send_samples = @transaction_sampler.config.fetch('enabled', true)
761
- @should_send_random_samples = @transaction_sampler.config.fetch('random_sample', false)
762
- set_sql_recording!
763
-
764
- # default to 2.0, string 'apdex_f' will turn into your
765
- # apdex * 4
766
- @slowest_transaction_threshold = @transaction_sampler.config.fetch('transaction_threshold', 2.0).to_f
767
- @slowest_transaction_threshold = apdex_f if apdex_f_threshold?
768
- end
769
-
770
- # Enables or disables the transaction tracer and sets its
771
- # options based on the options provided to the
772
- # method.
773
- def configure_transaction_tracer!(server_enabled, sample_rate)
774
- # Ask the server for permission to send transaction samples.
775
- # determined by subscription license.
776
- @transaction_sampler.config['enabled'] = server_enabled
777
- @sql_sampler.configure!
778
- @should_send_samples = @config_should_send_samples && server_enabled
779
-
780
- if @should_send_samples
781
- # I don't think this is ever true, but...
782
- enable_random_samples!(sample_rate) if @should_send_random_samples
783
-
784
- @transaction_sampler.slow_capture_threshold = @slowest_transaction_threshold
785
-
786
- log.debug "Transaction tracing threshold is #{@slowest_transaction_threshold} seconds."
787
- else
788
- log.debug "Transaction traces will not be sent to the New Relic service."
789
- end
712
+ @service.connect(connect_settings)
790
713
  end
791
714
 
792
715
  # apdex_f is always 4 times the apdex_t
793
716
  def apdex_f
794
- (4 * NewRelic::Control.instance.apdex_t).to_f
795
- end
796
-
797
- # If the transaction threshold is set to the string
798
- # 'apdex_f', we use 4 times the apdex_t value to record
799
- # transactions. This gears well with using apdex since you
800
- # will attempt to send any transactions that register as 'failing'
801
- def apdex_f_threshold?
802
- @transaction_sampler.config.fetch('transaction_threshold', '') =~ /apdex_f/i
803
- end
804
-
805
- # Sets the sql recording configuration by trying to detect
806
- # any attempt to disable the sql collection - 'off',
807
- # 'false', 'none', and friends. Otherwise, we accept 'raw',
808
- # and unrecognized values default to 'obfuscated'
809
- def set_sql_recording!
810
- record_sql_config = @transaction_sampler.config.fetch('record_sql', :obfuscated)
811
- case record_sql_config.to_s
812
- when 'off'
813
- @record_sql = :off
814
- when 'none'
815
- @record_sql = :off
816
- when 'false'
817
- @record_sql = :off
818
- when 'raw'
819
- @record_sql = :raw
820
- else
821
- @record_sql = :obfuscated
822
- end
823
-
824
- log_sql_transmission_warning?
825
- end
826
-
827
- # Warn the user when we are sending raw sql across the wire
828
- # - they should probably be using ssl when this is true
829
- def log_sql_transmission_warning?
830
- log.warn("Agent is configured to send raw SQL to the service") if @record_sql == :raw
831
- end
832
-
833
- # Asks the collector to tell us which sub-collector we
834
- # should be reporting to, and then does the name resolution
835
- # on that host so we don't block on DNS during the normal
836
- # course of agent processing
837
- def set_collector_host!
838
- host = invoke_remote(:get_redirect_host)
839
- if host
840
- @collector = control.server_from_host(host)
841
- end
717
+ (4 * Agent.config[:apdex_t]).to_f
842
718
  end
843
719
 
844
720
  # Sets the collector host and connects to the server, then
845
721
  # invokes the final configuration with the returned data
846
722
  def query_server_for_configuration
847
- set_collector_host!
848
-
849
723
  finish_setup(connect_to_server)
850
724
  end
851
725
 
@@ -857,30 +731,52 @@ module NewRelic
857
731
  # Can accommodate most arbitrary data - anything extra is
858
732
  # ignored unless we say to do something with it here.
859
733
  def finish_setup(config_data)
860
- @agent_id = config_data['agent_run_id']
861
- @report_period = config_data['data_report_period']
862
- @url_rules = config_data['url_rules']
863
- @beacon_configuration = BeaconConfiguration.new(config_data)
864
- @server_side_config_enabled = config_data['listen_to_server_config']
865
-
866
- if @server_side_config_enabled
867
- log.info "Using config from server"
868
- log.debug "Server provided config: #{config_data.inspect}"
734
+ return if config_data == nil
735
+
736
+ @service.agent_id = config_data['agent_run_id'] if @service
737
+
738
+ if config_data['agent_config']
739
+ ::NewRelic::Agent.logger.debug "Using config from server"
869
740
  end
870
741
 
871
- control.merge_server_side_config(config_data) if @server_side_config_enabled
872
- config_transaction_tracer
873
- log_connection!(config_data)
874
- configure_transaction_tracer!(config_data['collect_traces'], config_data['sample_rate'])
875
- configure_error_collector!(config_data['collect_errors'])
742
+ ::NewRelic::Agent.logger.debug "Server provided config: #{config_data.inspect}"
743
+ server_config = NewRelic::Agent::Configuration::ServerSource.new(config_data)
744
+ Agent.config.apply_config(server_config, 1)
745
+ log_connection!(config_data) if @service
746
+
747
+ @cross_process_id = Agent.config[:cross_process_id]
748
+ @cross_process_encoding_key = Agent.config[:encoding_key]
749
+ @cross_process_encoding_bytes = get_bytes(@cross_process_encoding_key) unless @cross_process_encoding_key.nil?
750
+
751
+ @beacon_configuration = BeaconConfiguration.new
752
+ end
753
+
754
+ # Ruby 1.8.6 doesn't support the bytes method on strings.
755
+ def get_bytes(value)
756
+ return [] if value.nil?
757
+
758
+ bytes = []
759
+ value.each_byte do |b|
760
+ bytes << b
761
+ end
762
+ bytes
876
763
  end
877
-
764
+
878
765
  # Logs when we connect to the server, for debugging purposes
879
766
  # - makes sure we know if an agent has not connected
880
767
  def log_connection!(config_data)
881
- control.log! "Connected to NewRelic Service at #{@collector}"
882
- log.debug "Agent Run = #{@agent_id}."
883
- log.debug "Connection data = #{config_data.inspect}"
768
+ ::NewRelic::Agent.logger.debug "Connected to NewRelic Service at #{@service.collector.name}"
769
+ ::NewRelic::Agent.logger.debug "Agent Run = #{@service.agent_id}."
770
+ ::NewRelic::Agent.logger.debug "Connection data = #{config_data.inspect}"
771
+ if config_data['messages'] && config_data['messages'].any?
772
+ log_collector_messages(config_data['messages'])
773
+ end
774
+ end
775
+
776
+ def log_collector_messages(messages)
777
+ messages.each do |message|
778
+ ::NewRelic::Agent.logger.send(message['level'].downcase, message['message'])
779
+ end
884
780
  end
885
781
  end
886
782
  include Connect
@@ -909,14 +805,15 @@ module NewRelic
909
805
  def merge_data_from(data)
910
806
  metrics, transaction_traces, errors = data
911
807
  @stats_engine.merge_data(metrics) if metrics
912
- if transaction_traces
808
+ if transaction_traces && transaction_traces.respond_to?(:any?) &&
809
+ transaction_traces.any?
913
810
  if @traces
914
- @traces = @traces + transaction_traces
811
+ @traces += transaction_traces
915
812
  else
916
813
  @traces = transaction_traces
917
814
  end
918
815
  end
919
- if errors
816
+ if errors && errors.respond_to?(:any?) && errors.any?
920
817
  if @unsent_errors
921
818
  @unsent_errors = @unsent_errors + errors
922
819
  else
@@ -953,7 +850,7 @@ module NewRelic
953
850
  @connect_retry_period = should_keep_retrying?(options) ? 10 : 0
954
851
 
955
852
  sleep connect_retry_period
956
- log.debug "Connecting Process to New Relic: #$0"
853
+ ::NewRelic::Agent.logger.debug "Connecting Process to New Relic: #$0"
957
854
  query_server_for_configuration
958
855
  @connected_pid = $$
959
856
  @connected = true
@@ -1001,7 +898,9 @@ module NewRelic
1001
898
  # metric cache so we can save the collector some work by
1002
899
  # sending integers instead of strings
1003
900
  def fill_metric_id_cache(pairs_of_specs_and_ids)
1004
- Array(pairs_of_specs_and_ids).each do |metric_spec, metric_id|
901
+ Array(pairs_of_specs_and_ids).each do |metric_spec_hash, metric_id|
902
+ metric_spec = MetricSpec.new(metric_spec_hash['name'],
903
+ metric_spec_hash['scope'])
1005
904
  @metric_ids[metric_spec] = metric_id
1006
905
  end
1007
906
  end
@@ -1014,22 +913,19 @@ module NewRelic
1014
913
  NewRelic::Agent.instance.stats_engine.get_stats_no_scope('Supportability/invoke_remote').record_data_point(0.0)
1015
914
  NewRelic::Agent.instance.stats_engine.get_stats_no_scope('Supportability/invoke_remote/metric_data').record_data_point(0.0)
1016
915
  harvest_timeslice_data(now)
916
+ # In this version of the protocol
917
+ # we get back an assoc array of spec to id.
918
+ metric_specs_and_ids = []
1017
919
  begin
1018
- # In this version of the protocol, we get back an assoc array of spec to id.
1019
- metric_specs_and_ids = invoke_remote(:metric_data, @agent_id,
1020
- @last_harvest_time.to_f,
1021
- now.to_f,
1022
- @unsent_timeslice_data.values)
1023
-
1024
- rescue Timeout::Error
1025
- # assume that the data was received. chances are that it
1026
- # was. Also, lol.
1027
- metric_specs_and_ids = []
920
+ metric_specs_and_ids = @service.metric_data(@last_harvest_time.to_f,
921
+ now.to_f,
922
+ @unsent_timeslice_data.values)
923
+ rescue UnrecoverableServerException => e
924
+ ::NewRelic::Agent.logger.debug e.message
1028
925
  end
1029
-
1030
926
  fill_metric_id_cache(metric_specs_and_ids)
1031
927
 
1032
- log.debug "#{now}: sent #{@unsent_timeslice_data.length} timeslices (#{@agent_id}) in #{Time.now - now} seconds"
928
+ ::NewRelic::Agent.logger.debug "#{now}: sent #{@unsent_timeslice_data.length} timeslices (#{@service.agent_id}) in #{Time.now - now} seconds"
1033
929
 
1034
930
  # if we successfully invoked this web service, then clear the unsent message cache.
1035
931
  @unsent_timeslice_data = {}
@@ -1040,7 +936,7 @@ module NewRelic
1040
936
  # the transaction sampler, subject to the setting for slowest
1041
937
  # transaction threshold
1042
938
  def harvest_transaction_traces
1043
- @traces = @transaction_sampler.harvest(@traces, @slowest_transaction_threshold)
939
+ @traces = @transaction_sampler.harvest(@traces)
1044
940
  @traces
1045
941
  end
1046
942
 
@@ -1048,12 +944,14 @@ module NewRelic
1048
944
  # FIXME add the code to try to resend if our connection is down
1049
945
  sql_traces = @sql_sampler.harvest
1050
946
  unless sql_traces.empty?
1051
- log.debug "Sending (#{sql_traces.size}) sql traces"
947
+ ::NewRelic::Agent.logger.debug "Sending (#{sql_traces.size}) sql traces"
1052
948
  begin
1053
- response = invoke_remote :sql_trace_data, sql_traces
1054
- # log.debug "Sql trace response: #{response}"
1055
- rescue
1056
- @sql_sampler.merge sql_traces
949
+ @service.sql_trace_data(sql_traces)
950
+ rescue UnrecoverableServerException => e
951
+ ::NewRelic::Agent.logger.debug e.message
952
+ rescue => e
953
+ ::NewRelic::Agent.logger.debug "Remerging SQL traces after #{e.class.name}: #{e.message}"
954
+ @sql_sampler.merge sql_traces
1057
955
  end
1058
956
  end
1059
957
  end
@@ -1068,23 +966,22 @@ module NewRelic
1068
966
  harvest_transaction_traces
1069
967
  unless @traces.empty?
1070
968
  now = Time.now
1071
- log.debug "Sending (#{@traces.length}) transaction traces"
1072
-
969
+ ::NewRelic::Agent.logger.debug "Sending (#{@traces.length}) transaction traces"
970
+
1073
971
  begin
1074
972
  options = { :keep_backtraces => true }
1075
- options[:record_sql] = @record_sql unless @record_sql == :off
1076
- if @transaction_sampler.explain_enabled
1077
- options[:explain_sql] = @transaction_sampler.explain_threshold
973
+ if !(NewRelic::Agent::Database.record_sql_method == :off)
974
+ options[:record_sql] = NewRelic::Agent::Database.record_sql_method
1078
975
  end
1079
- traces = @traces.collect {|trace| trace.prepare_to_send(options)}
1080
- invoke_remote :transaction_sample_data, @agent_id, traces
1081
- rescue PostTooBigException
1082
- # we tried to send too much data, drop the first trace and
1083
- # try again
1084
- retry if @traces.shift
976
+ if Agent.config[:'transaction_tracer.explain_enabled']
977
+ options[:explain_sql] = Agent.config[:'transaction_tracer.explain_threshold']
978
+ end
979
+ traces = @traces.map {|trace| trace.prepare_to_send(options) }
980
+ @service.transaction_sample_data(traces)
981
+ ::NewRelic::Agent.logger.debug "Sent slowest sample (#{@service.agent_id}) in #{Time.now - now} seconds"
982
+ rescue UnrecoverableServerException => e
983
+ ::NewRelic::Agent.logger.debug e.message
1085
984
  end
1086
-
1087
- log.debug "Sent slowest sample (#{@agent_id}) in #{Time.now - now} seconds"
1088
985
  end
1089
986
 
1090
987
  # if we succeed sending this sample, then we don't need to keep
@@ -1093,6 +990,17 @@ module NewRelic
1093
990
  @traces = nil
1094
991
  end
1095
992
 
993
+ def harvest_and_send_thread_profile(disconnecting=false)
994
+ @thread_profiler.stop(true) if disconnecting
995
+
996
+ if @thread_profiler.finished?
997
+ profile = @thread_profiler.harvest
998
+
999
+ ::NewRelic::Agent.logger.debug "Sending thread profile #{profile.profile_id}"
1000
+ @service.profile_data(profile)
1001
+ end
1002
+ end
1003
+
1096
1004
  # Gets the collection of unsent errors from the error
1097
1005
  # collector. We pass back in an existing array of errors that
1098
1006
  # may be left over from a previous send
@@ -1108,12 +1016,11 @@ module NewRelic
1108
1016
  def harvest_and_send_errors
1109
1017
  harvest_errors
1110
1018
  if @unsent_errors && @unsent_errors.length > 0
1111
- log.debug "Sending #{@unsent_errors.length} errors"
1019
+ ::NewRelic::Agent.logger.debug "Sending #{@unsent_errors.length} errors"
1112
1020
  begin
1113
- invoke_remote :error_data, @agent_id, @unsent_errors
1114
- rescue PostTooBigException
1115
- @unsent_errors.shift
1116
- retry
1021
+ @service.error_data(@unsent_errors)
1022
+ rescue UnrecoverableServerException => e
1023
+ ::NewRelic::Agent.logger.debug e.message
1117
1024
  end
1118
1025
  # if the remote invocation fails, then we never clear
1119
1026
  # @unsent_errors, and therefore we can re-attempt to send on
@@ -1123,171 +1030,37 @@ module NewRelic
1123
1030
  end
1124
1031
  end
1125
1032
 
1126
- # This method handles the compression of the request body that
1127
- # we are going to send to the server
1128
- #
1129
- # We currently optimize for CPU here since we get roughly a 10x
1130
- # reduction in message size with this, and CPU overhead is at a
1131
- # premium. For extra-large posts, we use the higher compression
1132
- # since otherwise it actually errors out.
1133
- #
1134
- # We do not compress if content is smaller than 64kb. There are
1135
- # problems with bugs in Ruby in some versions that expose us
1136
- # to a risk of segfaults if we compress aggressively.
1137
- #
1138
- # medium payloads get fast compression, to save CPU
1139
- # big payloads get all the compression possible, to stay under
1140
- # the 2,000,000 byte post threshold
1141
- def compress_data(object)
1142
- dump = Marshal.dump(object)
1143
-
1144
- dump_size = dump.size
1033
+ def check_for_agent_commands
1034
+ commands = @service.get_agent_commands
1035
+ ::NewRelic::Agent.logger.debug "Received get_agent_commands = #{commands.inspect}"
1145
1036
 
1146
- return [dump, 'identity'] if dump_size < (64*1024)
1147
-
1148
- compressed_dump = Zlib::Deflate.deflate(dump, Zlib::DEFAULT_COMPRESSION)
1149
-
1150
- # this checks to make sure mongrel won't choke on big uploads
1151
- check_post_size(compressed_dump)
1152
-
1153
- [compressed_dump, 'deflate']
1154
- end
1155
-
1156
- # Raises a PostTooBigException if the post_string is longer
1157
- # than the limit configured in the control object
1158
- def check_post_size(post_string)
1159
- # TODO: define this as a config option on the server side
1160
- return if post_string.size < control.post_size_limit
1161
- log.warn "Tried to send too much data: #{post_string.size} bytes"
1162
- raise PostTooBigException
1163
- end
1164
-
1165
- # Posts to the specified server
1166
- #
1167
- # Options:
1168
- # - :uri => the path to request on the server (a misnomer of
1169
- # course)
1170
- # - :encoding => the encoding to pass to the server
1171
- # - :collector => a URI object that responds to the 'name' method
1172
- # and returns the name of the collector to
1173
- # contact
1174
- # - :data => the data to send as the body of the request
1175
- def send_request(opts)
1176
- request = Net::HTTP::Post.new(opts[:uri], 'CONTENT-ENCODING' => opts[:encoding], 'HOST' => opts[:collector].name)
1177
- request['user-agent'] = user_agent
1178
- request.content_type = "application/octet-stream"
1179
- request.body = opts[:data]
1180
-
1181
- log.debug "Connect to #{opts[:collector]}#{opts[:uri]}"
1182
-
1183
- response = nil
1184
- http = control.http_connection(collector)
1185
- http.read_timeout = nil
1186
- begin
1187
- NewRelic::TimerLib.timeout(@request_timeout) do
1188
- response = http.request(request)
1189
- end
1190
- rescue Timeout::Error
1191
- log.warn "Timed out trying to post data to New Relic (timeout = #{@request_timeout} seconds)" unless @request_timeout < 30
1192
- raise
1193
- end
1194
- if response.is_a? Net::HTTPServiceUnavailable
1195
- raise NewRelic::Agent::ServerConnectionException, "Service unavailable (#{response.code}): #{response.message}"
1196
- elsif response.is_a? Net::HTTPGatewayTimeOut
1197
- log.debug("Timed out getting response: #{response.message}")
1198
- raise Timeout::Error, response.message
1199
- elsif response.is_a? Net::HTTPRequestEntityTooLarge
1200
- raise PostTooBigException
1201
- elsif !(response.is_a? Net::HTTPSuccess)
1202
- raise NewRelic::Agent::ServerConnectionException, "Unexpected response from server (#{response.code}): #{response.message}"
1203
- end
1204
- response
1205
- end
1206
-
1207
- # Decompresses the response from the server, if it is gzip
1208
- # encoded, otherwise returns it verbatim
1209
- def decompress_response(response)
1210
- if response['content-encoding'] != 'gzip'
1211
- log.debug "Uncompressed content returned"
1212
- return response.body
1037
+ @thread_profiler.respond_to_commands(commands) do |command_id, error|
1038
+ @service.agent_command_results(command_id, error)
1213
1039
  end
1214
- log.debug "Decompressing return value"
1215
- i = Zlib::GzipReader.new(StringIO.new(response.body))
1216
- i.read
1217
- end
1218
-
1219
- # unmarshals the response and raises it if it is an exception,
1220
- # so we can handle it in nonlocally
1221
- def check_for_exception(response)
1222
- dump = decompress_response(response)
1223
- value = Marshal.load(dump)
1224
- raise value if value.is_a? Exception
1225
- value
1226
- end
1227
-
1228
- # The path on the server that we should post our data to
1229
- def remote_method_uri(method)
1230
- uri = "/agent_listener/#{PROTOCOL_VERSION}/#{control.license_key}/#{method}"
1231
- uri << "?run_id=#{@agent_id}" if @agent_id
1232
- uri
1233
- end
1234
-
1235
- # Sets the user agent for connections to the server, to
1236
- # conform with the HTTP spec and allow for debugging. Includes
1237
- # the ruby version and also zlib version if available since
1238
- # that may cause corrupt compression if there is a problem.
1239
- def user_agent
1240
- ruby_description = ''
1241
- # note the trailing space!
1242
- ruby_description << "(ruby #{::RUBY_VERSION} #{::RUBY_PLATFORM}) " if defined?(::RUBY_VERSION) && defined?(::RUBY_PLATFORM)
1243
- zlib_version = ''
1244
- zlib_version << "zlib/#{Zlib.zlib_version}" if defined?(::Zlib) && Zlib.respond_to?(:zlib_version)
1245
- "NewRelic-RubyAgent/#{NewRelic::VERSION::STRING} #{ruby_description}#{zlib_version}"
1246
1040
  end
1247
1041
 
1248
- # send a message via post to the actual server. This attempts
1249
- # to automatically compress the data via zlib if it is large
1250
- # enough to be worth compressing, and handles any errors the
1251
- # server may return
1252
- def invoke_remote(method, *args)
1042
+ def transmit_data(disconnecting=false)
1253
1043
  now = Time.now
1254
- #determines whether to zip the data or send plain
1255
- post_data, encoding = compress_data(args)
1256
-
1257
- response = send_request({:uri => remote_method_uri(method), :encoding => encoding, :collector => collector, :data => post_data})
1258
-
1259
- # raises the right exception if the remote server tells it to die
1260
- return check_for_exception(response)
1261
- rescue NewRelic::Agent::ForceRestartException => e
1262
- log.info e.message
1263
- raise
1264
- rescue SystemCallError, SocketError => e
1265
- # These include Errno connection errors
1266
- raise NewRelic::Agent::ServerConnectionException, "Recoverable error connecting to the server: #{e}"
1267
- ensure
1268
- NewRelic::Agent.instance.stats_engine.get_stats_no_scope('Supportability/invoke_remote').record_data_point((Time.now - now).to_f)
1269
- NewRelic::Agent.instance.stats_engine.get_stats_no_scope('Supportability/invoke_remote/' + method.to_s).record_data_point((Time.now - now).to_f)
1270
- end
1271
-
1272
- def save_or_transmit_data
1273
- if NewRelic::DataSerialization.should_send_data?
1274
- log.debug "Sending data to New Relic Service"
1275
- NewRelic::Agent.load_data unless NewRelic::Control.instance.disable_serialization?
1276
- harvest_and_send_errors
1277
- harvest_and_send_slowest_sample
1278
- harvest_and_send_slowest_sql
1279
- harvest_and_send_timeslice_data
1280
- else
1281
- log.debug "Serializing agent data to disk"
1282
- NewRelic::Agent.save_data
1283
- end
1044
+ ::NewRelic::Agent.logger.debug "Sending data to New Relic Service"
1045
+ harvest_and_send_errors
1046
+ harvest_and_send_slowest_sample
1047
+ harvest_and_send_slowest_sql
1048
+ harvest_and_send_timeslice_data
1049
+ harvest_and_send_thread_profile(disconnecting)
1050
+
1051
+ check_for_agent_commands
1284
1052
  rescue => e
1285
- NewRelic::Control.instance.disable_serialization = true
1286
- NewRelic::Control.instance.log.warn("Disabling serialization: #{e.message}")
1287
1053
  retry_count ||= 0
1288
1054
  retry_count += 1
1289
- retry unless retry_count > 1
1055
+ if retry_count <= 1
1056
+ ::NewRelic::Agent.logger.debug "retrying transmit_data after #{e}"
1057
+ retry
1058
+ end
1290
1059
  raise e
1060
+ ensure
1061
+ NewRelic::Agent::Database.close_connections unless forked?
1062
+ @stats_engine.get_stats_no_scope('Supportability/Harvest') \
1063
+ .record_data_point((Time.now - now).to_f)
1291
1064
  end
1292
1065
 
1293
1066
  # This method contacts the server to send remaining data and
@@ -1300,19 +1073,21 @@ module NewRelic
1300
1073
  def graceful_disconnect
1301
1074
  if @connected
1302
1075
  begin
1303
- @request_timeout = 10
1304
- save_or_transmit_data
1305
- if @connected_pid == $$
1306
- log.debug "Sending New Relic service agent run shutdown message"
1307
- invoke_remote :shutdown, @agent_id, Time.now.to_f
1076
+ @service.request_timeout = 10
1077
+ transmit_data(true)
1078
+
1079
+ if @connected_pid == $$ && !@service.kind_of?(NewRelic::Agent::NewRelicService)
1080
+ ::NewRelic::Agent.logger.debug "Sending New Relic service agent run shutdown message"
1081
+ @service.shutdown(Time.now.to_f)
1308
1082
  else
1309
- log.debug "This agent connected from parent process #{@connected_pid}--not sending shutdown"
1083
+ ::NewRelic::Agent.logger.debug "This agent connected from parent process #{@connected_pid}--not sending shutdown"
1310
1084
  end
1311
- log.debug "Graceful disconnect complete"
1312
- rescue Timeout::Error, StandardError
1085
+ ::NewRelic::Agent.logger.debug "Graceful disconnect complete"
1086
+ rescue Timeout::Error, StandardError => e
1087
+ ::NewRelic::Agent.logger.debug "Error when disconnecting #{e.class.name}: #{e.message}"
1313
1088
  end
1314
1089
  else
1315
- log.debug "Bypassing graceful disconnect - agent not connected"
1090
+ ::NewRelic::Agent.logger.debug "Bypassing graceful disconnect - agent not connected"
1316
1091
  end
1317
1092
  end
1318
1093
  end