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
@@ -10,7 +10,7 @@ module NewRelic
10
10
  HEROKU_QUEUE_HEADER = 'HTTP_X_HEROKU_QUEUE_WAIT_TIME'
11
11
  APP_HEADER = 'HTTP_X_APPLICATION_START'
12
12
 
13
- HEADER_REGEX = /([^\s\/,(t=)]+)? ?t=([0-9]+)/
13
+ HEADER_REGEX = /([^\s\/,(t=)]+)? ?t=([0-9\.]+)/
14
14
  SERVER_METRIC = 'WebFrontend/WebServer/'
15
15
  MIDDLEWARE_METRIC = 'Middleware/'
16
16
  # no individual queue metric - more than one queue?!
@@ -93,7 +93,7 @@ module NewRelic
93
93
  def get_matches_from_header(header, env)
94
94
  return [] if env.nil?
95
95
  get_matches(env[header]).map do |name, time|
96
- convert_to_name_time_pair(name, time)
96
+ convert_to_name_time_pair(name, time.sub('.', ''))
97
97
  end
98
98
  end
99
99
 
@@ -7,7 +7,7 @@ module NewRelic
7
7
  #
8
8
  # New Relic will instrument a #call method as if it were a controller
9
9
  # action, collecting transaction traces and errors. The middleware will
10
- # be identified only by it's class, so if you want to instrument multiple
10
+ # be identified only by its class, so if you want to instrument multiple
11
11
  # actions in a middleware, you need to use
12
12
  # NewRelic::Agent::Instrumentation::ControllerInstrumentation::ClassMethods#add_transaction_tracer
13
13
  #
@@ -2,13 +2,13 @@ DependencyDetection.defer do
2
2
  @name = :rails21_view
3
3
 
4
4
  depends_on do
5
- !NewRelic::Control.instance['disable_view_instrumentation'] &&
5
+ !NewRelic::Agent.config[:disable_view_instrumentation] &&
6
6
  defined?(ActionController) && defined?(ActionController::Base) && defined?(ActionView::PartialTemplate) && defined?(ActionView::Template) &&
7
7
  defined?(Rails::VERSION::STRING) && Rails::VERSION::STRING =~ /^2\.1\./ # Rails 2.1 &&
8
8
  end
9
9
 
10
10
  executes do
11
- NewRelic::Agent.logger.debug 'Installing Rails 2.1 View instrumentation'
11
+ ::NewRelic::Agent.logger.info 'Installing Rails 2.1 View instrumentation'
12
12
  end
13
13
 
14
14
  executes do
@@ -26,13 +26,13 @@ DependencyDetection.defer do
26
26
  @name = :old_rails_view
27
27
 
28
28
  depends_on do
29
- !NewRelic::Control.instance['disable_view_instrumentation'] &&
29
+ !NewRelic::Agent.config[:disable_view_instrumentation] &&
30
30
  defined?(ActionController) && defined?(ActionController::Base) &&
31
31
  defined?(Rails::VERSION::STRING) && Rails::VERSION::STRING =~ /^(1\.|2\.0)/ # Rails 1.* - 2.0
32
32
  end
33
33
 
34
34
  executes do
35
- NewRelic::Agent.logger.debug 'Installing Rails 1.* - 2.0 View instrumentation'
35
+ ::NewRelic::Agent.logger.info 'Installing Rails 1.* - 2.0 View instrumentation'
36
36
  end
37
37
 
38
38
  executes do
@@ -47,13 +47,13 @@ DependencyDetection.defer do
47
47
  @name = :rails23_view
48
48
 
49
49
  depends_on do
50
- !NewRelic::Control.instance['disable_view_instrumentation'] &&
50
+ !NewRelic::Agent.config[:disable_view_instrumentation] &&
51
51
  defined?(ActionView) && defined?(ActionView::Template) && defined?(ActionView::RenderablePartial) &&
52
52
  defined?(Rails::VERSION::STRING) && Rails::VERSION::STRING =~ /^2\.[23]/
53
53
  end
54
54
 
55
55
  executes do
56
- NewRelic::Agent.logger.debug 'Installing Rails 2.2 - 2.3 View instrumentation'
56
+ ::NewRelic::Agent.logger.info 'Installing Rails 2.2 - 2.3 View instrumentation'
57
57
  end
58
58
 
59
59
  executes do
@@ -78,7 +78,7 @@ DependencyDetection.defer do
78
78
  end
79
79
 
80
80
  executes do
81
- NewRelic::Agent.logger.debug 'Installing Rails 2 Controller instrumentation'
81
+ ::NewRelic::Agent.logger.info 'Installing Rails 2 Controller instrumentation'
82
82
  end
83
83
 
84
84
  executes do
@@ -6,7 +6,7 @@ DependencyDetection.defer do
6
6
  end
7
7
 
8
8
  executes do
9
- NewRelic::Agent.logger.debug 'Installing Rails ActionWebService instrumentation'
9
+ ::NewRelic::Agent.logger.info 'Installing Rails ActionWebService instrumentation'
10
10
  end
11
11
 
12
12
  executes do
@@ -10,7 +10,7 @@ DependencyDetection.defer do
10
10
  end
11
11
 
12
12
  executes do
13
- NewRelic::Agent.logger.debug 'Installing Rails 2 Error instrumentation'
13
+ ::NewRelic::Agent.logger.info 'Installing Rails 2 Error instrumentation'
14
14
  end
15
15
 
16
16
  executes do
@@ -78,7 +78,7 @@ DependencyDetection.defer do
78
78
  end
79
79
 
80
80
  executes do
81
- NewRelic::Agent.logger.debug 'Installing Rails 3 Controller instrumentation'
81
+ ::NewRelic::Agent.logger.info 'Installing Rails 3 Controller instrumentation'
82
82
  end
83
83
 
84
84
  executes do
@@ -96,11 +96,11 @@ DependencyDetection.defer do
96
96
  end
97
97
 
98
98
  depends_on do
99
- !NewRelic::Control.instance['disable_view_instrumentation']
99
+ !NewRelic::Agent.config[:disable_view_instrumentation]
100
100
  end
101
101
 
102
102
  executes do
103
- NewRelic::Agent.logger.debug 'Installing Rails 3.0 view instrumentation'
103
+ ::NewRelic::Agent.logger.info 'Installing Rails 3.0 view instrumentation'
104
104
  end
105
105
 
106
106
  executes do
@@ -135,11 +135,11 @@ DependencyDetection.defer do
135
135
  end
136
136
 
137
137
  depends_on do
138
- !NewRelic::Control.instance['disable_view_instrumentation']
138
+ !NewRelic::Agent.config[:disable_view_instrumentation]
139
139
  end
140
140
 
141
141
  executes do
142
- NewRelic::Agent.logger.debug 'Installing Rails 3.1/3.2 view instrumentation'
142
+ ::NewRelic::Agent.logger.info 'Installing Rails 3.1/3.2 view instrumentation'
143
143
  end
144
144
 
145
145
  executes do
@@ -6,7 +6,11 @@ module NewRelic
6
6
  def newrelic_notice_error(exception, custom_params = {})
7
7
  filtered_params = (respond_to? :filter_parameters) ? filter_parameters(params) : params
8
8
  filtered_params.merge!(custom_params)
9
- NewRelic::Agent.agent.error_collector.notice_error(exception, request, newrelic_metric_path, filtered_params)
9
+ NewRelic::Agent::Instrumentation::MetricFrame.notice_error( \
10
+ exception, \
11
+ :request => request, \
12
+ :metric => newrelic_metric_path, \
13
+ :custom_params => filtered_params)
10
14
  end
11
15
  end
12
16
  end
@@ -26,7 +30,7 @@ DependencyDetection.defer do
26
30
  end
27
31
 
28
32
  executes do
29
- NewRelic::Agent.logger.debug 'Installing Rails3 Error instrumentation'
33
+ ::NewRelic::Agent.logger.info 'Installing Rails3 Error instrumentation'
30
34
  end
31
35
 
32
36
  executes do
@@ -0,0 +1,81 @@
1
+ DependencyDetection.defer do
2
+ @name = :resque
3
+
4
+ depends_on do
5
+ defined?(::Resque::Job) && !NewRelic::Agent.config[:disable_resque] &&
6
+ !NewRelic::LanguageSupport.using_version?('1.9.1')
7
+ end
8
+
9
+ executes do
10
+ ::NewRelic::Agent.logger.info 'Installing Resque instrumentation'
11
+ end
12
+
13
+ executes do
14
+ # == Resque Instrumentation
15
+ #
16
+ # Installs a hook to ensure the agent starts manually when the worker
17
+ # starts and also adds the tracer to the process method which executes
18
+ # in the forked task.
19
+
20
+ module Resque
21
+ module Plugins
22
+ module NewRelicInstrumentation
23
+ include NewRelic::Agent::Instrumentation::ControllerInstrumentation
24
+
25
+ def around_perform_with_monitoring(*args)
26
+ begin
27
+ perform_action_with_newrelic_trace(:name => 'perform',
28
+ :class_name => self.name,
29
+ :category => 'OtherTransaction/ResqueJob') do
30
+ yield(*args)
31
+ end
32
+ ensure
33
+ NewRelic::Agent.shutdown if NewRelic::LanguageSupport.can_fork?
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ module NewRelic
41
+ module Agent
42
+ module Instrumentation
43
+ module ResqueInstrumentationInstaller
44
+ def payload_class
45
+ klass = super
46
+ klass.instance_eval do
47
+ extend ::Resque::Plugins::NewRelicInstrumentation
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ ::Resque::Job.class_eval do
56
+ def self.new(*args)
57
+ super(*args).extend NewRelic::Agent::Instrumentation::ResqueInstrumentationInstaller
58
+ end
59
+ end
60
+
61
+ if NewRelic::LanguageSupport.can_fork?
62
+ ::Resque.before_first_fork do
63
+ NewRelic::Agent.manual_start(:dispatcher => :resque,
64
+ :sync_startup => true,
65
+ :start_channel_listener => true,
66
+ :report_instance_busy => false)
67
+ end
68
+
69
+ ::Resque.before_fork do |job|
70
+ NewRelic::Agent.register_report_channel(job.object_id)
71
+ end
72
+
73
+ ::Resque.after_fork do |job|
74
+ NewRelic::Agent.after_fork(:report_to_channel => job.object_id)
75
+ end
76
+ end
77
+ end
78
+ end
79
+
80
+ # call this now so it is memoized before potentially forking worker processes
81
+ NewRelic::LanguageSupport.can_fork?
@@ -1,13 +1,15 @@
1
1
  require 'new_relic/agent/instrumentation/controller_instrumentation'
2
2
 
3
3
  DependencyDetection.defer do
4
+ @name = :sinatra
5
+
4
6
  depends_on do
5
7
  defined?(::Sinatra) && defined?(::Sinatra::Base) && !defined?(::WeaselDiesel) &&
6
8
  Sinatra::Base.private_method_defined?(:dispatch!)
7
9
  end
8
10
 
9
11
  executes do
10
- NewRelic::Agent.logger.debug 'Installing Sinatra instrumentation'
12
+ ::NewRelic::Agent.logger.info 'Installing Sinatra instrumentation'
11
13
  end
12
14
 
13
15
  executes do
@@ -32,14 +34,14 @@ module NewRelic
32
34
  # will all be tracked as separate actions.
33
35
  module Sinatra
34
36
  include ::NewRelic::Agent::Instrumentation::ControllerInstrumentation
35
-
37
+
36
38
  def dispatch_with_newrelic
37
39
  txn_name = NewRelic.transaction_name(self.class.routes, @request) do |pattern, keys, conditions|
38
40
  process_route(pattern, keys, conditions) do
39
41
  pattern.source
40
42
  end
41
43
  end
42
-
44
+
43
45
  perform_action_with_newrelic_trace(:category => :sinatra,
44
46
  :name => txn_name,
45
47
  :params => @request.params) do
@@ -47,28 +49,37 @@ module NewRelic
47
49
  end
48
50
  end
49
51
 
52
+ # Define Request Header accessor for Sinatra
53
+ def newrelic_request_headers
54
+ request.env
55
+ end
56
+
50
57
  module NewRelic
51
58
  extend self
52
-
59
+
53
60
  def http_verb(request)
54
61
  request.request_method if request.respond_to?(:request_method)
55
62
  end
56
-
63
+
57
64
  def transaction_name(routes, request)
58
65
  name = '(unknown)'
59
66
  verb = http_verb(request)
60
-
67
+
61
68
  Array(routes[verb]).each do |pattern, keys, conditions, block|
62
- if pattern = yield(pattern, keys, conditions)
63
- name = pattern
69
+ if route = yield(pattern, keys, conditions)
70
+ name = route
71
+ # it's important we short circuit here. Otherwise we risk
72
+ # applying conditions from lower priority routes which can
73
+ # break the action.
74
+ break
64
75
  end
65
76
  end
66
-
77
+
67
78
  name.gsub!(%r{^[/^]*(.*?)[/\$\?]*$}, '\1')
68
79
  if verb
69
80
  name = verb + ' ' + name
70
81
  end
71
-
82
+
72
83
  name
73
84
  end
74
85
  end
@@ -6,7 +6,7 @@ DependencyDetection.defer do
6
6
  end
7
7
 
8
8
  executes do
9
- NewRelic::Agent.logger.debug 'Installing Rails Sunspot instrumentation'
9
+ ::NewRelic::Agent.logger.info 'Installing Rails Sunspot instrumentation'
10
10
  end
11
11
 
12
12
  executes do
@@ -4,15 +4,16 @@ DependencyDetection.defer do
4
4
  depends_on do
5
5
  defined?(::Unicorn) && defined?(::Unicorn::HttpServer)
6
6
  end
7
-
7
+
8
8
  executes do
9
- NewRelic::Agent.logger.debug 'Installing Unicorn instrumentation'
9
+ ::NewRelic::Agent.logger.info 'Installing Unicorn instrumentation'
10
+ ::NewRelic::Agent.logger.info 'Detected Unicorn, please see additional documentation: https://newrelic.com/docs/troubleshooting/im-using-unicorn-and-i-dont-see-any-data'
10
11
  end
11
-
12
+
12
13
  executes do
13
14
  Unicorn::HttpServer.class_eval do
14
15
  old_worker_loop = instance_method(:worker_loop)
15
- define_method(:worker_loop) do | worker |
16
+ define_method(:worker_loop) do |worker|
16
17
  NewRelic::Agent.after_fork(:force_reconnect => true)
17
18
  old_worker_loop.bind(self).call(worker)
18
19
  end
@@ -175,13 +175,11 @@ module NewRelic
175
175
  end
176
176
 
177
177
  # helper for logging errors to the newrelic_agent.log
178
- # properly. Logs the error at error level, and includes a
179
- # backtrace if we're running at debug level
178
+ # properly. Logs the error at error level
180
179
  def log_errors(code_area, metric)
181
180
  yield
182
181
  rescue => e
183
- NewRelic::Control.instance.log.error("Caught exception in #{code_area}. Metric name = #{metric}, exception = #{e}")
184
- NewRelic::Control.instance.log.error(e.backtrace.join("\n"))
182
+ ::NewRelic::Agent.logger.error("Caught exception in #{code_area}. Metric name = #{metric}", e)
185
183
  end
186
184
 
187
185
  # provides the header for our traced execution scoped
@@ -327,7 +325,7 @@ module NewRelic
327
325
  # anything if the method doesn't exist.
328
326
  def newrelic_method_exists?(method_name)
329
327
  exists = method_defined?(method_name) || private_method_defined?(method_name)
330
- NewRelic::Control.instance.log.warn("Did not trace #{self.name}##{method_name} because that method does not exist") unless exists
328
+ ::NewRelic::Agent.logger.error("Did not trace #{self.name}##{method_name} because that method does not exist") unless exists
331
329
  exists
332
330
  end
333
331
 
@@ -337,7 +335,7 @@ module NewRelic
337
335
  # to help with debugging custom instrumentation.
338
336
  def traced_method_exists?(method_name, metric_name_code)
339
337
  exists = method_defined?(_traced_method_name(method_name, metric_name_code))
340
- NewRelic::Control.instance.log.warn("Attempt to trace a method twice with the same metric: Method = #{method_name}, Metric Name = #{metric_name_code}") if exists
338
+ ::NewRelic::Agent.logger.error("Attempt to trace a method twice with the same metric: Method = #{method_name}, Metric Name = #{metric_name_code}") if exists
341
339
  exists
342
340
  end
343
341
 
@@ -481,10 +479,14 @@ module NewRelic
481
479
 
482
480
  traced_method = code_to_eval(method_name, metric_name_code, options)
483
481
 
482
+ visibility = NewRelic::Helper.instance_method_visibility self, method_name
483
+
484
484
  class_eval traced_method, __FILE__, __LINE__
485
485
  alias_method _untraced_method_name(method_name, metric_name_code), method_name
486
486
  alias_method method_name, _traced_method_name(method_name, metric_name_code)
487
- NewRelic::Control.instance.log.debug("Traced method: class = #{self.name},"+
487
+ send visibility, method_name
488
+ send visibility, _traced_method_name(method_name, metric_name_code)
489
+ ::NewRelic::Agent.logger.debug("Traced method: class = #{self.name},"+
488
490
  "method = #{method_name}, "+
489
491
  "metric = '#{metric_name_code}'")
490
492
  end
@@ -493,11 +495,11 @@ module NewRelic
493
495
  # from when they were added, or else other tracers that were added to the same method
494
496
  # may get removed as well.
495
497
  def remove_method_tracer(method_name, metric_name_code) # :nodoc:
496
- return unless NewRelic::Control.instance.agent_enabled?
498
+ return unless Agent.config[:agent_enabled]
497
499
  if method_defined? "#{_traced_method_name(method_name, metric_name_code)}"
498
500
  alias_method method_name, "#{_untraced_method_name(method_name, metric_name_code)}"
499
501
  undef_method "#{_traced_method_name(method_name, metric_name_code)}"
500
- NewRelic::Control.instance.log.debug("removed method tracer #{method_name} #{metric_name_code}\n")
502
+ ::NewRelic::Agent.logger.debug("removed method tracer #{method_name} #{metric_name_code}\n")
501
503
  else
502
504
  raise "No tracer for '#{metric_name_code}' on method '#{method_name}'"
503
505
  end
@@ -0,0 +1,379 @@
1
+ require 'zlib'
2
+ require 'new_relic/agent/audit_logger'
3
+
4
+ module NewRelic
5
+ module Agent
6
+ class NewRelicService
7
+ # Specifies the version of the agent's communication protocol with
8
+ # the NewRelic hosted site.
9
+
10
+ PROTOCOL_VERSION = 10
11
+ # cf0d1ff1: v9 (tag 3.5.0)
12
+ # 14105: v8 (tag 2.10.3)
13
+ # (no v7)
14
+ # 10379: v6 (not tagged)
15
+ # 4078: v5 (tag 2.5.4)
16
+ # 2292: v4 (tag 2.3.6)
17
+ # 1754: v3 (tag 2.3.0)
18
+ # 534: v2 (shows up in 2.1.0, our first tag)
19
+
20
+ attr_accessor :request_timeout, :agent_id
21
+ attr_reader :collector, :marshaller
22
+
23
+ def initialize(license_key=nil, collector=control.server)
24
+ @license_key = license_key || Agent.config[:license_key]
25
+ @collector = collector
26
+ @request_timeout = Agent.config[:timeout]
27
+
28
+ @audit_logger = ::NewRelic::Agent::AuditLogger.new(Agent.config)
29
+ Agent.config.register_callback(:'audit_log.enabled') do |enabled|
30
+ @audit_logger.enabled = enabled
31
+ end
32
+
33
+ Agent.config.register_callback(:marshaller) do |marshaller|
34
+ begin
35
+ if marshaller == 'json'
36
+ require 'json'
37
+ @marshaller = JsonMarshaller.new
38
+ else
39
+ @marshaller = PrubyMarshaller.new
40
+ end
41
+ rescue LoadError
42
+ @marshaller = PrubyMarshaller.new
43
+ end
44
+ end
45
+ end
46
+
47
+ def connect(settings={})
48
+ if host = get_redirect_host
49
+ @collector = NewRelic::Control.instance.server_from_host(host)
50
+ end
51
+ response = invoke_remote(:connect, settings)
52
+ @agent_id = response['agent_run_id']
53
+ response
54
+ end
55
+
56
+ def get_redirect_host
57
+ invoke_remote(:get_redirect_host)
58
+ end
59
+
60
+ def shutdown(time)
61
+ invoke_remote(:shutdown, @agent_id, time.to_i) if @agent_id
62
+ end
63
+
64
+ def metric_data(last_harvest_time, now, unsent_timeslice_data)
65
+ invoke_remote(:metric_data, @agent_id, last_harvest_time, now,
66
+ unsent_timeslice_data)
67
+ end
68
+
69
+ def error_data(unsent_errors)
70
+ invoke_remote(:error_data, @agent_id, unsent_errors)
71
+ end
72
+
73
+ def transaction_sample_data(traces)
74
+ invoke_remote(:transaction_sample_data, @agent_id, traces)
75
+ end
76
+
77
+ def sql_trace_data(sql_traces)
78
+ invoke_remote(:sql_trace_data, sql_traces)
79
+ end
80
+
81
+ def profile_data(profile)
82
+ invoke_remote(:profile_data, @agent_id, profile) || ''
83
+ end
84
+
85
+ def get_agent_commands
86
+ invoke_remote(:get_agent_commands, @agent_id)
87
+ end
88
+
89
+ def agent_command_results(command_id, error=nil)
90
+ results = {}
91
+ results["error"] = error unless error.nil?
92
+
93
+ invoke_remote(:agent_command_results, @agent_id, { command_id.to_s => results })
94
+ end
95
+
96
+ # We do not compress if content is smaller than 64kb. There are
97
+ # problems with bugs in Ruby in some versions that expose us
98
+ # to a risk of segfaults if we compress aggressively.
99
+ def compress_request_if_needed(data)
100
+ encoding = 'identity'
101
+ if data.size > 64 * 1024
102
+ data = Encoders::Compressed.encode(data)
103
+ encoding = 'deflate'
104
+ end
105
+ check_post_size(data)
106
+ [data, encoding]
107
+ end
108
+
109
+ private
110
+
111
+ # A shorthand for NewRelic::Control.instance
112
+ def control
113
+ NewRelic::Control.instance
114
+ end
115
+
116
+ # The path on the server that we should post our data to
117
+ def remote_method_uri(method, format='ruby')
118
+ params = {'run_id' => @agent_id, 'marshal_format' => format}
119
+ uri = "/agent_listener/#{PROTOCOL_VERSION}/#{@license_key}/#{method}"
120
+ uri << '?' + params.map do |k,v|
121
+ next unless v
122
+ "#{k}=#{v}"
123
+ end.compact.join('&')
124
+ uri
125
+ end
126
+
127
+ # send a message via post to the actual server. This attempts
128
+ # to automatically compress the data via zlib if it is large
129
+ # enough to be worth compressing, and handles any errors the
130
+ # server may return
131
+ def invoke_remote(method, *args)
132
+ now = Time.now
133
+
134
+ data = @marshaller.dump(args)
135
+ data, encoding = compress_request_if_needed(data)
136
+
137
+ uri = remote_method_uri(method, @marshaller.format)
138
+ full_uri = "#{@collector}#{uri}"
139
+
140
+ @audit_logger.log_request(full_uri, args, @marshaller)
141
+ response = send_request(:data => data,
142
+ :uri => uri,
143
+ :encoding => encoding,
144
+ :collector => @collector)
145
+ @marshaller.load(decompress_response(response))
146
+ rescue NewRelic::Agent::ForceRestartException => e
147
+ ::NewRelic::Agent.logger.debug e.message
148
+ raise
149
+ ensure
150
+ record_supportability_metrics(method, now)
151
+ end
152
+
153
+ def record_supportability_metrics(method, now)
154
+ NewRelic::Agent.instance.stats_engine. \
155
+ get_stats_no_scope('Supportability/invoke_remote'). \
156
+ record_data_point((Time.now - now).to_f)
157
+ NewRelic::Agent.instance.stats_engine. \
158
+ get_stats_no_scope('Supportability/invoke_remote/' + method.to_s). \
159
+ record_data_point((Time.now - now).to_f)
160
+ end
161
+
162
+ # Raises an UnrecoverableServerException if the post_string is longer
163
+ # than the limit configured in the control object
164
+ def check_post_size(post_string)
165
+ return if post_string.size < Agent.config[:post_size_limit]
166
+ ::NewRelic::Agent.logger.debug "Tried to send too much data: #{post_string.size} bytes"
167
+ raise UnrecoverableServerException.new('413 Request Entity Too Large')
168
+ end
169
+
170
+ # Posts to the specified server
171
+ #
172
+ # Options:
173
+ # - :uri => the path to request on the server (a misnomer of
174
+ # course)
175
+ # - :encoding => the encoding to pass to the server
176
+ # - :collector => a URI object that responds to the 'name' method
177
+ # and returns the name of the collector to
178
+ # contact
179
+ # - :data => the data to send as the body of the request
180
+ def send_request(opts)
181
+ request = Net::HTTP::Post.new(opts[:uri], 'CONTENT-ENCODING' => opts[:encoding], 'HOST' => opts[:collector].name)
182
+ request['user-agent'] = user_agent
183
+ request.content_type = "application/octet-stream"
184
+ request.body = opts[:data]
185
+
186
+ ::NewRelic::Agent.logger.debug "Connect to #{opts[:collector]}#{opts[:uri]}"
187
+
188
+ response = nil
189
+ http = control.http_connection(@collector)
190
+ http.read_timeout = nil
191
+ begin
192
+ NewRelic::TimerLib.timeout(@request_timeout) do
193
+ response = http.request(request)
194
+ end
195
+ rescue Timeout::Error
196
+ ::NewRelic::Agent.logger.warn "Timed out trying to post data to New Relic (timeout = #{@request_timeout} seconds)" unless @request_timeout < 30
197
+ raise
198
+ end
199
+ if response.is_a? Net::HTTPUnauthorized
200
+ raise LicenseException, 'Invalid license key, please contact support@newrelic.com'
201
+ elsif response.is_a? Net::HTTPServiceUnavailable
202
+ raise ServerConnectionException, "Service unavailable (#{response.code}): #{response.message}"
203
+ elsif response.is_a? Net::HTTPGatewayTimeOut
204
+ ::NewRelic::Agent.logger.warn("Timed out getting response: #{response.message}")
205
+ raise Timeout::Error, response.message
206
+ elsif response.is_a? Net::HTTPRequestEntityTooLarge
207
+ raise UnrecoverableServerException, '413 Request Entity Too Large'
208
+ elsif response.is_a? Net::HTTPUnsupportedMediaType
209
+ raise UnrecoverableServerException, '415 Unsupported Media Type'
210
+ elsif !(response.is_a? Net::HTTPSuccess)
211
+ raise ServerConnectionException, "Unexpected response from server (#{response.code}): #{response.message}"
212
+ end
213
+ response
214
+ rescue SystemCallError, SocketError => e
215
+ # These include Errno connection errors
216
+ raise NewRelic::Agent::ServerConnectionException, "Recoverable error connecting to the server: #{e}"
217
+ end
218
+
219
+ # Decompresses the response from the server, if it is gzip
220
+ # encoded, otherwise returns it verbatim
221
+ def decompress_response(response)
222
+ if response['content-encoding'] != 'gzip'
223
+ ::NewRelic::Agent.logger.debug "Uncompressed content returned"
224
+ return response.body
225
+ end
226
+ ::NewRelic::Agent.logger.debug "Decompressing return value"
227
+ i = Zlib::GzipReader.new(StringIO.new(response.body))
228
+ i.read
229
+ end
230
+
231
+ # Sets the user agent for connections to the server, to
232
+ # conform with the HTTP spec and allow for debugging. Includes
233
+ # the ruby version and also zlib version if available since
234
+ # that may cause corrupt compression if there is a problem.
235
+ def user_agent
236
+ ruby_description = ''
237
+ # note the trailing space!
238
+ ruby_description << "(ruby #{::RUBY_VERSION} #{::RUBY_PLATFORM}) " if defined?(::RUBY_VERSION) && defined?(::RUBY_PLATFORM)
239
+ zlib_version = ''
240
+ zlib_version << "zlib/#{Zlib.zlib_version}" if defined?(::Zlib) && Zlib.respond_to?(:zlib_version)
241
+ "NewRelic-RubyAgent/#{NewRelic::VERSION::STRING} #{ruby_description}#{zlib_version}"
242
+ end
243
+
244
+ module Encoders
245
+ module Identity
246
+ def self.encode(data)
247
+ data
248
+ end
249
+ end
250
+
251
+ module Compressed
252
+ def self.encode(data)
253
+ Zlib::Deflate.deflate(data, Zlib::DEFAULT_COMPRESSION)
254
+ end
255
+ end
256
+
257
+ module Base64CompressedJSON
258
+ def self.encode(data)
259
+ Base64.encode64(Compressed.encode(JSON.dump(data)))
260
+ end
261
+ end
262
+ end
263
+
264
+ class Marshaller
265
+ def parsed_error(error)
266
+ error_class = error['error_type'].split('::') \
267
+ .inject(Module) {|mod,const| mod.const_get(const) }
268
+ error_class.new(error['message'])
269
+ rescue NameError
270
+ CollectorError.new("#{error['error_type']}: #{error['message']}")
271
+ end
272
+
273
+ def prepare(data, options={})
274
+ encoder = options[:encoder] || default_encoder
275
+ if data.respond_to?(:to_collector_array)
276
+ data.to_collector_array(encoder)
277
+ elsif data.kind_of?(Array)
278
+ data.map { |element| prepare(element, options) }
279
+ else
280
+ data
281
+ end
282
+ end
283
+
284
+ def default_encoder
285
+ Encoders::Identity
286
+ end
287
+
288
+ def self.human_readable?
289
+ false
290
+ end
291
+
292
+ protected
293
+
294
+ def return_value(data)
295
+ if data.respond_to?(:has_key?)
296
+ if data.has_key?('exception')
297
+ raise parsed_error(data['exception'])
298
+ elsif data.has_key?('return_value')
299
+ return data['return_value']
300
+ end
301
+ end
302
+ ::NewRelic::Agent.logger.debug("Unexpected response from collector: #{data}")
303
+ nil
304
+ end
305
+ end
306
+
307
+ # Primitive Ruby Object Notation which complies JSON format data strutures
308
+ class PrubyMarshaller < Marshaller
309
+ def initialize
310
+ ::NewRelic::Agent.logger.debug 'Using Pruby marshaller'
311
+ end
312
+
313
+ def dump(ruby, opts={})
314
+ NewRelic::LanguageSupport.with_cautious_gc do
315
+ Marshal.dump(prepare(ruby, opts))
316
+ end
317
+ rescue => e
318
+ ::NewRelic::Agent.logger.debug("#{e.class.name} : #{e.message} when marshalling #{ruby.inspect}")
319
+ raise
320
+ end
321
+
322
+ def load(data)
323
+ return unless data && data != ''
324
+ NewRelic::LanguageSupport.with_cautious_gc do
325
+ return_value(Marshal.load(data))
326
+ end
327
+ rescue
328
+ ::NewRelic::Agent.logger.debug "Error encountered loading collector response: #{data}"
329
+ raise
330
+ end
331
+
332
+ def format
333
+ 'pruby'
334
+ end
335
+
336
+ def self.is_supported?
337
+ true
338
+ end
339
+ end
340
+
341
+ # Marshal collector protocol with JSON when available
342
+ class JsonMarshaller < Marshaller
343
+ def initialize
344
+ ::NewRelic::Agent.logger.debug 'Using JSON marshaller'
345
+ end
346
+
347
+ def dump(ruby, opts={})
348
+ JSON.dump(prepare(ruby, opts))
349
+ end
350
+
351
+ def load(data)
352
+ return unless data && data != ''
353
+ return_value(JSON.load(data))
354
+ rescue
355
+ ::NewRelic::Agent.logger.debug "Error encountered loading collector response: #{data}"
356
+ raise
357
+ end
358
+
359
+ def default_encoder
360
+ Encoders::Base64CompressedJSON
361
+ end
362
+
363
+ def format
364
+ 'json'
365
+ end
366
+
367
+ def self.is_supported?
368
+ RUBY_VERSION >= '1.9.2'
369
+ end
370
+
371
+ def self.human_readable?
372
+ true # for some definitions of 'human'
373
+ end
374
+ end
375
+
376
+ class CollectorError < StandardError; end
377
+ end
378
+ end
379
+ end