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,110 @@
1
+ module NewRelic
2
+ module Agent
3
+ # This class contains the configuration data for setting up RUM
4
+ # headers and footers - acts as a cache of this data so we don't
5
+ # need to look it up or reconfigure it every request
6
+ class BeaconConfiguration
7
+
8
+ # the statically generated header - generated when the beacon
9
+ # configuration is created - does not vary per page
10
+ attr_reader :browser_timing_header
11
+
12
+ # the static portion of the RUM footer - this part does not vary
13
+ # by which request is in progress
14
+ attr_reader :browser_timing_static_footer
15
+
16
+ # the application id we include in the javascript -
17
+ # crossreferences with the application id on the collectors
18
+ attr_reader :application_id
19
+
20
+ # the key used for browser monitoring. This is different from
21
+ # the account key
22
+ attr_reader :browser_monitoring_key
23
+
24
+ # which beacon we should report to - set by startup of the agent
25
+ attr_reader :beacon
26
+
27
+ # whether RUM is enabled or not - determined based on server and
28
+ # local config
29
+ attr_reader :rum_enabled
30
+
31
+ # A static javascript header that is identical for every account
32
+ # and application
33
+ JS_HEADER = "<script type=\"text/javascript\">var NREUMQ=NREUMQ||[];NREUMQ.push([\"mark\",\"firstbyte\",new Date().getTime()]);</script>"
34
+
35
+ # Creates a new browser configuration data. Argument is a hash
36
+ # of configuration values from the server
37
+ def initialize(connect_data)
38
+ @browser_monitoring_key = connect_data['browser_key']
39
+ @application_id = connect_data['application_id']
40
+ @beacon = connect_data['beacon']
41
+ @rum_enabled = connect_data['rum.enabled']
42
+ @rum_enabled = true if @rum_enabled.nil?
43
+ NewRelic::Control.instance.log.warn("Real User Monitoring is disabled for this agent. Edit your configuration to change this.") unless @rum_enabled
44
+ @browser_timing_header = build_browser_timing_header
45
+ NewRelic::Control.instance.log.debug("Browser timing header: #{@browser_timing_header.inspect}")
46
+ @browser_timing_static_footer = build_load_file_js(connect_data)
47
+ NewRelic::Control.instance.log.debug("Browser timing static footer: #{@browser_timing_static_footer.inspect}")
48
+ end
49
+
50
+ # returns a memoized version of the bytes in the license key for
51
+ # obscuring transaction names in the javascript
52
+ def license_bytes
53
+ if @license_bytes.nil?
54
+ @license_bytes = []
55
+ NewRelic::Control.instance.license_key.each_byte {|byte| @license_bytes << byte}
56
+ end
57
+ @license_bytes
58
+ end
59
+
60
+ # returns a snippet of text that does not change
61
+ # per-transaction. Is empty when rum is disabled, or we are not
62
+ # including the episodes file dynamically (i.e. the user
63
+ # includes it themselves)
64
+ def build_load_file_js(connect_data)
65
+ js = <<-EOS
66
+ if (!NREUMQ.f) { NREUMQ.f=function() {
67
+ NREUMQ.push(["load",new Date().getTime()]);
68
+ EOS
69
+
70
+ if connect_data.fetch('rum.load_episodes_file', true)
71
+ episodes_url = connect_data.fetch('episodes_url', '')
72
+ js << <<-EOS
73
+ var e=document.createElement(\"script\");
74
+ e.type=\"text/javascript\";e.async=true;e.src=\"#{episodes_url}\";
75
+ document.body.appendChild(e);
76
+ EOS
77
+ end
78
+
79
+ js << <<-EOS
80
+ if(NREUMQ.a)NREUMQ.a();
81
+ };
82
+ NREUMQ.a=window.onload;window.onload=NREUMQ.f;
83
+ };
84
+ EOS
85
+ js
86
+ end
87
+
88
+ # returns a copy of the static javascript header, in case people
89
+ # are munging strings somewhere down the line
90
+ def javascript_header
91
+ JS_HEADER.dup
92
+ end
93
+
94
+ # Returns the header string, properly html-safed if needed
95
+ def build_browser_timing_header
96
+ return "" if !@rum_enabled
97
+ return "" if @browser_monitoring_key.nil?
98
+
99
+ value = javascript_header
100
+ if value.respond_to?(:html_safe)
101
+ value.html_safe
102
+ else
103
+ value
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
109
+
110
+
@@ -0,0 +1,102 @@
1
+ require 'base64'
2
+ require 'new_relic/agent/beacon_configuration'
3
+ module NewRelic
4
+ module Agent
5
+ # This module contains support for Real User Monitoring - the
6
+ # javascript generation and configuration
7
+ module BrowserMonitoring
8
+
9
+ # This method returns a string suitable for inclusion in a page
10
+ # - known as 'manual instrumentation' for Real User
11
+ # Monitoring. Can return either a script tag with associated
12
+ # javascript, or in the case of disabled Real User Monitoring,
13
+ # an empty string
14
+ #
15
+ # This is the header string - it should be placed as high in the
16
+ # page as is reasonably possible - that is, before any style or
17
+ # javascript inclusions, but after any header-related meta tags
18
+ def browser_timing_header
19
+ return "" if NewRelic::Agent.instance.beacon_configuration.nil?
20
+ return "" if !NewRelic::Agent.is_transaction_traced? || !NewRelic::Agent.is_execution_traced?
21
+
22
+ NewRelic::Agent.instance.beacon_configuration.browser_timing_header
23
+ end
24
+
25
+ # This method returns a string suitable for inclusion in a page
26
+ # - known as 'manual instrumentation' for Real User
27
+ # Monitoring. Can return either a script tag with associated
28
+ # javascript, or in the case of disabled Real User Monitoring,
29
+ # an empty string
30
+ #
31
+ # This is the footer string - it should be placed as low in the
32
+ # page as is reasonably possible.
33
+ def browser_timing_footer
34
+ config = NewRelic::Agent.instance.beacon_configuration
35
+ return "" if config.nil? || !config.rum_enabled || config.browser_monitoring_key.nil?
36
+ return "" if !NewRelic::Agent.is_transaction_traced? || !NewRelic::Agent.is_execution_traced?
37
+ generate_footer_js
38
+ end
39
+
40
+ private
41
+
42
+ def generate_footer_js
43
+ if browser_monitoring_start_time
44
+ config = NewRelic::Agent.instance.beacon_configuration
45
+ application_id = config.application_id
46
+ beacon = config.beacon
47
+ license_key = config.browser_monitoring_key
48
+
49
+ footer_js_string(beacon, license_key, application_id)
50
+ else
51
+ ''
52
+ end
53
+ end
54
+
55
+ def browser_monitoring_transaction_name
56
+ Thread.current[:newrelic_most_recent_transaction] || "<unknown>"
57
+ end
58
+
59
+ def browser_monitoring_start_time
60
+ Thread.current[:newrelic_start_time]
61
+ end
62
+
63
+ def clamp_to_positive(value)
64
+ return 0.0 if value < 0
65
+ value
66
+ end
67
+
68
+ def browser_monitoring_app_time
69
+ clamp_to_positive(((Time.now - browser_monitoring_start_time).to_f * 1000.0).round)
70
+ end
71
+
72
+ def browser_monitoring_queue_time
73
+ clamp_to_positive((Thread.current[:newrelic_queue_time].to_f * 1000.0).round)
74
+ end
75
+
76
+ def footer_js_string(beacon, license_key, application_id)
77
+ obfuscated_transaction_name = obfuscate(browser_monitoring_transaction_name)
78
+ html_safe_if_needed("<script type=\"text/javascript\">#{NewRelic::Agent.instance.beacon_configuration.browser_timing_static_footer}NREUMQ.push([\"nrf2\",\"#{beacon}\",\"#{license_key}\",#{application_id},\"#{obfuscated_transaction_name}\",#{browser_monitoring_queue_time},#{browser_monitoring_app_time},new Date().getTime()])</script>")
79
+ end
80
+
81
+ def html_safe_if_needed(string)
82
+ if string.respond_to?(:html_safe)
83
+ string.html_safe
84
+ else
85
+ string
86
+ end
87
+ end
88
+
89
+ def obfuscate(text)
90
+ obfuscated = ""
91
+ key_bytes = NewRelic::Agent.instance.beacon_configuration.license_bytes
92
+ index = 0
93
+ text.each_byte{|byte|
94
+ obfuscated.concat((byte ^ key_bytes[index % 13].to_i))
95
+ index+=1
96
+ }
97
+
98
+ [obfuscated].pack("m0").gsub("\n", '')
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,99 @@
1
+ module NewRelic
2
+ module Agent
3
+ # This module supports calculation of actual time spent processing requests over the course of
4
+ # one harvest period. It's similar to what you would get if you just added up all the
5
+ # execution times of controller calls, however that will be inaccurate when requests
6
+ # span the minute boundaries. This module manages accounting of requests not yet
7
+ # completed.
8
+ #
9
+ # Calls are re-entrant. All start calls must be paired with finish
10
+ # calls, or a reset call.
11
+ module BusyCalculator
12
+
13
+ extend self
14
+
15
+ # For testability, add accessors:
16
+ attr_reader :harvest_start, :accumulator
17
+
18
+ # sets up busy calculations based on the start and end of
19
+ # transactions - used for a rough estimate of what percentage of
20
+ # wall clock time is spent processing requests
21
+ def dispatcher_start(time)
22
+ Thread.current[:busy_entries] ||= 0
23
+ callers = Thread.current[:busy_entries] += 1
24
+ return if callers > 1
25
+ @lock.synchronize do
26
+ @entrypoint_stack.push time
27
+ end
28
+ end
29
+
30
+ # called when a transaction finishes, to add time to the
31
+ # instance variable accumulator. this is harvested when we send
32
+ # data to the server
33
+ def dispatcher_finish(end_time = Time.now)
34
+ callers = Thread.current[:busy_entries] -= 1
35
+ # Ignore nested calls
36
+ return if callers > 0
37
+ @lock.synchronize do
38
+ if @entrypoint_stack.empty?
39
+ NewRelic::Agent.logger.error("Stack underflow tracking dispatcher entry and exit!\n #{caller.join(" \n")}")
40
+ else
41
+ @accumulator += (end_time - @entrypoint_stack.pop).to_f
42
+ end
43
+ end
44
+ end
45
+
46
+ # this returns the size of the entry point stack, which
47
+ # determines how many transactions are running
48
+ def busy_count
49
+ @entrypoint_stack.size
50
+ end
51
+
52
+ # Reset the state of the information accumulated by all threads,
53
+ # but only reset the recursion counter for this thread.
54
+ def reset
55
+ @entrypoint_stack = []
56
+ Thread.current[:busy_entries] = 0
57
+ @lock ||= Mutex.new
58
+ @accumulator = 0
59
+ @harvest_start = Time.now
60
+ end
61
+
62
+ self.reset
63
+
64
+ # Called before uploading to to the server to collect current busy stats.
65
+ def harvest_busy
66
+ busy = 0
67
+ t0 = Time.now
68
+ @lock.synchronize do
69
+ busy = accumulator
70
+ @accumulator = 0
71
+
72
+ # Walk through the stack and capture all times up to
73
+ # now for entrypoints
74
+ @entrypoint_stack.size.times do |frame|
75
+ busy += (t0 - @entrypoint_stack[frame]).to_f
76
+ @entrypoint_stack[frame] = t0
77
+ end
78
+
79
+ end
80
+
81
+ busy = 0.0 if busy < 0.0 # don't go below 0%
82
+
83
+ time_window = (t0 - harvest_start).to_f
84
+ time_window = 1.0 if time_window == 0.0 # protect against divide by zero
85
+
86
+ busy = busy / time_window
87
+
88
+ instance_busy_stats.record_data_point busy
89
+ @harvest_start = t0
90
+ end
91
+ private
92
+ def instance_busy_stats
93
+ # Late binding on the Instance/busy stats
94
+ NewRelic::Agent.agent.stats_engine.get_stats_no_scope 'Instance/Busy'
95
+ end
96
+
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,13 @@
1
+ # This class is used by NewRelic::Agent.set_sql_obfuscator to chain multiple
2
+ # obfuscation blocks when not using the default :replace action
3
+ class NewRelic::ChainedCall
4
+ def initialize(block1, block2)
5
+ @block1 = block1
6
+ @block2 = block2
7
+ end
8
+
9
+ def call(sql)
10
+ sql = @block1.call(sql)
11
+ @block2.call(sql)
12
+ end
13
+ end
@@ -0,0 +1,203 @@
1
+ require 'singleton'
2
+
3
+ module NewRelic
4
+ # columns for a mysql explain plan
5
+ MYSQL_EXPLAIN_COLUMNS = [
6
+ "Id",
7
+ "Select Type",
8
+ "Table",
9
+ "Type",
10
+ "Possible Keys",
11
+ "Key",
12
+ "Key Length",
13
+ "Ref",
14
+ "Rows",
15
+ "Extra"
16
+ ].freeze
17
+
18
+ module Agent
19
+ module Database
20
+ extend self
21
+
22
+ def obfuscate_sql(sql)
23
+ Obfuscator.instance.obfuscator.call(sql)
24
+ end
25
+
26
+ def set_sql_obfuscator(type, &block)
27
+ Obfuscator.instance.set_sql_obfuscator(type, &block)
28
+ end
29
+
30
+ def get_connection(config)
31
+ ConnectionManager.instance.get_connection(config)
32
+ end
33
+
34
+ def close_connections
35
+ ConnectionManager.instance.close_connections
36
+ end
37
+
38
+ # Perform this in the runtime environment of a managed
39
+ # application, to explain the sql statement executed within a
40
+ # segment of a transaction sample. Returns an array of
41
+ # explanations (which is an array rows consisting of an array of
42
+ # strings for each column returned by the the explain query)
43
+ # Note this happens only for statements whose execution time
44
+ # exceeds a threshold (e.g. 500ms) and only within the slowest
45
+ # transaction in a report period, selected for shipment to New
46
+ # Relic
47
+ def explain_sql(sql, connection_config)
48
+ return nil unless sql && connection_config
49
+ statement = sql.split(";\n")[0] # only explain the first
50
+ explain_sql = explain_statement(statement, connection_config)
51
+ return explain_sql || []
52
+ end
53
+
54
+ def explain_statement(statement, config)
55
+ if is_select?(statement)
56
+ handle_exception_in_explain do
57
+ connection = get_connection(config)
58
+ plan = nil
59
+ if connection
60
+ plan = process_resultset(connection.execute("EXPLAIN #{statement}"))
61
+ end
62
+ return plan
63
+ end
64
+ end
65
+ end
66
+
67
+ def process_resultset(items)
68
+ # The resultset type varies for different drivers. Only thing you can count on is
69
+ # that it implements each. Also: can't use select_rows because the native postgres
70
+ # driver doesn't know that method.
71
+
72
+ headers = []
73
+ values = []
74
+ if items.respond_to?(:each_hash)
75
+ items.each_hash do |row|
76
+ headers = row.keys
77
+ values << headers.map{|h| row[h] }
78
+ end
79
+ elsif items.respond_to?(:each)
80
+ items.each do |row|
81
+ if row.kind_of?(Hash)
82
+ headers = row.keys
83
+ values << headers.map{|h| row[h] }
84
+ else
85
+ values << row
86
+ end
87
+ end
88
+ else
89
+ values = [items]
90
+ end
91
+
92
+ headers = nil if headers.empty?
93
+ [headers, values]
94
+ end
95
+
96
+ def handle_exception_in_explain
97
+ yield
98
+ rescue Exception => e
99
+ begin
100
+ # guarantees no throw from explain_sql
101
+ NewRelic::Control.instance.log.error("Error getting query plan: #{e.message}")
102
+ NewRelic::Control.instance.log.debug(e.backtrace.join("\n"))
103
+ rescue Exception
104
+ # double exception. throw up your hands
105
+ end
106
+ end
107
+
108
+ def is_select?(statement)
109
+ # split the string into at most two segments on the
110
+ # system-defined field separator character
111
+ first_word, rest_of_statement = statement.split($;, 2)
112
+ (first_word.upcase == 'SELECT')
113
+ end
114
+
115
+ class ConnectionManager
116
+ include Singleton
117
+
118
+ # Returns a cached connection for a given ActiveRecord
119
+ # configuration - these are stored or reopened as needed, and if
120
+ # we cannot get one, we ignore it and move on without explaining
121
+ # the sql
122
+ def get_connection(config)
123
+ @connections ||= {}
124
+
125
+ connection = @connections[config]
126
+
127
+ return connection if connection
128
+
129
+ begin
130
+ connection = ActiveRecord::Base.send("#{config[:adapter]}_connection", config)
131
+ @connections[config] = connection
132
+ rescue => e
133
+ NewRelic::Agent.agent.log.error("Caught exception #{e} trying to get connection to DB for explain. Control: #{config}")
134
+ NewRelic::Agent.agent.log.error(e.backtrace.join("\n"))
135
+ nil
136
+ end
137
+ end
138
+
139
+ # Closes all the connections in the internal connection cache
140
+ def close_connections
141
+ @connections ||= {}
142
+ @connections.values.each do |connection|
143
+ begin
144
+ connection.disconnect!
145
+ rescue
146
+ end
147
+ end
148
+
149
+ @connections = {}
150
+ end
151
+ end
152
+
153
+ class Obfuscator
154
+ include Singleton
155
+
156
+ attr_reader :obfuscator
157
+
158
+ def initialize
159
+ reset
160
+ end
161
+
162
+ def reset
163
+ @obfuscator = method(:default_sql_obfuscator)
164
+ end
165
+
166
+ # Sets the sql obfuscator used to clean up sql when sending it
167
+ # to the server. Possible types are:
168
+ #
169
+ # :before => sets the block to run before the existing
170
+ # obfuscators
171
+ #
172
+ # :after => sets the block to run after the existing
173
+ # obfuscator(s)
174
+ #
175
+ # :replace => removes the current obfuscator and replaces it
176
+ # with the provided block
177
+ def set_sql_obfuscator(type, &block)
178
+ if type == :before
179
+ @obfuscator = NewRelic::ChainedCall.new(block, @obfuscator)
180
+ elsif type == :after
181
+ @obfuscator = NewRelic::ChainedCall.new(@obfuscator, block)
182
+ elsif type == :replace
183
+ @obfuscator = block
184
+ else
185
+ fail "unknown sql_obfuscator type #{type}"
186
+ end
187
+ end
188
+
189
+ def default_sql_obfuscator(sql)
190
+ sql = sql.dup
191
+ # This is hardly readable. Use the unit tests.
192
+ # remove single quoted strings:
193
+ sql.gsub!(/'(.*?[^\\'])??'(?!')/, '?')
194
+ # remove double quoted strings:
195
+ sql.gsub!(/"(.*?[^\\"])??"(?!")/, '?')
196
+ # replace all number literals
197
+ sql.gsub!(/\d+/, "?")
198
+ sql
199
+ end
200
+ end
201
+ end
202
+ end
203
+ end