ghazel-newrelic_rpm 3.4.0.2 → 3.5.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (231) hide show
  1. data/.gitignore +21 -0
  2. data/.project +23 -0
  3. data/.travis.yml +9 -0
  4. data/CHANGELOG +180 -1
  5. data/GUIDELINES_FOR_CONTRIBUTING.md +73 -0
  6. data/Gemfile +16 -0
  7. data/InstallationNotes.md +15 -0
  8. data/LICENSE +1 -1
  9. data/{README.rdoc → README.md} +71 -55
  10. data/Rakefile +54 -0
  11. data/config.dot +290 -0
  12. data/config/database.yml +5 -0
  13. data/init.rb +38 -0
  14. data/lib/new_relic/agent.rb +9 -4
  15. data/lib/new_relic/agent/agent.rb +189 -230
  16. data/lib/new_relic/agent/beacon_configuration.rb +34 -48
  17. data/lib/new_relic/agent/browser_monitoring.rb +108 -61
  18. data/lib/new_relic/agent/busy_calculator.rb +12 -4
  19. data/lib/new_relic/agent/configuration.rb +49 -0
  20. data/lib/new_relic/agent/configuration/defaults.rb +89 -0
  21. data/lib/new_relic/agent/configuration/environment_source.rb +56 -0
  22. data/lib/new_relic/agent/configuration/manager.rb +116 -0
  23. data/lib/new_relic/agent/configuration/server_source.rb +27 -0
  24. data/lib/new_relic/agent/configuration/yaml_source.rb +61 -0
  25. data/lib/new_relic/agent/database.rb +37 -22
  26. data/lib/new_relic/agent/error_collector.rb +47 -43
  27. data/lib/new_relic/agent/instrumentation/active_record.rb +1 -5
  28. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +27 -6
  29. data/lib/new_relic/agent/instrumentation/data_mapper.rb +2 -10
  30. data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +1 -1
  31. data/lib/new_relic/agent/instrumentation/memcache.rb +2 -2
  32. data/lib/new_relic/agent/instrumentation/metric_frame.rb +4 -14
  33. data/lib/new_relic/agent/instrumentation/passenger_instrumentation.rb +4 -18
  34. data/lib/new_relic/agent/instrumentation/rack.rb +1 -1
  35. data/lib/new_relic/agent/instrumentation/rails/action_controller.rb +3 -3
  36. data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +2 -2
  37. data/lib/new_relic/agent/instrumentation/rails3/errors.rb +5 -1
  38. data/lib/new_relic/agent/instrumentation/resque.rb +1 -1
  39. data/lib/new_relic/agent/instrumentation/sinatra.rb +14 -10
  40. data/lib/new_relic/agent/instrumentation/unicorn_instrumentation.rb +4 -3
  41. data/lib/new_relic/agent/method_tracer.rb +5 -1
  42. data/lib/new_relic/agent/new_relic_service.rb +231 -61
  43. data/lib/new_relic/agent/pipe_channel_manager.rb +37 -23
  44. data/lib/new_relic/agent/pipe_service.rb +5 -1
  45. data/lib/new_relic/agent/samplers/delayed_job_sampler.rb +2 -5
  46. data/lib/new_relic/agent/samplers/memory_sampler.rb +2 -2
  47. data/lib/new_relic/agent/sql_sampler.rb +44 -68
  48. data/lib/new_relic/agent/stats_engine/gc_profiler.rb +40 -24
  49. data/lib/new_relic/agent/stats_engine/metric_stats.rb +89 -14
  50. data/lib/new_relic/agent/stats_engine/samplers.rb +7 -3
  51. data/lib/new_relic/agent/stats_engine/transactions.rb +19 -11
  52. data/lib/new_relic/agent/thread.rb +27 -0
  53. data/lib/new_relic/agent/thread_profiler.rb +295 -0
  54. data/lib/new_relic/agent/transaction_info.rb +24 -4
  55. data/lib/new_relic/agent/transaction_sample_builder.rb +11 -11
  56. data/lib/new_relic/agent/transaction_sampler.rb +51 -61
  57. data/lib/new_relic/agent/worker_loop.rb +29 -15
  58. data/lib/new_relic/collection_helper.rb +1 -1
  59. data/lib/new_relic/commands/deployments.rb +19 -10
  60. data/lib/new_relic/control.rb +0 -1
  61. data/lib/new_relic/control/class_methods.rb +2 -3
  62. data/lib/new_relic/control/frameworks/rails.rb +24 -18
  63. data/lib/new_relic/control/frameworks/rails3.rb +18 -1
  64. data/lib/new_relic/control/frameworks/ruby.rb +2 -2
  65. data/lib/new_relic/control/instance_methods.rb +36 -53
  66. data/lib/new_relic/control/logging_methods.rb +5 -23
  67. data/lib/new_relic/control/server_methods.rb +11 -13
  68. data/lib/new_relic/delayed_job_injection.rb +1 -1
  69. data/lib/new_relic/helper.rb +13 -0
  70. data/lib/new_relic/language_support.rb +19 -22
  71. data/lib/new_relic/local_environment.rb +2 -3
  72. data/lib/new_relic/metric_data.rb +10 -2
  73. data/lib/new_relic/metric_spec.rb +6 -2
  74. data/lib/new_relic/noticed_error.rb +24 -9
  75. data/lib/new_relic/rack.rb +4 -0
  76. data/lib/new_relic/rack/browser_monitoring.rb +28 -10
  77. data/lib/new_relic/rack/developer_mode.rb +3 -0
  78. data/lib/new_relic/rack/error_collector.rb +56 -0
  79. data/lib/new_relic/transaction_sample.rb +23 -13
  80. data/lib/new_relic/transaction_sample/segment.rb +13 -15
  81. data/lib/new_relic/version.rb +3 -3
  82. data/lib/tasks/tests.rake +8 -8
  83. data/newrelic.yml +15 -32
  84. data/newrelic_rpm.gemspec +158 -38
  85. data/newrelic_rpm.gemspec.erb +55 -0
  86. data/test/config/newrelic.yml +3 -2
  87. data/test/intentional_fail.rb +10 -0
  88. data/test/multiverse/.gitignore +10 -0
  89. data/test/multiverse/README.md +90 -0
  90. data/test/multiverse/Rakefile +17 -0
  91. data/test/multiverse/lib/multiverse/color.rb +13 -0
  92. data/test/multiverse/lib/multiverse/envfile.rb +66 -0
  93. data/test/multiverse/lib/multiverse/environment.rb +16 -0
  94. data/test/multiverse/lib/multiverse/output_collector.rb +29 -0
  95. data/test/multiverse/lib/multiverse/runner.rb +44 -0
  96. data/test/multiverse/lib/multiverse/suite.rb +162 -0
  97. data/test/multiverse/script/run_one +3 -0
  98. data/test/multiverse/script/runner +9 -0
  99. data/test/multiverse/suites/active_record/Envfile +13 -0
  100. data/test/multiverse/suites/active_record/ar_method_aliasing.rb +94 -0
  101. data/test/multiverse/suites/active_record/config/newrelic.yml +22 -0
  102. data/test/multiverse/suites/active_record/encoding_test.rb +26 -0
  103. data/test/multiverse/suites/agent_only/Envfile +3 -0
  104. data/test/multiverse/suites/agent_only/config/newrelic.yml +22 -0
  105. data/test/multiverse/suites/agent_only/http_response_code_test.rb +53 -0
  106. data/test/multiverse/suites/agent_only/marshaling_test.rb +109 -0
  107. data/test/multiverse/suites/agent_only/method_visibility_test.rb +98 -0
  108. data/test/multiverse/suites/agent_only/pipe_manager_test.rb +33 -0
  109. data/test/multiverse/suites/agent_only/service_timeout_test.rb +29 -0
  110. data/test/multiverse/suites/agent_only/test_trace_method_with_punctuation.rb +30 -0
  111. data/test/multiverse/suites/agent_only/test_trace_transaction_with_punctuation.rb +32 -0
  112. data/test/multiverse/suites/agent_only/thread_profiling_test.rb +80 -0
  113. data/test/multiverse/suites/datamapper/Envfile +8 -0
  114. data/test/multiverse/suites/datamapper/config/newrelic.yml +22 -0
  115. data/test/multiverse/suites/datamapper/encoding_test.rb +36 -0
  116. data/test/multiverse/suites/monitor_mode_false/Envfile +2 -0
  117. data/test/multiverse/suites/monitor_mode_false/config/newrelic.yml +25 -0
  118. data/test/multiverse/suites/monitor_mode_false/no_dns_resolv.rb +29 -0
  119. data/test/multiverse/suites/no_load/Envfile +2 -0
  120. data/test/multiverse/suites/no_load/config/newrelic.yml +23 -0
  121. data/test/multiverse/suites/no_load/start_up_test.rb +14 -0
  122. data/test/multiverse/suites/rails_3_error_tracing/Envfile +15 -0
  123. data/test/multiverse/suites/rails_3_error_tracing/config/newrelic.yml +165 -0
  124. data/test/multiverse/suites/rails_3_error_tracing/error_tracing_test.rb +236 -0
  125. data/test/multiverse/suites/rails_3_gc/Envfile +8 -0
  126. data/test/multiverse/suites/rails_3_gc/config/newrelic.yml +167 -0
  127. data/test/multiverse/suites/rails_3_gc/instrumentation_test.rb +92 -0
  128. data/test/multiverse/suites/rails_3_queue_time/Envfile +15 -0
  129. data/test/multiverse/suites/rails_3_queue_time/config/newrelic.yml +165 -0
  130. data/test/multiverse/suites/rails_3_queue_time/queue_time_test.rb +75 -0
  131. data/test/multiverse/suites/rails_3_views/.gitignore +3 -0
  132. data/test/multiverse/suites/rails_3_views/Envfile +16 -0
  133. data/test/multiverse/suites/rails_3_views/app/views/foos/_foo.html.haml +1 -0
  134. data/test/multiverse/suites/rails_3_views/app/views/test/_a_partial.html.erb +1 -0
  135. data/test/multiverse/suites/rails_3_views/app/views/test/_mid_partial.html.erb +1 -0
  136. data/test/multiverse/suites/rails_3_views/app/views/test/_top_partial.html.erb +3 -0
  137. data/test/multiverse/suites/rails_3_views/app/views/test/deep_partial.html.erb +3 -0
  138. data/test/multiverse/suites/rails_3_views/app/views/test/haml_view.html.haml +6 -0
  139. data/test/multiverse/suites/rails_3_views/app/views/test/index.html.erb +4 -0
  140. data/test/multiverse/suites/rails_3_views/config/newrelic.yml +164 -0
  141. data/test/multiverse/suites/rails_3_views/view_instrumentation_test.rb +245 -0
  142. data/test/multiverse/suites/resque/Envfile +21 -0
  143. data/test/multiverse/suites/resque/config/newrelic.yml +22 -0
  144. data/test/multiverse/suites/resque/dump.rdb +0 -0
  145. data/test/multiverse/suites/resque/instrumentation_test.rb +73 -0
  146. data/test/multiverse/suites/rum_auto_instrumentation/Envfile +4 -0
  147. data/test/multiverse/suites/rum_auto_instrumentation/config/newrelic.yml +24 -0
  148. data/test/multiverse/suites/rum_auto_instrumentation/problem_response.html +422 -0
  149. data/test/multiverse/suites/rum_auto_instrumentation/responses/worst_case_small.html +5000 -0
  150. data/test/multiverse/suites/rum_auto_instrumentation/sanity_test.rb +115 -0
  151. data/test/multiverse/suites/sinatra/Envfile +13 -0
  152. data/test/multiverse/suites/sinatra/config/newrelic.yml +24 -0
  153. data/test/multiverse/suites/sinatra/sinatra_metric_explosion_test.rb +76 -0
  154. data/test/multiverse/suites/sinatra/sinatra_routes_test.rb +46 -0
  155. data/test/multiverse/test/multiverse_test.rb +55 -0
  156. data/test/multiverse/test/suite_examples/one/a/Envfile +3 -0
  157. data/test/multiverse/test/suite_examples/one/a/a_test.rb +11 -0
  158. data/test/multiverse/test/suite_examples/one/a/config/newrelic.yml +24 -0
  159. data/test/multiverse/test/suite_examples/one/b/Envfile +3 -0
  160. data/test/multiverse/test/suite_examples/one/b/b_test.rb +11 -0
  161. data/test/multiverse/test/suite_examples/one/b/config/newrelic.yml +24 -0
  162. data/test/multiverse/test/suite_examples/three/a/Envfile +2 -0
  163. data/test/multiverse/test/suite_examples/three/a/fail_test.rb +6 -0
  164. data/test/multiverse/test/suite_examples/three/b/Envfile +2 -0
  165. data/test/multiverse/test/suite_examples/three/b/win_test.rb +6 -0
  166. data/test/multiverse/test/suite_examples/two/a/Envfile +1 -0
  167. data/test/multiverse/test/suite_examples/two/a/fail_test.rb +6 -0
  168. data/test/new_relic/agent/agent/connect_test.rb +134 -164
  169. data/test/new_relic/agent/agent/start_test.rb +111 -81
  170. data/test/new_relic/agent/agent/start_worker_thread_test.rb +6 -33
  171. data/test/new_relic/agent/agent_test.rb +88 -9
  172. data/test/new_relic/agent/agent_test_controller.rb +1 -1
  173. data/test/new_relic/agent/agent_test_controller_test.rb +42 -10
  174. data/test/new_relic/agent/beacon_configuration_test.rb +63 -67
  175. data/test/new_relic/agent/browser_monitoring_test.rb +150 -79
  176. data/test/new_relic/agent/configuration/environment_source_test.rb +74 -0
  177. data/test/new_relic/agent/configuration/manager_test.rb +149 -0
  178. data/test/new_relic/agent/configuration/server_source_test.rb +45 -0
  179. data/test/new_relic/agent/configuration/yaml_source_test.rb +56 -0
  180. data/test/new_relic/agent/error_collector/notice_error_test.rb +63 -50
  181. data/test/new_relic/agent/error_collector_test.rb +22 -12
  182. data/test/new_relic/agent/instrumentation/active_record_instrumentation_test.rb +21 -11
  183. data/test/new_relic/agent/instrumentation/metric_frame_test.rb +6 -0
  184. data/test/new_relic/agent/instrumentation/task_instrumentation_test.rb +2 -2
  185. data/test/new_relic/agent/method_tracer/class_methods/add_method_tracer_test.rb +5 -5
  186. data/test/new_relic/agent/method_tracer_test.rb +6 -6
  187. data/test/new_relic/agent/mock_scope_listener.rb +3 -0
  188. data/test/new_relic/agent/new_relic_service_test.rb +208 -23
  189. data/test/new_relic/agent/pipe_channel_manager_test.rb +34 -17
  190. data/test/new_relic/agent/rpm_agent_test.rb +27 -23
  191. data/test/new_relic/agent/sql_sampler_test.rb +81 -56
  192. data/test/new_relic/agent/stats_engine/metric_stats/harvest_test.rb +3 -20
  193. data/test/new_relic/agent/stats_engine/metric_stats_test.rb +12 -1
  194. data/test/new_relic/agent/stats_engine_test.rb +17 -8
  195. data/test/new_relic/agent/thread_profiler_test.rb +536 -0
  196. data/test/new_relic/agent/thread_test.rb +76 -0
  197. data/test/new_relic/agent/threaded_test.rb +65 -0
  198. data/test/new_relic/agent/transaction_info_test.rb +45 -4
  199. data/test/new_relic/agent/transaction_sample_builder_test.rb +8 -6
  200. data/test/new_relic/agent/transaction_sampler_test.rb +193 -204
  201. data/test/new_relic/agent/worker_loop_test.rb +20 -0
  202. data/test/new_relic/agent_test.rb +69 -41
  203. data/test/new_relic/collection_helper_test.rb +7 -8
  204. data/test/new_relic/command/deployments_test.rb +18 -2
  205. data/test/new_relic/control/frameworks/rails_test.rb +26 -0
  206. data/test/new_relic/control/logging_methods_test.rb +78 -52
  207. data/test/new_relic/control_test.rb +91 -129
  208. data/test/new_relic/fake_collector.rb +103 -31
  209. data/test/new_relic/fake_service.rb +8 -2
  210. data/test/new_relic/load_test.rb +13 -0
  211. data/test/new_relic/local_environment_test.rb +7 -10
  212. data/test/new_relic/metric_data_test.rb +45 -16
  213. data/test/new_relic/noticed_error_test.rb +14 -0
  214. data/test/new_relic/rack/browser_monitoring_test.rb +15 -9
  215. data/test/new_relic/rack/developer_mode_test.rb +13 -7
  216. data/test/new_relic/rack/error_collector_test.rb +74 -0
  217. data/test/new_relic/transaction_sample/segment_test.rb +23 -4
  218. data/test/new_relic/transaction_sample_test.rb +47 -2
  219. data/test/script/build_test_gem.sh +9 -3
  220. data/test/script/ci.sh +48 -21
  221. data/test/script/ci_multiverse_runner.sh +11 -11
  222. data/test/test_helper.rb +37 -18
  223. data/ui/helpers/developer_mode_helper.rb +21 -11
  224. data/ui/views/layouts/newrelic_default.rhtml +1 -0
  225. data/ui/views/newrelic/show_sample.rhtml +1 -1
  226. data/ui/views/newrelic/threads.rhtml +2 -10
  227. data/vendor/gems/metric_parser-0.1.0.pre1/.specification +116 -0
  228. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/servlet_init.rb +7 -0
  229. metadata +132 -58
  230. data/lib/new_relic/control/configuration.rb +0 -206
  231. data/test/new_relic/control/configuration_test.rb +0 -77
@@ -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,7 +2,7 @@ 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
@@ -26,7 +26,7 @@ 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
@@ -47,7 +47,7 @@ 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
@@ -96,7 +96,7 @@ 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
@@ -135,7 +135,7 @@ 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
@@ -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
@@ -2,7 +2,7 @@ DependencyDetection.defer do
2
2
  @name = :resque
3
3
 
4
4
  depends_on do
5
- defined?(::Resque::Job) && !NewRelic::Control.instance['disable_resque'] &&
5
+ defined?(::Resque::Job) && !NewRelic::Agent.config[:disable_resque] &&
6
6
  !NewRelic::LanguageSupport.using_version?('1.9.1')
7
7
  end
8
8
 
@@ -2,7 +2,7 @@ require 'new_relic/agent/instrumentation/controller_instrumentation'
2
2
 
3
3
  DependencyDetection.defer do
4
4
  @name = :sinatra
5
-
5
+
6
6
  depends_on do
7
7
  defined?(::Sinatra) && defined?(::Sinatra::Base) &&
8
8
  Sinatra::Base.private_method_defined?(:dispatch!)
@@ -34,14 +34,14 @@ module NewRelic
34
34
  # will all be tracked as separate actions.
35
35
  module Sinatra
36
36
  include ::NewRelic::Agent::Instrumentation::ControllerInstrumentation
37
-
37
+
38
38
  def dispatch_with_newrelic
39
39
  txn_name = NewRelic.transaction_name(self.class.routes, @request) do |pattern, keys, conditions|
40
40
  process_route(pattern, keys, conditions) do
41
41
  pattern.source
42
42
  end
43
43
  end
44
-
44
+
45
45
  perform_action_with_newrelic_trace(:category => :sinatra,
46
46
  :name => txn_name,
47
47
  :params => @request.params) do
@@ -51,26 +51,30 @@ module NewRelic
51
51
 
52
52
  module NewRelic
53
53
  extend self
54
-
54
+
55
55
  def http_verb(request)
56
56
  request.request_method if request.respond_to?(:request_method)
57
57
  end
58
-
58
+
59
59
  def transaction_name(routes, request)
60
60
  name = '(unknown)'
61
61
  verb = http_verb(request)
62
-
62
+
63
63
  Array(routes[verb]).each do |pattern, keys, conditions, block|
64
- if pattern = yield(pattern, keys, conditions)
65
- name = pattern
64
+ if route = yield(pattern, keys, conditions)
65
+ name = route
66
+ # it's important we short circuit here. Otherwise we risk
67
+ # applying conditions from lower priority routes which can
68
+ # break the action.
69
+ break
66
70
  end
67
71
  end
68
-
72
+
69
73
  name.gsub!(%r{^[/^]*(.*?)[/\$\?]*$}, '\1')
70
74
  if verb
71
75
  name = verb + ' ' + name
72
76
  end
73
-
77
+
74
78
  name
75
79
  end
76
80
  end
@@ -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
9
  NewRelic::Agent.logger.debug '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
@@ -481,9 +481,13 @@ module NewRelic
481
481
 
482
482
  traced_method = code_to_eval(method_name, metric_name_code, options)
483
483
 
484
+ visibility = NewRelic::Helper.instance_method_visibility self, method_name
485
+
484
486
  class_eval traced_method, __FILE__, __LINE__
485
487
  alias_method _untraced_method_name(method_name, metric_name_code), method_name
486
488
  alias_method method_name, _traced_method_name(method_name, metric_name_code)
489
+ send visibility, method_name
490
+ send visibility, _traced_method_name(method_name, metric_name_code)
487
491
  NewRelic::Control.instance.log.debug("Traced method: class = #{self.name},"+
488
492
  "method = #{method_name}, "+
489
493
  "metric = '#{metric_name_code}'")
@@ -493,7 +497,7 @@ module NewRelic
493
497
  # from when they were added, or else other tracers that were added to the same method
494
498
  # may get removed as well.
495
499
  def remove_method_tracer(method_name, metric_name_code) # :nodoc:
496
- return unless NewRelic::Control.instance.agent_enabled?
500
+ return unless Agent.config[:agent_enabled]
497
501
  if method_defined? "#{_traced_method_name(method_name, metric_name_code)}"
498
502
  alias_method method_name, "#{_untraced_method_name(method_name, metric_name_code)}"
499
503
  undef_method "#{_traced_method_name(method_name, metric_name_code)}"
@@ -1,10 +1,13 @@
1
+ require 'zlib'
2
+
1
3
  module NewRelic
2
4
  module Agent
3
5
  class NewRelicService
4
6
  # Specifies the version of the agent's communication protocol with
5
7
  # the NewRelic hosted site.
6
-
7
- PROTOCOL_VERSION = 8
8
+
9
+ PROTOCOL_VERSION = 10
10
+ # cf0d1ff1: v9 (tag 3.5.0)
8
11
  # 14105: v8 (tag 2.10.3)
9
12
  # (no v7)
10
13
  # 10379: v6 (not tagged)
@@ -12,20 +15,32 @@ module NewRelic
12
15
  # 2292: v4 (tag 2.3.6)
13
16
  # 1754: v3 (tag 2.3.0)
14
17
  # 534: v2 (shows up in 2.1.0, our first tag)
15
-
16
- attr_accessor :request_timeout
17
- attr_reader :collector
18
- attr_accessor :agent_id
19
-
20
- def initialize(license_key=control.license_key, collector=control.server)
21
- @license_key = license_key
18
+
19
+ attr_accessor :request_timeout, :agent_id
20
+ attr_reader :collector, :marshaller
21
+
22
+ def initialize(license_key=nil, collector=control.server)
23
+ @license_key = license_key || Agent.config[:license_key]
22
24
  @collector = collector
23
- @request_timeout = NewRelic::Control.instance.fetch('timeout', 2 * 60)
25
+ @request_timeout = Agent.config[:timeout]
26
+ load_marshaller
24
27
  end
25
-
28
+
29
+ def load_marshaller
30
+ if Agent.config[:marshaller] == :json
31
+ require 'json'
32
+ @marshaller = JsonMarshaller.new
33
+ else
34
+ @marshaller = PrubyMarshaller.new
35
+ end
36
+ rescue LoadError
37
+ @marshaller = PrubyMarshaller.new
38
+ end
39
+
26
40
  def connect(settings={})
27
- host = get_redirect_host
28
- @collector.name = host if host
41
+ if host = get_redirect_host
42
+ @collector = NewRelic::Control.instance.server_from_host(host)
43
+ end
29
44
  response = invoke_remote(:connect, settings)
30
45
  @agent_id = response['agent_run_id']
31
46
  response
@@ -36,14 +51,14 @@ module NewRelic
36
51
  end
37
52
 
38
53
  def shutdown(time)
39
- invoke_remote(:shutdown, @agent_id, time) if @agent_id
54
+ invoke_remote(:shutdown, @agent_id, time.to_i) if @agent_id
40
55
  end
41
56
 
42
57
  def metric_data(last_harvest_time, now, unsent_timeslice_data)
43
58
  invoke_remote(:metric_data, @agent_id, last_harvest_time, now,
44
59
  unsent_timeslice_data)
45
60
  end
46
-
61
+
47
62
  def error_data(unsent_errors)
48
63
  invoke_remote(:error_data, @agent_id, unsent_errors)
49
64
  end
@@ -56,50 +71,73 @@ module NewRelic
56
71
  invoke_remote(:sql_trace_data, sql_traces)
57
72
  end
58
73
 
74
+ def profile_data(profile)
75
+ invoke_remote(:profile_data, @agent_id, profile.to_compressed_array) || ''
76
+ end
77
+
78
+ def get_agent_commands
79
+ invoke_remote(:get_agent_commands, @agent_id)
80
+ end
81
+
82
+ def agent_command_results(command_id, error=nil)
83
+ results = {}
84
+ results["error"] = error unless error.nil?
85
+
86
+ invoke_remote(:agent_command_results, @agent_id, { command_id.to_s => results })
87
+ end
88
+
59
89
  private
60
-
90
+
61
91
  # A shorthand for NewRelic::Control.instance
62
92
  def control
63
93
  NewRelic::Control.instance
64
94
  end
65
-
95
+
66
96
  # Shorthand to the NewRelic::Agent.logger method
67
97
  def log
68
98
  NewRelic::Agent.logger
69
99
  end
70
-
100
+
71
101
  # The path on the server that we should post our data to
72
- def remote_method_uri(method)
102
+ def remote_method_uri(method, format='ruby')
103
+ params = {'run_id' => @agent_id, 'marshal_format' => format}
73
104
  uri = "/agent_listener/#{PROTOCOL_VERSION}/#{@license_key}/#{method}"
74
- uri << "?run_id=#{@agent_id}" if @agent_id
105
+ uri << '?' + params.map do |k,v|
106
+ next unless v
107
+ "#{k}=#{v}"
108
+ end.compact.join('&')
75
109
  uri
76
110
  end
77
-
111
+
78
112
  # send a message via post to the actual server. This attempts
79
113
  # to automatically compress the data via zlib if it is large
80
114
  # enough to be worth compressing, and handles any errors the
81
115
  # server may return
82
116
  def invoke_remote(method, *args)
83
117
  now = Time.now
84
- #determines whether to zip the data or send plain
85
- post_data, encoding = compress_data(args)
86
-
87
- response = send_request(:uri => remote_method_uri(method),
88
- :encoding => encoding,
89
- :collector => @collector,
90
- :data => post_data)
91
-
92
- # raises the right exception if the remote server tells it to die
93
- return check_for_exception(response)
118
+
119
+ data = @marshaller.dump(args)
120
+ check_post_size(data)
121
+ response = send_request(:data => data,
122
+ :uri => remote_method_uri(method,
123
+ @marshaller.format),
124
+ :encoding => @marshaller.encoding,
125
+ :collector => @collector)
126
+ @marshaller.load(decompress_response(response))
94
127
  rescue NewRelic::Agent::ForceRestartException => e
95
128
  log.info e.message
96
129
  raise
97
- rescue SystemCallError, SocketError => e
98
- # These include Errno connection errors
99
- raise NewRelic::Agent::ServerConnectionException, "Recoverable error connecting to the server: #{e}"
100
130
  ensure
101
- NewRelic::Agent.instance.stats_engine.get_stats_no_scope('Supportability/invoke_remote').record_data_point((Time.now - now).to_f)
102
- NewRelic::Agent.instance.stats_engine.get_stats_no_scope('Supportability/invoke_remote/' + method.to_s).record_data_point((Time.now - now).to_f)
131
+ record_supportability_metrics(method, now)
132
+ end
133
+
134
+ def record_supportability_metrics(method, now)
135
+ NewRelic::Agent.instance.stats_engine. \
136
+ get_stats_no_scope('Supportability/invoke_remote'). \
137
+ record_data_point((Time.now - now).to_f)
138
+ NewRelic::Agent.instance.stats_engine. \
139
+ get_stats_no_scope('Supportability/invoke_remote/' + method.to_s). \
140
+ record_data_point((Time.now - now).to_f)
103
141
  end
104
142
 
105
143
  # This method handles the compression of the request body that
@@ -118,11 +156,9 @@ module NewRelic
118
156
  # big payloads get all the compression possible, to stay under
119
157
  # the 2,000,000 byte post threshold
120
158
  def compress_data(object)
121
- dump = Marshal.dump(object)
159
+ dump = marshal_data(object)
122
160
 
123
- dump_size = dump.size
124
-
125
- return [dump, 'identity'] if dump_size < (64*1024)
161
+ return [dump, 'identity'] if dump.size < (64*1024)
126
162
 
127
163
  compressed_dump = Zlib::Deflate.deflate(dump, Zlib::DEFAULT_COMPRESSION)
128
164
 
@@ -132,13 +168,21 @@ module NewRelic
132
168
  [compressed_dump, 'deflate']
133
169
  end
134
170
 
135
- # Raises a PostTooBigException if the post_string is longer
171
+ def marshal_data(data)
172
+ NewRelic::LanguageSupport.with_cautious_gc do
173
+ Marshal.dump(data)
174
+ end
175
+ rescue => e
176
+ log.debug("#{e.class.name} : #{e.message} when marshalling #{object}")
177
+ raise
178
+ end
179
+
180
+ # Raises an UnrecoverableServerException if the post_string is longer
136
181
  # than the limit configured in the control object
137
182
  def check_post_size(post_string)
138
- # TODO: define this as a config option on the server side
139
- return if post_string.size < control.post_size_limit
140
- log.warn "Tried to send too much data: #{post_string.size} bytes"
141
- raise PostTooBigException
183
+ return if post_string.size < Agent.config[:post_size_limit]
184
+ log.debug "Tried to send too much data: #{post_string.size} bytes"
185
+ raise UnrecoverableServerException.new('413 Request Entity Too Large')
142
186
  end
143
187
 
144
188
  # Posts to the specified server
@@ -156,9 +200,9 @@ module NewRelic
156
200
  request['user-agent'] = user_agent
157
201
  request.content_type = "application/octet-stream"
158
202
  request.body = opts[:data]
159
-
203
+
160
204
  log.debug "Connect to #{opts[:collector]}#{opts[:uri]}"
161
-
205
+
162
206
  response = nil
163
207
  http = control.http_connection(@collector)
164
208
  http.read_timeout = nil
@@ -167,20 +211,27 @@ module NewRelic
167
211
  response = http.request(request)
168
212
  end
169
213
  rescue Timeout::Error
170
- log.warn "Timed out trying to post data to New Relic (timeout = #{@request_timeout} seconds)" unless @service.request_timeout < 30
214
+ log.warn "Timed out trying to post data to New Relic (timeout = #{@request_timeout} seconds)" unless @request_timeout < 30
171
215
  raise
172
216
  end
173
- if response.is_a? Net::HTTPServiceUnavailable
174
- raise NewRelic::Agent::ServerConnectionException, "Service unavailable (#{response.code}): #{response.message}"
217
+ if response.is_a? Net::HTTPUnauthorized
218
+ raise LicenseException, 'Invalid license key, please contact support@newrelic.com'
219
+ elsif response.is_a? Net::HTTPServiceUnavailable
220
+ raise ServerConnectionException, "Service unavailable (#{response.code}): #{response.message}"
175
221
  elsif response.is_a? Net::HTTPGatewayTimeOut
176
222
  log.debug("Timed out getting response: #{response.message}")
177
223
  raise Timeout::Error, response.message
178
224
  elsif response.is_a? Net::HTTPRequestEntityTooLarge
179
- raise PostTooBigException
225
+ raise UnrecoverableServerException, '413 Request Entity Too Large'
226
+ elsif response.is_a? Net::HTTPUnsupportedMediaType
227
+ raise UnrecoverableServerException, '415 Unsupported Media Type'
180
228
  elsif !(response.is_a? Net::HTTPSuccess)
181
- raise NewRelic::Agent::ServerConnectionException, "Unexpected response from server (#{response.code}): #{response.message}"
229
+ raise ServerConnectionException, "Unexpected response from server (#{response.code}): #{response.message}"
182
230
  end
183
231
  response
232
+ rescue SystemCallError, SocketError => e
233
+ # These include Errno connection errors
234
+ raise NewRelic::Agent::ServerConnectionException, "Recoverable error connecting to the server: #{e}"
184
235
  end
185
236
 
186
237
  # Decompresses the response from the server, if it is gzip
@@ -195,15 +246,6 @@ module NewRelic
195
246
  i.read
196
247
  end
197
248
 
198
- # unmarshals the response and raises it if it is an exception,
199
- # so we can handle it in nonlocally
200
- def check_for_exception(response)
201
- dump = decompress_response(response)
202
- value = Marshal.load(dump)
203
- raise value if value.is_a? Exception
204
- value
205
- end
206
-
207
249
  # Sets the user agent for connections to the server, to
208
250
  # conform with the HTTP spec and allow for debugging. Includes
209
251
  # the ruby version and also zlib version if available since
@@ -216,6 +258,134 @@ module NewRelic
216
258
  zlib_version << "zlib/#{Zlib.zlib_version}" if defined?(::Zlib) && Zlib.respond_to?(:zlib_version)
217
259
  "NewRelic-RubyAgent/#{NewRelic::VERSION::STRING} #{ruby_description}#{zlib_version}"
218
260
  end
261
+
262
+ class Marshaller
263
+ attr_reader :encoding
264
+
265
+ # This method handles the compression of the request body that
266
+ # we are going to send to the server
267
+ #
268
+ # We currently optimize for CPU here since we get roughly a 10x
269
+ # reduction in message size with this, and CPU overhead is at a
270
+ # premium. For extra-large posts, we use the higher compression
271
+ # since otherwise it actually errors out.
272
+ #
273
+ # We do not compress if content is smaller than 64kb. There are
274
+ # problems with bugs in Ruby in some versions that expose us
275
+ # to a risk of segfaults if we compress aggressively.
276
+ #
277
+ # medium payloads get fast compression, to save CPU
278
+ # big payloads get all the compression possible, to stay under
279
+ # the 2,000,000 byte post threshold
280
+ def compress(data, opts={})
281
+ if opts[:force] || data.size > 64 * 1024
282
+ data = Zlib::Deflate.deflate(data, Zlib::DEFAULT_COMPRESSION)
283
+ @encoding = 'deflate'
284
+ else
285
+ @encoding = 'identity'
286
+ end
287
+ data
288
+ end
289
+
290
+ def parsed_error(error)
291
+ error_class = error['error_type'].split('::') \
292
+ .inject(Module) {|mod,const| mod.const_get(const) }
293
+ error_class.new(error['message'])
294
+ rescue NameError
295
+ CollectorError.new("#{error['error_type']}: #{error['message']}")
296
+ end
297
+
298
+ protected
299
+
300
+ def prepare(data)
301
+ if data.respond_to?(:to_collector_array)
302
+ data.to_collector_array(self)
303
+ elsif data.kind_of?(Array)
304
+ data.map {|element| prepare(element) }
305
+ else
306
+ data
307
+ end
308
+ end
309
+
310
+ def return_value(data)
311
+ if data.respond_to?(:has_key?)
312
+ if data.has_key?('exception')
313
+ raise parsed_error(data['exception'])
314
+ elsif data.has_key?('return_value')
315
+ return data['return_value']
316
+ end
317
+ end
318
+ NewRelic::Agent.logger.debug("Unexpected response from collector: #{data}")
319
+ nil
320
+ end
321
+ end
322
+
323
+ # Primitive Ruby Object Notation which complies JSON format data strutures
324
+ class PrubyMarshaller < Marshaller
325
+ def initialize
326
+ NewRelic::Agent.logger.debug 'Using Pruby marshaller'
327
+ end
328
+
329
+ def dump(ruby)
330
+ NewRelic::LanguageSupport.with_cautious_gc do
331
+ compress(Marshal.dump(prepare(ruby)))
332
+ end
333
+ rescue => e
334
+ NewRelic::Agent.logger.debug("#{e.class.name} : #{e.message} when marshalling #{ruby.inspect}")
335
+ raise
336
+ end
337
+
338
+ def load(data)
339
+ return unless data && data != ''
340
+ NewRelic::LanguageSupport.with_cautious_gc do
341
+ return_value(Marshal.load(data))
342
+ end
343
+ rescue
344
+ NewRelic::Agent.logger.debug "Error encountered loading collector response: #{data}"
345
+ raise
346
+ end
347
+
348
+ def format
349
+ 'pruby'
350
+ end
351
+
352
+ def self.is_supported?
353
+ true
354
+ end
355
+ end
356
+
357
+ # Marshal collector protocol with JSON when available
358
+ class JsonMarshaller < Marshaller
359
+ def initialize
360
+ NewRelic::Agent.logger.debug 'Using JSON marshaller'
361
+ end
362
+
363
+ def dump(ruby)
364
+ compress(JSON.dump(prepare(ruby)))
365
+ end
366
+
367
+ def load(data)
368
+ return unless data && data != ''
369
+ return_value(JSON.load(data))
370
+ rescue
371
+ NewRelic::Agent.logger.debug "Error encountered loading collector response: #{data}"
372
+ raise
373
+ end
374
+
375
+ def encode_compress(data)
376
+ Base64.encode64(compress(JSON.dump(data), :force => true))
377
+ end
378
+
379
+ def format
380
+ 'json'
381
+ end
382
+
383
+ def self.is_supported?
384
+ RUBY_VERSION >= '1.9.2'
385
+ end
386
+ end
387
+
388
+ class CollectorError < StandardError; end
219
389
  end
220
390
  end
221
391
  end