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,397 @@
1
+ require 'new_relic/agent'
2
+ require 'new_relic/control'
3
+ require 'new_relic/agent/transaction_sample_builder'
4
+ module NewRelic
5
+ module Agent
6
+
7
+ # This class contains the logic of sampling a transaction -
8
+ # creation and modification of transaction samples
9
+ class TransactionSampler
10
+
11
+ # Module defining methods stubbed out when the agent is disabled
12
+ module Shim #:nodoc:
13
+ def notice_first_scope_push(*args); end
14
+ def notice_push_scope(*args); end
15
+ def notice_pop_scope(*args); end
16
+ def notice_scope_empty(*args); end
17
+ end
18
+
19
+ BUILDER_KEY = :transaction_sample_builder
20
+
21
+ attr_accessor :stack_trace_threshold, :random_sampling, :sampling_rate
22
+ attr_accessor :explain_threshold, :explain_enabled, :transaction_threshold
23
+ attr_reader :samples, :last_sample, :disabled
24
+
25
+ def initialize
26
+ # @samples is an array of recent samples up to @max_samples in
27
+ # size - it's only used by developer mode
28
+ @samples = []
29
+ @max_samples = 100
30
+
31
+ # @harvest_count is a count of harvests used for random
32
+ # sampling - we pull 1 @random_sample in every @sampling_rate harvests
33
+ @harvest_count = 0
34
+ @random_sample = nil
35
+ @sampling_rate = 10
36
+ configure!
37
+
38
+ # This lock is used to synchronize access to the @last_sample
39
+ # and related variables. It can become necessary on JRuby or
40
+ # any 'honest-to-god'-multithreaded system
41
+ @samples_lock = Mutex.new
42
+ end
43
+
44
+ def configure!
45
+ # @segment_limit and @stack_trace_threshold come from the
46
+ # configuration file, with built-in defaults that should
47
+ # suffice for most customers
48
+
49
+ # enable if config.fetch('enabled', true)
50
+
51
+ @segment_limit = config.fetch('limit_segments', 4000)
52
+ @stack_trace_threshold = config.fetch('stack_trace_threshold', 0.500).to_f
53
+ @explain_threshold = config.fetch('explain_threshold', 0.5).to_f
54
+ @explain_enabled = config.fetch('explain_enabled', true)
55
+ @transaction_threshold = config.fetch('transation_threshold', 2.0)
56
+ end
57
+
58
+ def config
59
+ NewRelic::Control.instance.fetch('transaction_tracer', {})
60
+ end
61
+
62
+ # Returns the current sample id, delegated from `builder`
63
+ def current_sample_id
64
+ b=builder
65
+ b and b.sample_id
66
+ end
67
+
68
+ # Enable the transaction sampler - this also registers it with
69
+ # the statistics engine.
70
+ def enable
71
+ @disabled = false
72
+ NewRelic::Agent.instance.stats_engine.transaction_sampler = self
73
+ end
74
+
75
+ # Disable the transaction sampler - this also deregisters it
76
+ # with the statistics engine.
77
+ def disable
78
+ @disabled = true
79
+ NewRelic::Agent.instance.stats_engine.remove_transaction_sampler(self)
80
+ end
81
+
82
+ def enabled?
83
+ !@disabled
84
+ end
85
+
86
+ # Set with an integer value n, this takes one in every n
87
+ # harvested samples. It also resets the harvest count to a
88
+ # random integer between 0 and (n-1)
89
+ def sampling_rate=(val)
90
+ @sampling_rate = val.to_i
91
+ @harvest_count = rand(val.to_i).to_i
92
+ end
93
+
94
+
95
+ # Creates a new transaction sample builder, unless the
96
+ # transaction sampler is disabled. Takes a time parameter for
97
+ # the start of the transaction sample
98
+ def notice_first_scope_push(time)
99
+ start_builder(time.to_f) unless disabled
100
+ end
101
+
102
+ # This delegates to the builder to create a new open transaction
103
+ # segment for the specified scope, beginning at the optionally
104
+ # specified time.
105
+ #
106
+ # Note that in developer mode, this captures a stacktrace for
107
+ # the beginning of each segment, which can be fairly slow
108
+ def notice_push_scope(scope, time=Time.now)
109
+ return unless builder
110
+
111
+ builder.trace_entry(scope, time.to_f)
112
+
113
+ capture_segment_trace if NewRelic::Control.instance.developer_mode?
114
+ end
115
+
116
+ # in developer mode, capture the stack trace with the segment.
117
+ # this is cpu and memory expensive and therefore should not be
118
+ # turned on in production mode
119
+ def capture_segment_trace
120
+ return unless NewRelic::Control.instance.developer_mode?
121
+ segment = builder.current_segment
122
+ if segment
123
+ # Strip stack frames off the top that match /new_relic/agent/
124
+ trace = caller
125
+ while trace.first =~/\/lib\/new_relic\/agent\//
126
+ trace.shift
127
+ end
128
+
129
+ trace = trace[0..39] if trace.length > 40
130
+ segment[:backtrace] = trace
131
+ end
132
+ end
133
+
134
+ # Defaults to zero, otherwise delegated to the transaction
135
+ # sample builder
136
+ def scope_depth
137
+ return 0 unless builder
138
+
139
+ builder.scope_depth
140
+ end
141
+
142
+ # Informs the transaction sample builder about the end of a
143
+ # traced scope
144
+ def notice_pop_scope(scope, time = Time.now)
145
+ return unless builder
146
+ raise "frozen already???" if builder.sample.frozen?
147
+ builder.trace_exit(scope, time.to_f)
148
+ end
149
+
150
+ # This is called when we are done with the transaction. We've
151
+ # unwound the stack to the top level. It also clears the
152
+ # transaction sample builder so that it won't continue to have
153
+ # scopes appended to it.
154
+ #
155
+ # It sets various instance variables to the finished sample,
156
+ # depending on which settings are active. See `store_sample`
157
+ def notice_scope_empty(time=Time.now)
158
+
159
+ last_builder = builder
160
+ return unless last_builder
161
+
162
+ last_builder.finish_trace(time.to_f)
163
+ clear_builder
164
+ return if last_builder.ignored?
165
+
166
+ @samples_lock.synchronize do
167
+ # NB this instance variable may be used elsewhere, it's not
168
+ # just a side effect
169
+ @last_sample = last_builder.sample
170
+ store_sample(@last_sample)
171
+ end
172
+ end
173
+
174
+ # Samples can be stored in three places: the random sample
175
+ # variable, when random sampling is active, the developer mode
176
+ # @samples array, and the @slowest_sample variable if it is
177
+ # slower than the current occupant of that slot
178
+ def store_sample(sample)
179
+ store_random_sample(sample)
180
+ store_sample_for_developer_mode(sample)
181
+ store_slowest_sample(sample)
182
+ end
183
+
184
+ # Only active when random sampling is true - this is very rarely
185
+ # used. Always store the most recent sample so that random
186
+ # sampling can pick a few of the samples to store, upon harvest
187
+ def store_random_sample(sample)
188
+ if @random_sampling
189
+ @random_sample = sample
190
+ end
191
+ end
192
+
193
+ # Samples take up a ton of memory, so we only store a lot of
194
+ # them in developer mode - we truncate to @max_samples
195
+ def store_sample_for_developer_mode(sample)
196
+ return unless NewRelic::Control.instance.developer_mode?
197
+ @samples = [] unless @samples
198
+ @samples << sample
199
+ truncate_samples
200
+ end
201
+
202
+ # Sets @slowest_sample to the passed in sample if it is slower
203
+ # than the current sample in @slowest_sample
204
+ def store_slowest_sample(sample)
205
+ @slowest_sample = sample if slowest_sample?(@slowest_sample, sample)
206
+ end
207
+
208
+ # Checks to see if the old sample exists, or if it's duration is
209
+ # less than the new sample
210
+ def slowest_sample?(old_sample, new_sample)
211
+ old_sample.nil? || (new_sample.duration > old_sample.duration)
212
+ end
213
+
214
+ # Smashes the @samples array down to the length of @max_samples
215
+ # by taking the last @max_samples elements of the array
216
+ def truncate_samples
217
+ if @samples.length > @max_samples
218
+ @samples = @samples[-@max_samples..-1]
219
+ end
220
+ end
221
+
222
+ # Delegates to the builder to store the path, uri, and
223
+ # parameters if the sampler is active
224
+ def notice_transaction(path, uri=nil, params={})
225
+ builder.set_transaction_info(path, uri, params) if !disabled && builder
226
+ end
227
+
228
+ # Tells the builder to ignore a transaction, if we are currently
229
+ # creating one. Only causes the sample to be ignored upon end of
230
+ # the transaction, and does not change the metrics gathered
231
+ # outside of the sampler
232
+ def ignore_transaction
233
+ builder.ignore_transaction if builder
234
+ end
235
+
236
+ # For developer mode profiling support - delegates to the builder
237
+ def notice_profile(profile)
238
+ builder.set_profile(profile) if builder
239
+ end
240
+
241
+ # Sets the CPU time used by a transaction, delegates to the builder
242
+ def notice_transaction_cpu_time(cpu_time)
243
+ builder.set_transaction_cpu_time(cpu_time) if builder
244
+ end
245
+
246
+ MAX_DATA_LENGTH = 16384
247
+ # This method is used to record metadata into the currently
248
+ # active segment like a sql query, memcache key, or Net::HTTP uri
249
+ #
250
+ # duration is seconds, float value.
251
+ def notice_extra_data(message, duration, key, config=nil, config_key=nil)
252
+ return unless builder
253
+ segment = builder.current_segment
254
+ if segment
255
+ segment[key] = truncate_message(append_new_message(segment[key],
256
+ message))
257
+ segment[config_key] = config if config_key
258
+ append_backtrace(segment, duration)
259
+ end
260
+ end
261
+
262
+ private :notice_extra_data
263
+
264
+ # Truncates the message to `MAX_DATA_LENGTH` if needed, and
265
+ # appends an ellipsis because it makes the trucation clearer in
266
+ # the UI
267
+ def truncate_message(message)
268
+ if message.length > (MAX_DATA_LENGTH - 4)
269
+ message[0..MAX_DATA_LENGTH - 4] + '...'
270
+ else
271
+ message
272
+ end
273
+ end
274
+
275
+ # Allows the addition of multiple pieces of metadata to one
276
+ # segment - i.e. traced method calls multiple sql queries
277
+ def append_new_message(old_message, message)
278
+ if old_message
279
+ old_message + ";\n" + message
280
+ else
281
+ message
282
+ end
283
+ end
284
+
285
+ # Appends a backtrace to a segment if that segment took longer
286
+ # than the specified duration
287
+ def append_backtrace(segment, duration)
288
+ segment[:backtrace] = caller.join("\n") if duration >= @stack_trace_threshold
289
+ end
290
+
291
+ # some statements (particularly INSERTS with large BLOBS
292
+ # may be very large; we should trim them to a maximum usable length
293
+ # config is the driver configuration for the connection
294
+ # duration is seconds, float value.
295
+ def notice_sql(sql, config, duration)
296
+ if NewRelic::Agent.is_sql_recorded?
297
+ notice_extra_data(sql, duration, :sql, config, :connection_config)
298
+ end
299
+ end
300
+
301
+ # Adds non-sql metadata to a segment - generally the memcached
302
+ # key
303
+ #
304
+ # duration is seconds, float value.
305
+ def notice_nosql(key, duration)
306
+ notice_extra_data(key, duration, :key)
307
+ end
308
+
309
+ # Every 1/n harvests, adds the most recent sample to the harvest
310
+ # array if it exists. Makes sure that the random sample is not
311
+ # also the slowest sample for this harvest by `uniq!`ing the
312
+ # result array
313
+ #
314
+ # random sampling is very, very seldom used
315
+ def add_random_sample_to(result)
316
+ return unless @random_sampling && @sampling_rate && @sampling_rate.to_i > 0
317
+ @harvest_count += 1
318
+ if (@harvest_count.to_i % @sampling_rate.to_i) == 0
319
+ result << @random_sample if @random_sample
320
+ end
321
+ result.uniq!
322
+ nil # don't assume this method returns anything
323
+ end
324
+
325
+ # Returns an array of slow samples, with either one or two
326
+ # elements - one element unless random sampling is enabled. The
327
+ # sample returned will be the slowest sample among those
328
+ # available during this harvest
329
+ def add_samples_to(result, slow_threshold)
330
+ if @slowest_sample && @slowest_sample.duration >= slow_threshold
331
+ result << @slowest_sample
332
+ end
333
+ result.compact!
334
+ result = result.sort_by { |x| x.duration }
335
+ result = result[-1..-1] || []
336
+ add_random_sample_to(result)
337
+ result
338
+ end
339
+
340
+ # get the set of collected samples, merging into previous samples,
341
+ # and clear the collected sample list. Truncates samples to a
342
+ # specified @segment_limit to save memory and bandwith
343
+ # transmitting samples to the server.
344
+ def harvest(previous = [], slow_threshold = 2.0)
345
+ return [] if disabled
346
+ result = Array(previous)
347
+ @samples_lock.synchronize do
348
+ result = add_samples_to(result, slow_threshold)
349
+ # clear previous transaction samples
350
+ @slowest_sample = nil
351
+ @random_sample = nil
352
+ @last_sample = nil
353
+ end
354
+ # Truncate the samples at 2100 segments. The UI will clamp them at 2000 segments anyway.
355
+ # This will save us memory and bandwidth.
356
+ result.each { |sample| sample.truncate(@segment_limit) }
357
+ result
358
+ end
359
+
360
+ # reset samples without rebooting the web server
361
+ def reset!
362
+ @samples = []
363
+ @last_sample = nil
364
+ @random_sample = nil
365
+ @slowest_sample = nil
366
+ end
367
+
368
+ private
369
+
370
+ # Checks to see if the transaction sampler is disabled, if
371
+ # transaction trace recording is disabled by a thread local, or
372
+ # if execution is untraced - if so it clears the transaction
373
+ # sample builder from the thread local, otherwise it generates a
374
+ # new transaction sample builder with the stated time as a
375
+ # starting point and saves it in the thread local variable
376
+ def start_builder(time=nil)
377
+ if disabled || !NewRelic::Agent.is_transaction_traced? || !NewRelic::Agent.is_execution_traced?
378
+ clear_builder
379
+ else
380
+ Thread::current[BUILDER_KEY] ||= TransactionSampleBuilder.new(time)
381
+ end
382
+ end
383
+
384
+ # The current thread-local transaction sample builder
385
+ def builder
386
+ Thread::current[BUILDER_KEY]
387
+ end
388
+
389
+ # Sets the thread local variable storing the transaction sample
390
+ # builder to nil to clear it
391
+ def clear_builder
392
+ Thread::current[BUILDER_KEY] = nil
393
+ end
394
+
395
+ end
396
+ end
397
+ end
@@ -0,0 +1,89 @@
1
+ require 'thread'
2
+ module NewRelic
3
+ module Agent
4
+
5
+ # A worker loop executes a set of registered tasks on a single thread.
6
+ # A task is a proc or block with a specified call period in seconds.
7
+ class WorkerLoop
8
+
9
+ def initialize
10
+ @log = log
11
+ @should_run = true
12
+ @next_invocation_time = Time.now
13
+ @period = 60.0
14
+ end
15
+
16
+ # returns a class-level memoized mutex to make sure we don't run overlapping
17
+ def lock
18
+ @@lock ||= Mutex.new
19
+ end
20
+
21
+ # a helper to access the NewRelic::Control.instance.log
22
+ def log
23
+ NewRelic::Control.instance.log
24
+ end
25
+
26
+ # Run infinitely, calling the registered tasks at their specified
27
+ # call periods. The caller is responsible for creating the thread
28
+ # that runs this worker loop. This will run the task immediately.
29
+ def run(period=nil, &block)
30
+ @period = period if period
31
+ @next_invocation_time = (Time.now + @period)
32
+ @task = block
33
+ while keep_running do
34
+ now = Time.now
35
+ while now < @next_invocation_time
36
+ # sleep until this next task's scheduled invocation time
37
+ sleep_time = @next_invocation_time - now
38
+ sleep sleep_time if sleep_time > 0
39
+ now = Time.now
40
+ end
41
+ run_task if keep_running
42
+ end
43
+ end
44
+
45
+ # a simple accessor for @should_run
46
+ def keep_running
47
+ @should_run
48
+ end
49
+
50
+ # Sets @should_run to false. Returns false
51
+ def stop
52
+ @should_run = false
53
+ end
54
+
55
+ # Executes the block given to the worker loop, and handles many
56
+ # possible errors. Also updates the execution time so that the
57
+ # next run occurs on schedule, even if we execute at some odd time
58
+ def run_task
59
+ begin
60
+ lock.synchronize do
61
+ @task.call
62
+ end
63
+ rescue ServerError => e
64
+ log.debug "Server Error: #{e}"
65
+ rescue NewRelic::Agent::ForceRestartException, NewRelic::Agent::ForceDisconnectException
66
+ # blow out the loop
67
+ raise
68
+ rescue RuntimeError => e
69
+ # This is probably a server error which has been logged in the server along
70
+ # with your account name.
71
+ log.error "Error running task in worker loop, likely a server error (#{e})"
72
+ log.debug e.backtrace.join("\n")
73
+ rescue Timeout::Error, NewRelic::Agent::ServerConnectionException
74
+ # Want to ignore these because they are handled already
75
+ rescue SystemExit, NoMemoryError, SignalException
76
+ raise
77
+ rescue Exception => e
78
+ # Don't blow out the stack for anything that hasn't already propagated
79
+ log.error "Error running task in Agent Worker Loop '#{e}': #{e.backtrace.first}"
80
+ log.debug e.backtrace.join("\n")
81
+ end
82
+ now = Time.now
83
+ while @next_invocation_time <= now && @period > 0
84
+ @next_invocation_time += @period
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end