dolores_rpm 3.2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (257) hide show
  1. data/CHANGELOG +559 -0
  2. data/LICENSE +64 -0
  3. data/README.rdoc +179 -0
  4. data/bin/mongrel_rpm +33 -0
  5. data/bin/newrelic +13 -0
  6. data/bin/newrelic_cmd +5 -0
  7. data/cert/cacert.pem +118 -0
  8. data/cert/oldsite.pem +28 -0
  9. data/cert/site.pem +27 -0
  10. data/dolores_rpm-3.3.4.fork.gem +0 -0
  11. data/install.rb +9 -0
  12. data/lib/conditional_vendored_dependency_detection.rb +3 -0
  13. data/lib/conditional_vendored_metric_parser.rb +5 -0
  14. data/lib/new_relic/agent/agent.rb +1311 -0
  15. data/lib/new_relic/agent/beacon_configuration.rb +110 -0
  16. data/lib/new_relic/agent/browser_monitoring.rb +102 -0
  17. data/lib/new_relic/agent/busy_calculator.rb +99 -0
  18. data/lib/new_relic/agent/chained_call.rb +13 -0
  19. data/lib/new_relic/agent/database.rb +203 -0
  20. data/lib/new_relic/agent/error_collector.rb +251 -0
  21. data/lib/new_relic/agent/instrumentation/active_merchant.rb +27 -0
  22. data/lib/new_relic/agent/instrumentation/acts_as_solr.rb +68 -0
  23. data/lib/new_relic/agent/instrumentation/authlogic.rb +19 -0
  24. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +424 -0
  25. data/lib/new_relic/agent/instrumentation/data_mapper.rb +57 -0
  26. data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +52 -0
  27. data/lib/new_relic/agent/instrumentation/memcache.rb +80 -0
  28. data/lib/new_relic/agent/instrumentation/merb/controller.rb +41 -0
  29. data/lib/new_relic/agent/instrumentation/merb/errors.rb +29 -0
  30. data/lib/new_relic/agent/instrumentation/metric_frame/pop.rb +80 -0
  31. data/lib/new_relic/agent/instrumentation/metric_frame.rb +332 -0
  32. data/lib/new_relic/agent/instrumentation/net.rb +29 -0
  33. data/lib/new_relic/agent/instrumentation/passenger_instrumentation.rb +36 -0
  34. data/lib/new_relic/agent/instrumentation/queue_time.rb +210 -0
  35. data/lib/new_relic/agent/instrumentation/rack.rb +98 -0
  36. data/lib/new_relic/agent/instrumentation/rails/action_controller.rb +114 -0
  37. data/lib/new_relic/agent/instrumentation/rails/action_web_service.rb +42 -0
  38. data/lib/new_relic/agent/instrumentation/rails/active_record_instrumentation.rb +115 -0
  39. data/lib/new_relic/agent/instrumentation/rails/errors.rb +42 -0
  40. data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +118 -0
  41. data/lib/new_relic/agent/instrumentation/rails3/active_record_instrumentation.rb +122 -0
  42. data/lib/new_relic/agent/instrumentation/rails3/errors.rb +37 -0
  43. data/lib/new_relic/agent/instrumentation/sinatra.rb +58 -0
  44. data/lib/new_relic/agent/instrumentation/sunspot.rb +29 -0
  45. data/lib/new_relic/agent/instrumentation/unicorn_instrumentation.rb +21 -0
  46. data/lib/new_relic/agent/instrumentation.rb +9 -0
  47. data/lib/new_relic/agent/method_tracer.rb +528 -0
  48. data/lib/new_relic/agent/sampler.rb +50 -0
  49. data/lib/new_relic/agent/samplers/cpu_sampler.rb +58 -0
  50. data/lib/new_relic/agent/samplers/delayed_job_lock_sampler.rb +40 -0
  51. data/lib/new_relic/agent/samplers/memory_sampler.rb +144 -0
  52. data/lib/new_relic/agent/samplers/object_sampler.rb +26 -0
  53. data/lib/new_relic/agent/shim_agent.rb +29 -0
  54. data/lib/new_relic/agent/sql_sampler.rb +267 -0
  55. data/lib/new_relic/agent/stats_engine/metric_stats.rb +187 -0
  56. data/lib/new_relic/agent/stats_engine/samplers.rb +95 -0
  57. data/lib/new_relic/agent/stats_engine/transactions.rb +208 -0
  58. data/lib/new_relic/agent/stats_engine.rb +25 -0
  59. data/lib/new_relic/agent/transaction_sample_builder.rb +101 -0
  60. data/lib/new_relic/agent/transaction_sampler.rb +397 -0
  61. data/lib/new_relic/agent/worker_loop.rb +89 -0
  62. data/lib/new_relic/agent.rb +454 -0
  63. data/lib/new_relic/collection_helper.rb +75 -0
  64. data/lib/new_relic/command.rb +85 -0
  65. data/lib/new_relic/commands/deployments.rb +105 -0
  66. data/lib/new_relic/commands/install.rb +80 -0
  67. data/lib/new_relic/control/class_methods.rb +53 -0
  68. data/lib/new_relic/control/configuration.rb +202 -0
  69. data/lib/new_relic/control/frameworks/external.rb +16 -0
  70. data/lib/new_relic/control/frameworks/merb.rb +31 -0
  71. data/lib/new_relic/control/frameworks/rails.rb +164 -0
  72. data/lib/new_relic/control/frameworks/rails3.rb +75 -0
  73. data/lib/new_relic/control/frameworks/ruby.rb +42 -0
  74. data/lib/new_relic/control/frameworks/sinatra.rb +20 -0
  75. data/lib/new_relic/control/frameworks.rb +10 -0
  76. data/lib/new_relic/control/instance_methods.rb +179 -0
  77. data/lib/new_relic/control/instrumentation.rb +100 -0
  78. data/lib/new_relic/control/logging_methods.rb +143 -0
  79. data/lib/new_relic/control/profiling.rb +25 -0
  80. data/lib/new_relic/control/server_methods.rb +114 -0
  81. data/lib/new_relic/control.rb +46 -0
  82. data/lib/new_relic/data_serialization.rb +157 -0
  83. data/lib/new_relic/delayed_job_injection.rb +46 -0
  84. data/lib/new_relic/language_support.rb +69 -0
  85. data/lib/new_relic/local_environment.rb +414 -0
  86. data/lib/new_relic/merbtasks.rb +6 -0
  87. data/lib/new_relic/metric_data.rb +51 -0
  88. data/lib/new_relic/metric_spec.rb +75 -0
  89. data/lib/new_relic/metrics.rb +9 -0
  90. data/lib/new_relic/noticed_error.rb +24 -0
  91. data/lib/new_relic/rack/browser_monitoring.rb +68 -0
  92. data/lib/new_relic/rack/developer_mode.rb +268 -0
  93. data/lib/new_relic/recipes.rb +73 -0
  94. data/lib/new_relic/stats.rb +388 -0
  95. data/lib/new_relic/timer_lib.rb +27 -0
  96. data/lib/new_relic/transaction_analysis/segment_summary.rb +49 -0
  97. data/lib/new_relic/transaction_analysis.rb +77 -0
  98. data/lib/new_relic/transaction_sample/composite_segment.rb +27 -0
  99. data/lib/new_relic/transaction_sample/fake_segment.rb +9 -0
  100. data/lib/new_relic/transaction_sample/segment.rb +201 -0
  101. data/lib/new_relic/transaction_sample/summary_segment.rb +21 -0
  102. data/lib/new_relic/transaction_sample.rb +245 -0
  103. data/lib/new_relic/url_rule.rb +14 -0
  104. data/lib/new_relic/version.rb +55 -0
  105. data/lib/newrelic_rpm.rb +49 -0
  106. data/lib/tasks/all.rb +4 -0
  107. data/lib/tasks/install.rake +7 -0
  108. data/lib/tasks/tests.rake +19 -0
  109. data/newrelic.yml +265 -0
  110. data/recipes/newrelic.rb +6 -0
  111. data/test/active_record_fixtures.rb +77 -0
  112. data/test/config/newrelic.yml +48 -0
  113. data/test/config/test_control.rb +48 -0
  114. data/test/new_relic/agent/agent/connect_test.rb +410 -0
  115. data/test/new_relic/agent/agent/start_test.rb +255 -0
  116. data/test/new_relic/agent/agent/start_worker_thread_test.rb +153 -0
  117. data/test/new_relic/agent/agent_test.rb +139 -0
  118. data/test/new_relic/agent/agent_test_controller.rb +77 -0
  119. data/test/new_relic/agent/agent_test_controller_test.rb +363 -0
  120. data/test/new_relic/agent/apdex_from_server_test.rb +9 -0
  121. data/test/new_relic/agent/beacon_configuration_test.rb +108 -0
  122. data/test/new_relic/agent/browser_monitoring_test.rb +278 -0
  123. data/test/new_relic/agent/busy_calculator_test.rb +81 -0
  124. data/test/new_relic/agent/database_test.rb +162 -0
  125. data/test/new_relic/agent/error_collector/notice_error_test.rb +257 -0
  126. data/test/new_relic/agent/error_collector_test.rb +175 -0
  127. data/test/new_relic/agent/instrumentation/active_record_instrumentation_test.rb +538 -0
  128. data/test/new_relic/agent/instrumentation/controller_instrumentation_test.rb +36 -0
  129. data/test/new_relic/agent/instrumentation/instrumentation_test.rb +11 -0
  130. data/test/new_relic/agent/instrumentation/metric_frame/pop_test.rb +172 -0
  131. data/test/new_relic/agent/instrumentation/metric_frame_test.rb +50 -0
  132. data/test/new_relic/agent/instrumentation/net_instrumentation_test.rb +84 -0
  133. data/test/new_relic/agent/instrumentation/queue_time_test.rb +387 -0
  134. data/test/new_relic/agent/instrumentation/rack_test.rb +35 -0
  135. data/test/new_relic/agent/instrumentation/task_instrumentation_test.rb +184 -0
  136. data/test/new_relic/agent/memcache_instrumentation_test.rb +143 -0
  137. data/test/new_relic/agent/method_tracer/class_methods/add_method_tracer_test.rb +164 -0
  138. data/test/new_relic/agent/method_tracer/instance_methods/trace_execution_scoped_test.rb +234 -0
  139. data/test/new_relic/agent/method_tracer_test.rb +386 -0
  140. data/test/new_relic/agent/mock_scope_listener.rb +23 -0
  141. data/test/new_relic/agent/rpm_agent_test.rb +149 -0
  142. data/test/new_relic/agent/sampler_test.rb +19 -0
  143. data/test/new_relic/agent/shim_agent_test.rb +20 -0
  144. data/test/new_relic/agent/sql_sampler_test.rb +160 -0
  145. data/test/new_relic/agent/stats_engine/metric_stats/harvest_test.rb +150 -0
  146. data/test/new_relic/agent/stats_engine/metric_stats_test.rb +82 -0
  147. data/test/new_relic/agent/stats_engine/samplers_test.rb +99 -0
  148. data/test/new_relic/agent/stats_engine_test.rb +185 -0
  149. data/test/new_relic/agent/transaction_sample_builder_test.rb +195 -0
  150. data/test/new_relic/agent/transaction_sampler_test.rb +955 -0
  151. data/test/new_relic/agent/worker_loop_test.rb +66 -0
  152. data/test/new_relic/agent_test.rb +175 -0
  153. data/test/new_relic/collection_helper_test.rb +149 -0
  154. data/test/new_relic/command/deployments_test.rb +68 -0
  155. data/test/new_relic/control/class_methods_test.rb +62 -0
  156. data/test/new_relic/control/configuration_test.rb +72 -0
  157. data/test/new_relic/control/logging_methods_test.rb +185 -0
  158. data/test/new_relic/control_test.rb +254 -0
  159. data/test/new_relic/data_serialization_test.rb +208 -0
  160. data/test/new_relic/delayed_job_injection_test.rb +16 -0
  161. data/test/new_relic/local_environment_test.rb +72 -0
  162. data/test/new_relic/metric_data_test.rb +125 -0
  163. data/test/new_relic/metric_spec_test.rb +95 -0
  164. data/test/new_relic/rack/all_test.rb +11 -0
  165. data/test/new_relic/rack/browser_monitoring_test.rb +84 -0
  166. data/test/new_relic/rack/developer_mode_helper_test.rb +141 -0
  167. data/test/new_relic/rack/developer_mode_test.rb +43 -0
  168. data/test/new_relic/stats_test.rb +426 -0
  169. data/test/new_relic/transaction_analysis/segment_summary_test.rb +91 -0
  170. data/test/new_relic/transaction_analysis_test.rb +121 -0
  171. data/test/new_relic/transaction_sample/composite_segment_test.rb +35 -0
  172. data/test/new_relic/transaction_sample/fake_segment_test.rb +17 -0
  173. data/test/new_relic/transaction_sample/segment_test.rb +389 -0
  174. data/test/new_relic/transaction_sample/summary_segment_test.rb +31 -0
  175. data/test/new_relic/transaction_sample_subtest_test.rb +56 -0
  176. data/test/new_relic/transaction_sample_test.rb +164 -0
  177. data/test/new_relic/version_number_test.rb +89 -0
  178. data/test/test_contexts.rb +29 -0
  179. data/test/test_helper.rb +154 -0
  180. data/ui/helpers/developer_mode_helper.rb +357 -0
  181. data/ui/helpers/google_pie_chart.rb +48 -0
  182. data/ui/views/layouts/newrelic_default.rhtml +47 -0
  183. data/ui/views/newrelic/_explain_plans.rhtml +27 -0
  184. data/ui/views/newrelic/_sample.rhtml +20 -0
  185. data/ui/views/newrelic/_segment.rhtml +28 -0
  186. data/ui/views/newrelic/_segment_limit_message.rhtml +1 -0
  187. data/ui/views/newrelic/_segment_row.rhtml +12 -0
  188. data/ui/views/newrelic/_show_sample_detail.rhtml +24 -0
  189. data/ui/views/newrelic/_show_sample_sql.rhtml +24 -0
  190. data/ui/views/newrelic/_show_sample_summary.rhtml +3 -0
  191. data/ui/views/newrelic/_sql_row.rhtml +16 -0
  192. data/ui/views/newrelic/_stack_trace.rhtml +15 -0
  193. data/ui/views/newrelic/_table.rhtml +12 -0
  194. data/ui/views/newrelic/explain_sql.rhtml +43 -0
  195. data/ui/views/newrelic/file/images/arrow-close.png +0 -0
  196. data/ui/views/newrelic/file/images/arrow-open.png +0 -0
  197. data/ui/views/newrelic/file/images/blue_bar.gif +0 -0
  198. data/ui/views/newrelic/file/images/file_icon.png +0 -0
  199. data/ui/views/newrelic/file/images/gray_bar.gif +0 -0
  200. data/ui/views/newrelic/file/images/new-relic-rpm-desktop.gif +0 -0
  201. data/ui/views/newrelic/file/images/new_relic_rpm_desktop.gif +0 -0
  202. data/ui/views/newrelic/file/images/textmate.png +0 -0
  203. data/ui/views/newrelic/file/javascript/jquery-1.4.2.js +6240 -0
  204. data/ui/views/newrelic/file/javascript/transaction_sample.js +120 -0
  205. data/ui/views/newrelic/file/stylesheets/style.css +490 -0
  206. data/ui/views/newrelic/index.rhtml +71 -0
  207. data/ui/views/newrelic/sample_not_found.rhtml +2 -0
  208. data/ui/views/newrelic/show_sample.rhtml +80 -0
  209. data/ui/views/newrelic/show_source.rhtml +3 -0
  210. data/ui/views/newrelic/threads.rhtml +53 -0
  211. data/vendor/gems/dependency_detection-0.0.1.build/LICENSE +5 -0
  212. data/vendor/gems/dependency_detection-0.0.1.build/lib/dependency_detection/version.rb +3 -0
  213. data/vendor/gems/dependency_detection-0.0.1.build/lib/dependency_detection.rb +62 -0
  214. data/vendor/gems/metric_parser-0.1.0.pre1/lib/metric_parser.rb +1 -0
  215. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/action_mailer.rb +14 -0
  216. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/active_merchant.rb +31 -0
  217. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/active_record.rb +33 -0
  218. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/apdex.rb +89 -0
  219. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/background_transaction.rb +7 -0
  220. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/client.rb +46 -0
  221. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/controller.rb +67 -0
  222. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/controller_cpu.rb +43 -0
  223. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/controller_ext.rb +17 -0
  224. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/database.rb +48 -0
  225. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/database_pool.rb +24 -0
  226. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/dot_net.rb +28 -0
  227. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/dot_net_parser.rb +17 -0
  228. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/errors.rb +11 -0
  229. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/external.rb +55 -0
  230. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/frontend.rb +40 -0
  231. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/gc.rb +20 -0
  232. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/hibernate_session.rb +7 -0
  233. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/java.rb +31 -0
  234. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/java_parser.rb +17 -0
  235. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/jsp.rb +34 -0
  236. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/jsp_tag.rb +7 -0
  237. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/mem_cache.rb +55 -0
  238. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/metric_parser.rb +122 -0
  239. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/orm.rb +27 -0
  240. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/other_transaction.rb +40 -0
  241. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/servlet.rb +7 -0
  242. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/servlet_context_listener.rb +7 -0
  243. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/servlet_filter.rb +7 -0
  244. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/solr.rb +27 -0
  245. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/solr_request_handler.rb +15 -0
  246. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/spring.rb +54 -0
  247. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/spring_controller.rb +6 -0
  248. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/spring_view.rb +6 -0
  249. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/struts_action.rb +20 -0
  250. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/struts_result.rb +20 -0
  251. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/version.rb +5 -0
  252. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/view.rb +70 -0
  253. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/web_frontend.rb +18 -0
  254. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/web_service.rb +14 -0
  255. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/web_transaction.rb +133 -0
  256. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser.rb +64 -0
  257. metadata +398 -0
@@ -0,0 +1,58 @@
1
+ require 'new_relic/agent/instrumentation/controller_instrumentation'
2
+
3
+ DependencyDetection.defer do
4
+ depends_on do
5
+ defined?(::Sinatra) && defined?(::Sinatra::Base)
6
+ end
7
+
8
+ executes do
9
+ NewRelic::Agent.logger.debug 'Installing Sinatra instrumentation'
10
+ end
11
+
12
+ executes do
13
+ ::Sinatra::Base.class_eval do
14
+ include NewRelic::Agent::Instrumentation::Sinatra
15
+ alias route_eval_without_newrelic route_eval
16
+ alias route_eval route_eval_with_newrelic
17
+ end
18
+ end
19
+ end
20
+
21
+
22
+ module NewRelic
23
+ module Agent
24
+ module Instrumentation
25
+ # NewRelic instrumentation for Sinatra applications. Sinatra actions will
26
+ # appear in the UI similar to controller actions, and have breakdown charts
27
+ # and transaction traces.
28
+ #
29
+ # The actions in the UI will correspond to the pattern expression used
30
+ # to match them. HTTP operations are not distinguished. Multiple matches
31
+ # will all be tracked as separate actions.
32
+ module Sinatra
33
+
34
+ include NewRelic::Agent::Instrumentation::ControllerInstrumentation
35
+
36
+ def route_eval_with_newrelic(&block_arg)
37
+ path = unescape(@request.path_info)
38
+ name = path
39
+ # Go through each route and look for a match
40
+ if routes = self.class.routes[@request.request_method]
41
+ routes.detect do |pattern, keys, conditions, block|
42
+ if block_arg.equal? block
43
+ name = pattern.source
44
+ end
45
+ end
46
+ end
47
+ # strip off leading ^ and / chars and trailing $ and /
48
+ name.gsub!(%r{^[/^]*(.*?)[/\$\?]*$}, '\1')
49
+ name = 'root' if name.empty?
50
+ name = @request.request_method + ' ' + name if @request && @request.respond_to?(:request_method)
51
+ perform_action_with_newrelic_trace(:category => :sinatra, :name => name, :params => @request.params) do
52
+ route_eval_without_newrelic(&block_arg)
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,29 @@
1
+ DependencyDetection.defer do
2
+ @name = :sunspot
3
+
4
+ depends_on do
5
+ defined?(::Sunspot)
6
+ end
7
+
8
+ executes do
9
+ NewRelic::Agent.logger.debug 'Installing Rails Sunspot instrumentation'
10
+ end
11
+
12
+ executes do
13
+ ::Sunspot.module_eval do
14
+ class << self
15
+ %w(index index!).each do |method|
16
+ add_method_tracer method, 'SolrClient/Sunspot/index'
17
+ end
18
+ add_method_tracer :commit, 'SolrClient/Sunspot/commit'
19
+
20
+ %w[search more_like_this].each do |method|
21
+ add_method_tracer method, 'SolrClient/Sunspot/query'
22
+ end
23
+ %w[remove remove! remove_by_id remove_by_id! remove_all remove_all!].each do |method|
24
+ add_method_tracer method, 'SolrClient/Sunspot/delete'
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,21 @@
1
+ DependencyDetection.defer do
2
+ @name = :unicorn
3
+
4
+ depends_on do
5
+ defined?(::Unicorn) && defined?(::Unicorn::HttpServer)
6
+ end
7
+
8
+ executes do
9
+ NewRelic::Agent.logger.debug 'Installing Unicorn instrumentation'
10
+ end
11
+
12
+ executes do
13
+ Unicorn::HttpServer.class_eval do
14
+ old_worker_loop = instance_method(:worker_loop)
15
+ define_method(:worker_loop) do | worker |
16
+ NewRelic::Agent.after_fork(:force_reconnect => true)
17
+ old_worker_loop.bind(self).call(worker)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,9 @@
1
+ require 'new_relic/agent'
2
+ module NewRelic
3
+ module Agent
4
+ # stub module that contains instrumentation defined in the
5
+ # instrumentation directory
6
+ module Instrumentation
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,528 @@
1
+ require 'new_relic/control'
2
+ module NewRelic
3
+ module Agent
4
+ # This module contains class methods added to support installing custom
5
+ # metric tracers and executing for individual metrics.
6
+ #
7
+ # == Examples
8
+ #
9
+ # When the agent initializes, it extends Module with these methods.
10
+ # However if you want to use the API in code that might get loaded
11
+ # before the agent is initialized you will need to require
12
+ # this file:
13
+ #
14
+ # require 'new_relic/agent/method_tracer'
15
+ # class A
16
+ # include NewRelic::Agent::MethodTracer
17
+ # def process
18
+ # ...
19
+ # end
20
+ # add_method_tracer :process
21
+ # end
22
+ #
23
+ # To instrument a class method:
24
+ #
25
+ # require 'new_relic/agent/method_tracer'
26
+ # class An
27
+ # def self.process
28
+ # ...
29
+ # end
30
+ # class << self
31
+ # include NewRelic::Agent::MethodTracer
32
+ # add_method_tracer :process
33
+ # end
34
+ # end
35
+
36
+ module MethodTracer
37
+
38
+ def self.included clazz #:nodoc:
39
+ clazz.extend ClassMethods
40
+ clazz.send :include, InstanceMethods
41
+ end
42
+
43
+ def self.extended clazz #:nodoc:
44
+ clazz.extend ClassMethods
45
+ clazz.extend InstanceMethods
46
+ end
47
+
48
+ # Defines modules used at instrumentation runtime, to do the
49
+ # actual tracing of time spent
50
+ module InstanceMethods
51
+ # Deprecated: original method preserved for API backward compatibility.
52
+ # Use either #trace_execution_scoped or #trace_execution_unscoped
53
+ def trace_method_execution(metric_names, push_scope, produce_metric, deduct_call_time_from_parent, &block) #:nodoc:
54
+ if push_scope
55
+ trace_execution_scoped(metric_names, :metric => produce_metric,
56
+ :deduct_call_time_from_parent => deduct_call_time_from_parent, &block)
57
+ else
58
+ trace_execution_unscoped(metric_names, &block)
59
+ end
60
+ end
61
+
62
+ # Trace a given block with stats assigned to the given metric_name. It does not
63
+ # provide scoped measurements, meaning whatever is being traced will not 'blame the
64
+ # Controller'--that is to say appear in the breakdown chart.
65
+ # This is code is inlined in #add_method_tracer.
66
+ # * <tt>metric_names</tt> is a single name or an array of names of metrics
67
+ # * <tt>:force => true</tt> will force the metric to be captured even when
68
+ # tracing is disabled with NewRelic::Agent#disable_all_tracing
69
+ #
70
+ def trace_execution_unscoped(metric_names, options={})
71
+ return yield unless NewRelic::Agent.is_execution_traced?
72
+ t0 = Time.now
73
+ stats = Array(metric_names).map do | metric_name |
74
+ NewRelic::Agent.instance.stats_engine.get_stats_no_scope metric_name
75
+ end
76
+ begin
77
+ NewRelic::Agent.instance.push_trace_execution_flag(true) if options[:force]
78
+ yield
79
+ ensure
80
+ NewRelic::Agent.instance.pop_trace_execution_flag if options[:force]
81
+ duration = (Time.now - t0).to_f # for some reason this is 3 usec faster than Time - Time
82
+ stats.each { |stat| stat.trace_call(duration) }
83
+ end
84
+ end
85
+
86
+ # Deprecated. Use #trace_execution_scoped, a version with an options hash.
87
+ def trace_method_execution_with_scope(metric_names, produce_metric, deduct_call_time_from_parent, scoped_metric_only=false, &block) #:nodoc:
88
+ trace_execution_scoped(metric_names,
89
+ :metric => produce_metric,
90
+ :deduct_call_time_from_parent => deduct_call_time_from_parent,
91
+ :scoped_metric_only => scoped_metric_only, &block)
92
+ end
93
+
94
+ alias trace_method_execution_no_scope trace_execution_unscoped #:nodoc:
95
+
96
+ # Refactored out of the previous trace_execution_scoped
97
+ # method, most methods in this module relate to code used in
98
+ # the #trace_execution_scoped method in this module
99
+ module TraceExecutionScoped
100
+ # Shorthand to return the NewRelic::Agent.instance
101
+ def agent_instance
102
+ NewRelic::Agent.instance
103
+ end
104
+
105
+ # Shorthand to return the status of tracing
106
+ def traced?
107
+ NewRelic::Agent.is_execution_traced?
108
+ end
109
+
110
+ # Tracing is disabled if we are not in a traced context and
111
+ # no force option is supplied
112
+ def trace_disabled?(options)
113
+ !(traced? || options[:force])
114
+ end
115
+
116
+ # Shorthand to return the current statistics engine
117
+ def stat_engine
118
+ agent_instance.stats_engine
119
+ end
120
+
121
+ # returns a scoped metric stat for the specified name
122
+ def get_stats_scoped(first_name, scoped_metric_only)
123
+ stat_engine.get_stats(first_name, true, scoped_metric_only)
124
+ end
125
+ # Shorthand method to get stats from the stat engine
126
+ def get_stats_unscoped(name)
127
+ stat_engine.get_stats_no_scope(name)
128
+ end
129
+
130
+ # the main statistic we should record in
131
+ # #trace_execution_scoped - a scoped metric provided by the
132
+ # first item in the metric array
133
+ def main_stat(metric, options)
134
+ get_stats_scoped(metric, options[:scoped_metric_only])
135
+ end
136
+
137
+ # returns an array containing the first metric, and an array
138
+ # of other unscoped statistics we should also record along
139
+ # side it
140
+ def get_metric_stats(metrics, options)
141
+ metrics = Array(metrics)
142
+ first_name = metrics.shift
143
+ stats = metrics.map do | name |
144
+ get_stats_unscoped(name)
145
+ end
146
+ stats.unshift(main_stat(first_name, options)) if options[:metric]
147
+ [first_name, stats]
148
+ end
149
+
150
+ # Helper for setting a hash key if the hash key is nil,
151
+ # instead of the default ||= behavior which sets if it is
152
+ # false as well
153
+ def set_if_nil(hash, key)
154
+ hash[key] = true if hash[key].nil?
155
+ end
156
+
157
+ # delegates to #agent_instance to push a trace execution
158
+ # flag, only if execution of this metric is forced.
159
+ #
160
+ # This causes everything scoped inside this metric to be
161
+ # recorded, even if the parent transaction is generally not.
162
+ def push_flag!(forced)
163
+ agent_instance.push_trace_execution_flag(true) if forced
164
+ end
165
+
166
+ # delegates to #agent_instance to pop the trace execution
167
+ # flag, only if execution of this metric is
168
+ # forced. otherwise this is taken care of for us
169
+ # automatically.
170
+ #
171
+ # This ends the forced recording of metrics within the
172
+ # #trace_execution_scoped block
173
+ def pop_flag!(forced)
174
+ agent_instance.pop_trace_execution_flag if forced
175
+ end
176
+
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
180
+ def log_errors(code_area, metric)
181
+ yield
182
+ 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"))
185
+ end
186
+
187
+ # provides the header for our traced execution scoped
188
+ # method - gets the initial time, sets the tracing flag if
189
+ # needed, and pushes the scope onto the metric stack
190
+ # logs any errors that occur and returns the start time and
191
+ # the scope so that we can check for it later, to maintain
192
+ # sanity. If the scope stack becomes unbalanced, this
193
+ # transaction loses meaning.
194
+ def trace_execution_scoped_header(metric, options, t0=Time.now.to_f)
195
+ scope = log_errors("trace_execution_scoped header", metric) do
196
+ push_flag!(options[:force])
197
+ scope = stat_engine.push_scope(metric, t0, options[:deduct_call_time_from_parent])
198
+ end
199
+ # needed in case we have an error, above, to always return
200
+ # the start time.
201
+ [t0, scope]
202
+ end
203
+
204
+ # Handles the end of the #trace_execution_scoped method -
205
+ # calculating the time taken, popping the tracing flag if
206
+ # needed, deducting time taken by children, and tracing the
207
+ # subsidiary unscoped metrics if any
208
+ #
209
+ # this method fails safely if the header does not manage to
210
+ # push the scope onto the stack - it simply does not trace
211
+ # any metrics.
212
+ def trace_execution_scoped_footer(t0, first_name, metric_stats, expected_scope, forced, t1=Time.now.to_f)
213
+ log_errors("trace_method_execution footer", first_name) do
214
+ duration = t1 - t0
215
+
216
+ pop_flag!(forced)
217
+ if expected_scope
218
+ scope = stat_engine.pop_scope(expected_scope, duration, t1)
219
+ exclusive = duration - scope.children_time
220
+ metric_stats.each { |stats| stats.trace_call(duration, exclusive) }
221
+ end
222
+ end
223
+ end
224
+
225
+ # Trace a given block with stats and keep track of the caller.
226
+ # See NewRelic::Agent::MethodTracer::ClassMethods#add_method_tracer for a description of the arguments.
227
+ # +metric_names+ is either a single name or an array of metric names.
228
+ # If more than one metric is passed, the +produce_metric+ option only applies to the first. The
229
+ # others are always recorded. Only the first metric is pushed onto the scope stack.
230
+ #
231
+ # Generally you pass an array of metric names if you want to record the metric under additional
232
+ # categories, but generally this *should never ever be done*. Most of the time you can aggregate
233
+ # on the server.
234
+
235
+ def trace_execution_scoped(metric_names, options={})
236
+ return yield if trace_disabled?(options)
237
+ set_if_nil(options, :metric)
238
+ set_if_nil(options, :deduct_call_time_from_parent)
239
+ first_name, metric_stats = get_metric_stats(metric_names, options)
240
+ start_time, expected_scope = trace_execution_scoped_header(first_name, options)
241
+ begin
242
+ yield
243
+ ensure
244
+ trace_execution_scoped_footer(start_time, first_name, metric_stats, expected_scope, options[:force])
245
+ end
246
+ end
247
+
248
+ end
249
+ include TraceExecutionScoped
250
+
251
+ end
252
+
253
+ # Defines methods used at the class level, for adding instrumentation
254
+ module ClassMethods
255
+ # contains methods refactored out of the #add_method_tracer method
256
+ module AddMethodTracer
257
+ ALLOWED_KEYS = [:force, :metric, :push_scope, :deduct_call_time_from_parent, :code_header, :code_footer, :scoped_metric_only].freeze
258
+
259
+ # used to verify that the keys passed to
260
+ # NewRelic::Agent::MethodTracer::ClassMethods#add_method_tracer
261
+ # are valid. Returns a list of keys that were unexpected
262
+ def unrecognized_keys(expected, given)
263
+ given.keys - expected
264
+ end
265
+
266
+ # used to verify that the keys passed to
267
+ # NewRelic::Agent::MethodTracer::ClassMethods#add_method_tracer
268
+ # are valid. checks the expected list against the list
269
+ # actually provided
270
+ def any_unrecognized_keys?(expected, given)
271
+ unrecognized_keys(expected, given).any?
272
+ end
273
+
274
+ # raises an error when the
275
+ # NewRelic::Agent::MethodTracer::ClassMethods#add_method_tracer
276
+ # method is called with improper keys. This aids in
277
+ # debugging new instrumentation by failing fast
278
+ def check_for_illegal_keys!(options)
279
+ if any_unrecognized_keys?(ALLOWED_KEYS, options)
280
+ raise "Unrecognized options in add_method_tracer_call: #{unrecognized_keys(ALLOWED_KEYS, options).join(', ')}"
281
+ end
282
+ end
283
+
284
+ # Sets the options for deducting call time from
285
+ # parents. This defaults to true if we are recording a metric, but
286
+ # can be overridden by the user if desired.
287
+ #
288
+ # has the effect of not allowing overlapping times, and
289
+ # should generally be true
290
+ def set_deduct_call_time_based_on_metric(options)
291
+ {:deduct_call_time_from_parent => !!options[:metric]}.merge(options)
292
+ end
293
+
294
+ # validity checking - add_method_tracer must receive either
295
+ # push scope or metric, or else it would record no
296
+ # data. Raises an error if this is the case
297
+ def check_for_push_scope_and_metric(options)
298
+ unless options[:push_scope] || options[:metric]
299
+ raise "Can't add a tracer where push_scope is false and metric is false"
300
+ end
301
+ end
302
+
303
+ DEFAULT_SETTINGS = {:push_scope => true, :metric => true, :force => false, :code_header => "", :code_footer => "", :scoped_metric_only => false}.freeze
304
+
305
+ # Checks the provided options to make sure that they make
306
+ # sense. Raises an error if the options are incorrect to
307
+ # assist with debugging, so that errors occur at class
308
+ # construction time rather than instrumentation run time
309
+ def validate_options(options)
310
+ raise TypeError.new("provided options must be a Hash") unless options.is_a?(Hash)
311
+ check_for_illegal_keys!(options)
312
+ options = set_deduct_call_time_based_on_metric(DEFAULT_SETTINGS.merge(options))
313
+ check_for_push_scope_and_metric(options)
314
+ options
315
+ end
316
+
317
+ # Default to the class where the method is defined.
318
+ #
319
+ # Example:
320
+ # Foo.default_metric_name_code('bar') #=> "Custom/#{Foo.name}/bar"
321
+ def default_metric_name_code(method_name)
322
+ "Custom/#{self.name}/#{method_name.to_s}"
323
+ end
324
+
325
+ # Checks to see if the method we are attempting to trace
326
+ # actually exists or not. #add_method_tracer can't do
327
+ # anything if the method doesn't exist.
328
+ def newrelic_method_exists?(method_name)
329
+ 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
331
+ exists
332
+ end
333
+
334
+ # Checks to see if we have already traced a method with a
335
+ # given metric by checking to see if the traced method
336
+ # exists. Warns the user if methods are being double-traced
337
+ # to help with debugging custom instrumentation.
338
+ def traced_method_exists?(method_name, metric_name_code)
339
+ 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
341
+ exists
342
+ end
343
+
344
+ # Returns a code snippet to be eval'd that skips tracing
345
+ # when the agent is not tracing execution. turns
346
+ # instrumentation into effectively one method call overhead
347
+ # when the agent is disabled
348
+ def assemble_code_header(method_name, metric_name_code, options)
349
+ unless options[:force]
350
+ "return #{_untraced_method_name(method_name, metric_name_code)}(*args, &block) unless NewRelic::Agent.is_execution_traced?\n"
351
+ end.to_s + options[:code_header].to_s
352
+ end
353
+
354
+ # returns an eval-able string that contains the traced
355
+ # method code used if the agent is not creating a scope for
356
+ # use in scoped metrics.
357
+ def method_without_push_scope(method_name, metric_name_code, options)
358
+ "def #{_traced_method_name(method_name, metric_name_code)}(*args, &block)
359
+ #{assemble_code_header(method_name, metric_name_code, options)}
360
+ t0 = Time.now
361
+ stats = NewRelic::Agent.instance.stats_engine.get_stats_no_scope \"#{metric_name_code}\"
362
+ begin
363
+ #{"NewRelic::Agent.instance.push_trace_execution_flag(true)\n" if options[:force]}
364
+ #{_untraced_method_name(method_name, metric_name_code)}(*args, &block)\n
365
+ ensure
366
+ #{"NewRelic::Agent.instance.pop_trace_execution_flag\n" if options[:force] }
367
+ duration = (Time.now - t0).to_f
368
+ stats.trace_call(duration)
369
+ #{options[:code_footer]}
370
+ end
371
+ end"
372
+ end
373
+
374
+ # returns an eval-able string that contains the tracing code
375
+ # for a fully traced metric including scoping
376
+ def method_with_push_scope(method_name, metric_name_code, options)
377
+ klass = (self === Module) ? "self" : "self.class"
378
+
379
+ "def #{_traced_method_name(method_name, metric_name_code)}(*args, &block)
380
+ #{options[:code_header]}
381
+ result = #{klass}.trace_execution_scoped(\"#{metric_name_code}\",
382
+ :metric => #{options[:metric]},
383
+ :forced => #{options[:force]},
384
+ :deduct_call_time_from_parent => #{options[:deduct_call_time_from_parent]},
385
+ :scoped_metric_only => #{options[:scoped_metric_only]}) do
386
+ #{_untraced_method_name(method_name, metric_name_code)}(*args, &block)
387
+ end
388
+ #{options[:code_footer]}
389
+ result
390
+ end"
391
+ end
392
+
393
+ # Decides which code snippet we should be eval'ing in this
394
+ # context, based on the options.
395
+ def code_to_eval(method_name, metric_name_code, options)
396
+ options = validate_options(options)
397
+ if options[:push_scope]
398
+ method_with_push_scope(method_name, metric_name_code, options)
399
+ else
400
+ method_without_push_scope(method_name, metric_name_code, options)
401
+ end
402
+ end
403
+ end
404
+ include AddMethodTracer
405
+
406
+
407
+
408
+ # Add a method tracer to the specified method.
409
+ #
410
+ # === Common Options
411
+ #
412
+ # * <tt>:push_scope => false</tt> specifies this method tracer should not
413
+ # keep track of the caller; it will not show up in controller breakdown
414
+ # pie charts.
415
+ # * <tt>:metric => false</tt> specifies that no metric will be recorded.
416
+ # Instead the call will show up in transaction traces as well as traces
417
+ # shown in Developer Mode.
418
+ #
419
+ # === Uncommon Options
420
+ #
421
+ # * <tt>:scoped_metric_only => true</tt> indicates that the unscoped metric
422
+ # should not be recorded. Normally two metrics are potentially created
423
+ # on every invocation: the aggregate method where statistics for all calls
424
+ # of that metric are stored, and the "scoped metric" which records the
425
+ # statistics for invocations in a particular scope--generally a controller
426
+ # action. This option indicates that only the second type should be recorded.
427
+ # The effect is similar to <tt>:metric => false</tt> but in addition you
428
+ # will also see the invocation in breakdown pie charts.
429
+ # * <tt>:deduct_call_time_from_parent => false</tt> indicates that the method invocation
430
+ # time should never be deducted from the time reported as 'exclusive' in the
431
+ # caller. You would want to use this if you are tracing a recursive method
432
+ # or a method that might be called inside another traced method.
433
+ # * <tt>:code_header</tt> and <tt>:code_footer</tt> specify ruby code that
434
+ # is inserted into the tracer before and after the call.
435
+ # * <tt>:force = true</tt> will ensure the metric is captured even if called inside
436
+ # an untraced execution call. (See NewRelic::Agent#disable_all_tracing)
437
+ #
438
+ # === Overriding the metric name
439
+ #
440
+ # +metric_name_code+ is a string that is eval'd to get the
441
+ # name of the metric associated with the call, so if you want to
442
+ # use interpolaion evaluated at call time, then single quote
443
+ # the value like this:
444
+ #
445
+ # add_method_tracer :foo, 'Custom/#{self.class.name}/foo'
446
+ #
447
+ # This would name the metric according to the class of the runtime
448
+ # intance, as opposed to the class where +foo+ is defined.
449
+ #
450
+ # If not provided, the metric name will be <tt>Custom/ClassName/method_name</tt>.
451
+ #
452
+ # === Examples
453
+ #
454
+ # Instrument +foo+ only for custom views--will not show up in transaction traces or caller breakdown graphs:
455
+ #
456
+ # add_method_tracer :foo, :push_scope => false
457
+ #
458
+ # Instrument +foo+ just for transaction traces only:
459
+ #
460
+ # add_method_tracer :foo, :metric => false
461
+ #
462
+ # Instrument +foo+ so it shows up in transaction traces and caller breakdown graphs
463
+ # for actions:
464
+ #
465
+ # add_method_tracer :foo
466
+ #
467
+ # which is equivalent to:
468
+ #
469
+ # add_method_tracer :foo, 'Custom/#{self.class.name}/foo', :push_scope => true, :metric => true
470
+ #
471
+ # Instrument the class method +foo+ with the metric name 'Custom/People/fetch':
472
+ #
473
+ # class << self
474
+ # add_method_tracer :foo, 'Custom/People/fetch'
475
+ # end
476
+ #
477
+ def add_method_tracer(method_name, metric_name_code=nil, options = {})
478
+ return unless newrelic_method_exists?(method_name)
479
+ metric_name_code ||= default_metric_name_code(method_name)
480
+ return if traced_method_exists?(method_name, metric_name_code)
481
+
482
+ traced_method = code_to_eval(method_name, metric_name_code, options)
483
+
484
+ class_eval traced_method, __FILE__, __LINE__
485
+ alias_method _untraced_method_name(method_name, metric_name_code), method_name
486
+ alias_method method_name, _traced_method_name(method_name, metric_name_code)
487
+ NewRelic::Control.instance.log.debug("Traced method: class = #{self.name},"+
488
+ "method = #{method_name}, "+
489
+ "metric = '#{metric_name_code}'")
490
+ end
491
+
492
+ # For tests only because tracers must be removed in reverse-order
493
+ # from when they were added, or else other tracers that were added to the same method
494
+ # may get removed as well.
495
+ def remove_method_tracer(method_name, metric_name_code) # :nodoc:
496
+ return unless NewRelic::Control.instance.agent_enabled?
497
+ if method_defined? "#{_traced_method_name(method_name, metric_name_code)}"
498
+ alias_method method_name, "#{_untraced_method_name(method_name, metric_name_code)}"
499
+ 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")
501
+ else
502
+ raise "No tracer for '#{metric_name_code}' on method '#{method_name}'"
503
+ end
504
+ end
505
+ private
506
+
507
+ # given a method and a metric, this method returns the
508
+ # untraced alias of the method name
509
+ def _untraced_method_name(method_name, metric_name)
510
+ "#{_sanitize_name(method_name)}_without_trace_#{_sanitize_name(metric_name)}"
511
+ end
512
+
513
+ # given a method and a metric, this method returns the traced
514
+ # alias of the method name
515
+ def _traced_method_name(method_name, metric_name)
516
+ "#{_sanitize_name(method_name)}_with_trace_#{_sanitize_name(metric_name)}"
517
+ end
518
+
519
+ # makes sure that method names do not contain characters that
520
+ # might break the interpreter, for example ! or ? characters
521
+ # that are not allowed in the middle of method names
522
+ def _sanitize_name(name)
523
+ name.to_s.tr_s('^a-zA-Z0-9', '_')
524
+ end
525
+ end
526
+ end
527
+ end
528
+ end