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,388 @@
1
+
2
+ module NewRelic
3
+ module Stats
4
+
5
+ # a stat is absent if its call count equals zero
6
+ def absent?
7
+ call_count == 0
8
+ end
9
+
10
+ # outputs a useful human-readable time given a value in milliseconds
11
+ def time_str(value_ms)
12
+ case
13
+ when value_ms >= 10000
14
+ "%.1f s" % (value_ms / 1000.0)
15
+ when value_ms >= 5000
16
+ "%.2f s" % (value_ms / 1000.0)
17
+ else
18
+ "%.0f ms" % value_ms
19
+ end
20
+ end
21
+
22
+ # makes sure we aren't dividing by zero
23
+ def checked_calculation(numerator, denominator)
24
+ if denominator.nil? || denominator == 0
25
+ 0.0
26
+ else
27
+ numerator.to_f / denominator
28
+ end
29
+ end
30
+
31
+ def average_call_time
32
+ checked_calculation(total_call_time, call_count)
33
+ end
34
+ def average_exclusive_time
35
+ checked_calculation(total_exclusive_time, call_count)
36
+ end
37
+
38
+ # merge by adding to average response time
39
+ # - used to compose multiple metrics e.g. dispatcher time + mongrel queue time
40
+ def sum_merge! (other_stats)
41
+ Array(other_stats).each do |other|
42
+ self.sum_attributes(other)
43
+ end
44
+ self
45
+ end
46
+
47
+ def sum_attributes(other)
48
+ update_totals(other)
49
+ stack_min_max_from(other)
50
+ self.call_count = [self.call_count, other.call_count].max
51
+ update_boundaries(other)
52
+ end
53
+
54
+ def stack_min_max_from(other)
55
+ self.min_call_time += other.min_call_time
56
+ self.max_call_time += other.max_call_time
57
+ end
58
+
59
+ def update_boundaries(other)
60
+ self.begin_time = other.begin_time if should_replace_begin_time?(other)
61
+ self.end_time = other.end_time if should_replace_end_time?(other)
62
+ end
63
+
64
+ def should_replace_end_time?(other)
65
+ end_time.to_f < other.end_time.to_f
66
+ end
67
+
68
+ def should_replace_begin_time?(other)
69
+ other.begin_time.to_f < begin_time.to_f || begin_time.to_f == 0.0
70
+ end
71
+
72
+ def update_totals(other)
73
+ self.total_call_time += other.total_call_time
74
+ self.total_exclusive_time += other.total_exclusive_time
75
+ self.sum_of_squares += other.sum_of_squares
76
+ end
77
+
78
+ def min_time_less?(other)
79
+ (other.min_call_time < min_call_time && other.call_count > 0) || call_count == 0
80
+ end
81
+
82
+ def expand_min_max_to(other)
83
+ self.min_call_time = other.min_call_time if min_time_less?(other)
84
+ self.max_call_time = other.max_call_time if other.max_call_time > max_call_time
85
+ end
86
+
87
+ def merge_attributes(other)
88
+ update_totals(other)
89
+ expand_min_max_to(other)
90
+ self.call_count += other.call_count
91
+ update_boundaries(other)
92
+ end
93
+
94
+ def merge!(other_stats)
95
+ Array(other_stats).each do |other|
96
+ merge_attributes(other)
97
+ end
98
+
99
+ self
100
+ end
101
+
102
+ def merge(other_stats)
103
+ stats = self.clone
104
+ stats.merge!(other_stats)
105
+ end
106
+
107
+ # split into an array of timeslices whose
108
+ # time boundaries start on (begin_time + (n * duration)) and whose
109
+ # end time ends on (begin_time * (n + 1) * duration), except for the
110
+ # first and last elements, whose begin time and end time are the begin
111
+ # and end times of this stats instance, respectively. Yield to caller
112
+ # for the code that creates the actual stats instance
113
+ def split(rollup_begin_time, rollup_period)
114
+ rollup_begin_time = rollup_begin_time.to_f
115
+ rollup_begin_time += ((self.begin_time - rollup_begin_time) / rollup_period).floor * rollup_period
116
+
117
+ current_begin_time = self.begin_time
118
+ current_end_time = rollup_begin_time + rollup_period
119
+
120
+ return [self] if current_end_time >= self.end_time
121
+
122
+ timeslices = []
123
+ while current_end_time < self.end_time do
124
+ ts = yield(current_begin_time, current_end_time)
125
+ if ts
126
+ ts.fraction_of(self)
127
+ timeslices << ts
128
+ end
129
+ current_begin_time = current_end_time
130
+ current_end_time = current_begin_time + rollup_period
131
+ end
132
+
133
+ if self.end_time > current_begin_time
134
+ percentage = rollup_period / self.duration + (self.begin_time - rollup_begin_time) / rollup_period
135
+ ts = yield(current_begin_time, self.end_time)
136
+ if ts
137
+ ts.fraction_of(self)
138
+ timeslices << ts
139
+ end
140
+ end
141
+
142
+ timeslices
143
+ end
144
+
145
+ def is_reset?
146
+ call_count == 0 && total_call_time == 0.0 && total_exclusive_time == 0.0
147
+ end
148
+
149
+ def reset
150
+ self.call_count = 0
151
+ self.total_call_time = 0.0
152
+ self.total_exclusive_time = 0.0
153
+ self.min_call_time = 0.0
154
+ self.max_call_time = 0.0
155
+ self.sum_of_squares = 0.0
156
+ self.begin_time = Time.at(0)
157
+ self.end_time = Time.at(0)
158
+ end
159
+
160
+ def as_percentage_of(other_stats)
161
+ checked_calculation(total_call_time, other_stats.total_call_time) * 100.0
162
+ end
163
+
164
+ # the stat total_call_time is a percent
165
+ def as_percentage
166
+ average_call_time * 100.0
167
+ end
168
+
169
+ def duration
170
+ end_time ? (end_time - begin_time) : 0.0
171
+ end
172
+
173
+ def midpoint
174
+ begin_time + (duration/2)
175
+ end
176
+ def calls_per_minute
177
+ checked_calculation(call_count, duration) * 60
178
+ end
179
+
180
+ def total_call_time_per_minute
181
+ 60.0 * time_percentage
182
+ end
183
+
184
+ def standard_deviation
185
+ return 0 if call_count < 2 || self.sum_of_squares.nil?
186
+
187
+ # Convert sum of squares into standard deviation based on
188
+ # formula for the standard deviation for the entire population
189
+ x = self.sum_of_squares - (self.call_count * (self.average_value**2))
190
+ return 0 if x <= 0
191
+
192
+ Math.sqrt(x / self.call_count)
193
+ end
194
+
195
+ # returns the time spent in this component as a percentage of the total
196
+ # time window.
197
+ def time_percentage
198
+ checked_calculation(total_call_time, duration)
199
+ end
200
+
201
+ def exclusive_time_percentage
202
+ checked_calculation(total_exclusive_time, duration)
203
+ end
204
+
205
+ alias average_value average_call_time
206
+ alias average_response_time average_call_time
207
+ alias requests_per_minute calls_per_minute
208
+
209
+ def to_s
210
+ summary
211
+ end
212
+
213
+ # Summary string to facilitate testing
214
+ def summary
215
+ format = "%m/%d/%y %I:%M%p"
216
+ "[#{Time.at(begin_time.to_f).utc.strftime(format)} UTC, #{'%2.3fs' % duration.to_f}; #{'%2i' % call_count.to_i} calls #{'%4i' % average_call_time.to_f}s]"
217
+ end
218
+
219
+ # calculate this set of stats to be a percentage fraction
220
+ # of the provided stats, which has an overlapping time window.
221
+ # used as a key part of the split algorithm
222
+ def fraction_of(s)
223
+ min_end = (end_time < s.end_time ? end_time : s.end_time)
224
+ max_begin = (begin_time > s.begin_time ? begin_time : s.begin_time)
225
+ percentage = (min_end - max_begin) / s.duration
226
+
227
+ self.total_exclusive_time = s.total_exclusive_time * percentage
228
+ self.total_call_time = s.total_call_time * percentage
229
+ self.min_call_time = s.min_call_time
230
+ self.max_call_time = s.max_call_time
231
+ self.call_count = s.call_count * percentage
232
+ self.sum_of_squares = (s.sum_of_squares || 0) * percentage
233
+ end
234
+
235
+ # multiply the total time and rate by the given percentage
236
+ def multiply_by(percentage)
237
+ self.total_call_time = total_call_time * percentage
238
+ self.call_count = call_count * percentage
239
+ self.sum_of_squares = sum_of_squares * percentage
240
+
241
+ self
242
+ end
243
+
244
+ # returns s,t,f
245
+ def get_apdex
246
+ [@call_count, @total_call_time.to_i, @total_exclusive_time.to_i]
247
+ end
248
+
249
+ def apdex_score
250
+ s, t, f = get_apdex
251
+ (s.to_f + (t.to_f / 2)) / (s+t+f).to_f
252
+ end
253
+ end
254
+
255
+
256
+ class StatsBase
257
+ include Stats
258
+
259
+ attr_accessor :call_count
260
+ attr_accessor :min_call_time
261
+ attr_accessor :max_call_time
262
+ attr_accessor :total_call_time
263
+ attr_accessor :total_exclusive_time
264
+ attr_accessor :sum_of_squares
265
+
266
+ def initialize
267
+ reset
268
+ end
269
+
270
+ def freeze
271
+ @end_time = Time.now
272
+ super
273
+ end
274
+
275
+ def to_json(*a)
276
+ {'call_count' => call_count,
277
+ 'min_call_time' => min_call_time,
278
+ 'max_call_time' => max_call_time,
279
+ 'total_call_time' => total_call_time,
280
+ 'total_exclusive_time' => total_exclusive_time,
281
+ 'sum_of_squares' => sum_of_squares}.to_json(*a)
282
+ end
283
+
284
+
285
+ # In this class, we explicitly don't track begin and end time here, to save space during
286
+ # cross process serialization via xml. Still the accessor methods must be provided for merge to work.
287
+ def begin_time=(t)
288
+ end
289
+
290
+ def end_time=(t)
291
+ end
292
+
293
+ def begin_time
294
+ 0.0
295
+ end
296
+
297
+ def end_time
298
+ 0.0
299
+ end
300
+ end
301
+
302
+
303
+ class BasicStats < StatsBase
304
+ end
305
+
306
+ class ApdexStats < StatsBase
307
+
308
+ def record_apdex_s
309
+ @call_count += 1
310
+ end
311
+
312
+ def record_apdex_t
313
+ @total_call_time += 1
314
+ end
315
+
316
+ def record_apdex_f
317
+ @total_exclusive_time += 1
318
+ end
319
+ end
320
+
321
+ # Statistics used to track the performance of traced methods
322
+ class MethodTraceStats < StatsBase
323
+
324
+ alias data_point_count call_count
325
+
326
+ # record a single data point into the statistical gatherer. The gatherer
327
+ # will aggregate all data points collected over a specified period and upload
328
+ # its data to the NewRelic server
329
+ def record_data_point(value, exclusive_time = value)
330
+ @call_count += 1
331
+ @total_call_time += value
332
+ @min_call_time = value if value < @min_call_time || @call_count == 1
333
+ @max_call_time = value if value > @max_call_time
334
+ @total_exclusive_time += exclusive_time
335
+
336
+ @sum_of_squares += (value * value)
337
+ self
338
+ end
339
+
340
+ alias trace_call record_data_point
341
+
342
+ # Records multiple data points as one method call - this handles
343
+ # all the aggregation that would be done with multiple
344
+ # record_data_point calls
345
+ def record_multiple_data_points(total_value, count=1)
346
+ return record_data_point(total_value) if count == 1
347
+ @call_count += count
348
+ @total_call_time += total_value
349
+ avg_val = total_value / count
350
+ @min_call_time = avg_val if avg_val < @min_call_time || @call_count == count
351
+ @max_call_time = avg_val if avg_val > @max_call_time
352
+ @total_exclusive_time += total_value
353
+ @sum_of_squares += (avg_val * avg_val) * count
354
+ self
355
+ end
356
+
357
+ # increments the call_count by one
358
+ def increment_count(value = 1)
359
+ @call_count += value
360
+ end
361
+
362
+ # outputs a human-readable version of the MethodTraceStats object
363
+ def inspect
364
+ "#<NewRelic::MethodTraceStats #{summary} >"
365
+ end
366
+
367
+ end
368
+
369
+ class ScopedMethodTraceStats < MethodTraceStats
370
+ attr_accessor :unscoped_stats
371
+ def initialize(unscoped_stats)
372
+ super()
373
+ self.unscoped_stats = unscoped_stats
374
+ end
375
+ def trace_call(call_time, exclusive_time = call_time)
376
+ unscoped_stats.trace_call call_time, exclusive_time
377
+ super call_time, exclusive_time
378
+ end
379
+ # Records multiple data points as one method call - this handles
380
+ # all the aggregation that would be done with multiple
381
+ # trace_call calls
382
+ def record_multiple_data_points(total_value, count=1)
383
+ unscoped_stats.record_multiple_data_points(total_value, count)
384
+ super total_value, count
385
+ end
386
+ end
387
+ end
388
+
@@ -0,0 +1,27 @@
1
+ # Copyright: (C) 2008 David Vollbracht & Philippe Hanrigou
2
+
3
+ # This code was borrowed from the system_timer gem under the terms
4
+ # of the Ruby license. It has been slightly modified.
5
+
6
+ # Defines the constant TimerLib to the appropriate timeout library
7
+ module NewRelic #:nodoc:
8
+
9
+ begin
10
+ # Try to use the SystemTimer gem instead of Ruby's timeout library
11
+ # when running on Ruby 1.8.x. See:
12
+ # http://ph7spot.com/articles/system_timer
13
+ # We don't want to bother trying to load SystemTimer on jruby,
14
+ # ruby 1.9+ and rbx.
15
+ if !defined?(RUBY_ENGINE) || (RUBY_ENGINE == 'ruby' && RUBY_VERSION < '1.9.0')
16
+ require 'system_timer'
17
+ TimerLib = SystemTimer
18
+ else
19
+ require 'timeout'
20
+ TimerLib = Timeout
21
+ end
22
+ rescue LoadError => e
23
+ require 'timeout'
24
+ TimerLib = Timeout
25
+ end
26
+
27
+ end
@@ -0,0 +1,49 @@
1
+ module NewRelic
2
+ module TransactionAnalysis
3
+ # summarizes performance data for all calls to segments
4
+ # with the same metric_name
5
+ class SegmentSummary
6
+ attr_accessor :metric_name, :total_time, :exclusive_time, :call_count, :current_nest_count
7
+ def initialize(metric_name, sample)
8
+ @metric_name = metric_name
9
+ @total_time, @exclusive_time, @call_count = 0,0,0
10
+ @sample = sample
11
+ @current_nest_count = 0
12
+ end
13
+
14
+ def <<(segment)
15
+ if metric_name != segment.metric_name
16
+ raise ArgumentError, "Metric Name Mismatch: #{segment.metric_name} != #{metric_name}"
17
+ end
18
+
19
+ # a nested segment should use the sum of the top level totals
20
+ @total_time += segment.duration if current_nest_count == 0
21
+ @exclusive_time += segment.exclusive_duration
22
+ @call_count += 1
23
+ end
24
+
25
+ def average_time
26
+ @total_time / @call_count
27
+ end
28
+
29
+ def average_exclusive_time
30
+ @exclusive_time / @call_count
31
+ end
32
+
33
+ def exclusive_time_percentage
34
+ return 0 unless @exclusive_time && @sample.duration && @sample.duration > 0
35
+ @exclusive_time / @sample.duration
36
+ end
37
+
38
+ def total_time_percentage
39
+ return 0 unless @total_time && @sample.duration && @sample.duration > 0
40
+ @total_time / @sample.duration
41
+ end
42
+
43
+ def ui_name
44
+ return @metric_name if @metric_name == 'Remainder'
45
+ NewRelic::MetricParser::MetricParser.parse(@metric_name).developer_name
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,77 @@
1
+ require 'new_relic/transaction_analysis/segment_summary'
2
+ # Add these methods to TransactionSample that enable performance analysis in the user interface.
3
+ module NewRelic
4
+ module TransactionAnalysis
5
+ def database_time
6
+ time_percentage(/^Database\/.*/)
7
+ end
8
+
9
+ def render_time
10
+ time_percentage(/^View\/.*/)
11
+ end
12
+
13
+ # return the data that breaks down the performance of the transaction
14
+ # as an array of SegmentSummary objects. If a limit is specified, then
15
+ # limit the data set to the top n
16
+ def breakdown_data(limit = nil)
17
+ metric_hash = {}
18
+ each_segment_with_nest_tracking do |segment|
19
+ unless segment == root_segment
20
+ metric_name = segment.metric_name
21
+ metric_hash[metric_name] ||= SegmentSummary.new(metric_name, self)
22
+ metric_hash[metric_name] << segment
23
+ metric_hash[metric_name]
24
+ end
25
+ end
26
+
27
+ data = metric_hash.values
28
+
29
+ data.sort! do |x,y|
30
+ y.exclusive_time <=> x.exclusive_time
31
+ end
32
+
33
+ if limit && data.length > limit
34
+ data = data[0..limit - 1]
35
+ end
36
+
37
+ # add one last segment for the remaining time if any
38
+ remainder = duration
39
+ data.each do |segment|
40
+ remainder -= segment.exclusive_time
41
+ end
42
+
43
+ if (remainder*1000).round > 0
44
+ remainder_summary = SegmentSummary.new('Remainder', self)
45
+ remainder_summary.total_time = remainder_summary.exclusive_time = remainder
46
+ remainder_summary.call_count = 1
47
+ data << remainder_summary
48
+ end
49
+
50
+ data
51
+ end
52
+
53
+ # return an array of sql statements executed by this transaction
54
+ # each element in the array contains [sql, parent_segment_metric_name, duration]
55
+ def sql_segments(show_non_sql_segments = true)
56
+ segments = []
57
+ each_segment do |segment|
58
+ segments << segment if segment[:sql] || segment[:sql_obfuscated] || (show_non_sql_segments && segment[:key])
59
+ end
60
+ segments
61
+ end
62
+
63
+ private
64
+ def time_percentage(regex)
65
+ total = 0
66
+ each_segment do |segment|
67
+ if regex =~ segment.metric_name
68
+ total += segment.duration
69
+ end
70
+ end
71
+ fraction = 100.0 * total / duration
72
+ # percent value rounded to two digits:
73
+ return (100 * fraction).round / 100.0
74
+ end
75
+ end
76
+ end
77
+
@@ -0,0 +1,27 @@
1
+ require 'new_relic/transaction_sample'
2
+ require 'new_relic/transaction_sample/segment'
3
+ require 'new_relic/transaction_sample/summary_segment'
4
+ module NewRelic
5
+ class TransactionSample
6
+ class CompositeSegment < Segment
7
+ attr_reader :detail_segments
8
+
9
+ def initialize(segments)
10
+ summary = SummarySegment.new(segments.first)
11
+ super summary.entry_timestamp, "Repeating pattern (#{segments.length} repeats)", nil
12
+
13
+ summary.end_trace(segments.last.exit_timestamp)
14
+
15
+ @detail_segments = segments.clone
16
+
17
+ add_called_segment(summary)
18
+ end_trace summary.exit_timestamp
19
+ end
20
+
21
+ def detail_segments=(segments)
22
+ @detail_segments = segments
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,9 @@
1
+ require 'new_relic/transaction_sample'
2
+ require 'new_relic/transaction_sample/segment'
3
+ module NewRelic
4
+ class TransactionSample
5
+ class FakeSegment < Segment
6
+ public :parent_segment=
7
+ end
8
+ end
9
+ end