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.
- data/CHANGELOG +559 -0
- data/LICENSE +64 -0
- data/README.rdoc +179 -0
- data/bin/mongrel_rpm +33 -0
- data/bin/newrelic +13 -0
- data/bin/newrelic_cmd +5 -0
- data/cert/cacert.pem +118 -0
- data/cert/oldsite.pem +28 -0
- data/cert/site.pem +27 -0
- data/dolores_rpm-3.3.4.fork.gem +0 -0
- data/install.rb +9 -0
- data/lib/conditional_vendored_dependency_detection.rb +3 -0
- data/lib/conditional_vendored_metric_parser.rb +5 -0
- data/lib/new_relic/agent/agent.rb +1311 -0
- data/lib/new_relic/agent/beacon_configuration.rb +110 -0
- data/lib/new_relic/agent/browser_monitoring.rb +102 -0
- data/lib/new_relic/agent/busy_calculator.rb +99 -0
- data/lib/new_relic/agent/chained_call.rb +13 -0
- data/lib/new_relic/agent/database.rb +203 -0
- data/lib/new_relic/agent/error_collector.rb +251 -0
- data/lib/new_relic/agent/instrumentation/active_merchant.rb +27 -0
- data/lib/new_relic/agent/instrumentation/acts_as_solr.rb +68 -0
- data/lib/new_relic/agent/instrumentation/authlogic.rb +19 -0
- data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +424 -0
- data/lib/new_relic/agent/instrumentation/data_mapper.rb +57 -0
- data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +52 -0
- data/lib/new_relic/agent/instrumentation/memcache.rb +80 -0
- data/lib/new_relic/agent/instrumentation/merb/controller.rb +41 -0
- data/lib/new_relic/agent/instrumentation/merb/errors.rb +29 -0
- data/lib/new_relic/agent/instrumentation/metric_frame/pop.rb +80 -0
- data/lib/new_relic/agent/instrumentation/metric_frame.rb +332 -0
- data/lib/new_relic/agent/instrumentation/net.rb +29 -0
- data/lib/new_relic/agent/instrumentation/passenger_instrumentation.rb +36 -0
- data/lib/new_relic/agent/instrumentation/queue_time.rb +210 -0
- data/lib/new_relic/agent/instrumentation/rack.rb +98 -0
- data/lib/new_relic/agent/instrumentation/rails/action_controller.rb +114 -0
- data/lib/new_relic/agent/instrumentation/rails/action_web_service.rb +42 -0
- data/lib/new_relic/agent/instrumentation/rails/active_record_instrumentation.rb +115 -0
- data/lib/new_relic/agent/instrumentation/rails/errors.rb +42 -0
- data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +118 -0
- data/lib/new_relic/agent/instrumentation/rails3/active_record_instrumentation.rb +122 -0
- data/lib/new_relic/agent/instrumentation/rails3/errors.rb +37 -0
- data/lib/new_relic/agent/instrumentation/sinatra.rb +58 -0
- data/lib/new_relic/agent/instrumentation/sunspot.rb +29 -0
- data/lib/new_relic/agent/instrumentation/unicorn_instrumentation.rb +21 -0
- data/lib/new_relic/agent/instrumentation.rb +9 -0
- data/lib/new_relic/agent/method_tracer.rb +528 -0
- data/lib/new_relic/agent/sampler.rb +50 -0
- data/lib/new_relic/agent/samplers/cpu_sampler.rb +58 -0
- data/lib/new_relic/agent/samplers/delayed_job_lock_sampler.rb +40 -0
- data/lib/new_relic/agent/samplers/memory_sampler.rb +144 -0
- data/lib/new_relic/agent/samplers/object_sampler.rb +26 -0
- data/lib/new_relic/agent/shim_agent.rb +29 -0
- data/lib/new_relic/agent/sql_sampler.rb +267 -0
- data/lib/new_relic/agent/stats_engine/metric_stats.rb +187 -0
- data/lib/new_relic/agent/stats_engine/samplers.rb +95 -0
- data/lib/new_relic/agent/stats_engine/transactions.rb +208 -0
- data/lib/new_relic/agent/stats_engine.rb +25 -0
- data/lib/new_relic/agent/transaction_sample_builder.rb +101 -0
- data/lib/new_relic/agent/transaction_sampler.rb +397 -0
- data/lib/new_relic/agent/worker_loop.rb +89 -0
- data/lib/new_relic/agent.rb +454 -0
- data/lib/new_relic/collection_helper.rb +75 -0
- data/lib/new_relic/command.rb +85 -0
- data/lib/new_relic/commands/deployments.rb +105 -0
- data/lib/new_relic/commands/install.rb +80 -0
- data/lib/new_relic/control/class_methods.rb +53 -0
- data/lib/new_relic/control/configuration.rb +202 -0
- data/lib/new_relic/control/frameworks/external.rb +16 -0
- data/lib/new_relic/control/frameworks/merb.rb +31 -0
- data/lib/new_relic/control/frameworks/rails.rb +164 -0
- data/lib/new_relic/control/frameworks/rails3.rb +75 -0
- data/lib/new_relic/control/frameworks/ruby.rb +42 -0
- data/lib/new_relic/control/frameworks/sinatra.rb +20 -0
- data/lib/new_relic/control/frameworks.rb +10 -0
- data/lib/new_relic/control/instance_methods.rb +179 -0
- data/lib/new_relic/control/instrumentation.rb +100 -0
- data/lib/new_relic/control/logging_methods.rb +143 -0
- data/lib/new_relic/control/profiling.rb +25 -0
- data/lib/new_relic/control/server_methods.rb +114 -0
- data/lib/new_relic/control.rb +46 -0
- data/lib/new_relic/data_serialization.rb +157 -0
- data/lib/new_relic/delayed_job_injection.rb +46 -0
- data/lib/new_relic/language_support.rb +69 -0
- data/lib/new_relic/local_environment.rb +414 -0
- data/lib/new_relic/merbtasks.rb +6 -0
- data/lib/new_relic/metric_data.rb +51 -0
- data/lib/new_relic/metric_spec.rb +75 -0
- data/lib/new_relic/metrics.rb +9 -0
- data/lib/new_relic/noticed_error.rb +24 -0
- data/lib/new_relic/rack/browser_monitoring.rb +68 -0
- data/lib/new_relic/rack/developer_mode.rb +268 -0
- data/lib/new_relic/recipes.rb +73 -0
- data/lib/new_relic/stats.rb +388 -0
- data/lib/new_relic/timer_lib.rb +27 -0
- data/lib/new_relic/transaction_analysis/segment_summary.rb +49 -0
- data/lib/new_relic/transaction_analysis.rb +77 -0
- data/lib/new_relic/transaction_sample/composite_segment.rb +27 -0
- data/lib/new_relic/transaction_sample/fake_segment.rb +9 -0
- data/lib/new_relic/transaction_sample/segment.rb +201 -0
- data/lib/new_relic/transaction_sample/summary_segment.rb +21 -0
- data/lib/new_relic/transaction_sample.rb +245 -0
- data/lib/new_relic/url_rule.rb +14 -0
- data/lib/new_relic/version.rb +55 -0
- data/lib/newrelic_rpm.rb +49 -0
- data/lib/tasks/all.rb +4 -0
- data/lib/tasks/install.rake +7 -0
- data/lib/tasks/tests.rake +19 -0
- data/newrelic.yml +265 -0
- data/recipes/newrelic.rb +6 -0
- data/test/active_record_fixtures.rb +77 -0
- data/test/config/newrelic.yml +48 -0
- data/test/config/test_control.rb +48 -0
- data/test/new_relic/agent/agent/connect_test.rb +410 -0
- data/test/new_relic/agent/agent/start_test.rb +255 -0
- data/test/new_relic/agent/agent/start_worker_thread_test.rb +153 -0
- data/test/new_relic/agent/agent_test.rb +139 -0
- data/test/new_relic/agent/agent_test_controller.rb +77 -0
- data/test/new_relic/agent/agent_test_controller_test.rb +363 -0
- data/test/new_relic/agent/apdex_from_server_test.rb +9 -0
- data/test/new_relic/agent/beacon_configuration_test.rb +108 -0
- data/test/new_relic/agent/browser_monitoring_test.rb +278 -0
- data/test/new_relic/agent/busy_calculator_test.rb +81 -0
- data/test/new_relic/agent/database_test.rb +162 -0
- data/test/new_relic/agent/error_collector/notice_error_test.rb +257 -0
- data/test/new_relic/agent/error_collector_test.rb +175 -0
- data/test/new_relic/agent/instrumentation/active_record_instrumentation_test.rb +538 -0
- data/test/new_relic/agent/instrumentation/controller_instrumentation_test.rb +36 -0
- data/test/new_relic/agent/instrumentation/instrumentation_test.rb +11 -0
- data/test/new_relic/agent/instrumentation/metric_frame/pop_test.rb +172 -0
- data/test/new_relic/agent/instrumentation/metric_frame_test.rb +50 -0
- data/test/new_relic/agent/instrumentation/net_instrumentation_test.rb +84 -0
- data/test/new_relic/agent/instrumentation/queue_time_test.rb +387 -0
- data/test/new_relic/agent/instrumentation/rack_test.rb +35 -0
- data/test/new_relic/agent/instrumentation/task_instrumentation_test.rb +184 -0
- data/test/new_relic/agent/memcache_instrumentation_test.rb +143 -0
- data/test/new_relic/agent/method_tracer/class_methods/add_method_tracer_test.rb +164 -0
- data/test/new_relic/agent/method_tracer/instance_methods/trace_execution_scoped_test.rb +234 -0
- data/test/new_relic/agent/method_tracer_test.rb +386 -0
- data/test/new_relic/agent/mock_scope_listener.rb +23 -0
- data/test/new_relic/agent/rpm_agent_test.rb +149 -0
- data/test/new_relic/agent/sampler_test.rb +19 -0
- data/test/new_relic/agent/shim_agent_test.rb +20 -0
- data/test/new_relic/agent/sql_sampler_test.rb +160 -0
- data/test/new_relic/agent/stats_engine/metric_stats/harvest_test.rb +150 -0
- data/test/new_relic/agent/stats_engine/metric_stats_test.rb +82 -0
- data/test/new_relic/agent/stats_engine/samplers_test.rb +99 -0
- data/test/new_relic/agent/stats_engine_test.rb +185 -0
- data/test/new_relic/agent/transaction_sample_builder_test.rb +195 -0
- data/test/new_relic/agent/transaction_sampler_test.rb +955 -0
- data/test/new_relic/agent/worker_loop_test.rb +66 -0
- data/test/new_relic/agent_test.rb +175 -0
- data/test/new_relic/collection_helper_test.rb +149 -0
- data/test/new_relic/command/deployments_test.rb +68 -0
- data/test/new_relic/control/class_methods_test.rb +62 -0
- data/test/new_relic/control/configuration_test.rb +72 -0
- data/test/new_relic/control/logging_methods_test.rb +185 -0
- data/test/new_relic/control_test.rb +254 -0
- data/test/new_relic/data_serialization_test.rb +208 -0
- data/test/new_relic/delayed_job_injection_test.rb +16 -0
- data/test/new_relic/local_environment_test.rb +72 -0
- data/test/new_relic/metric_data_test.rb +125 -0
- data/test/new_relic/metric_spec_test.rb +95 -0
- data/test/new_relic/rack/all_test.rb +11 -0
- data/test/new_relic/rack/browser_monitoring_test.rb +84 -0
- data/test/new_relic/rack/developer_mode_helper_test.rb +141 -0
- data/test/new_relic/rack/developer_mode_test.rb +43 -0
- data/test/new_relic/stats_test.rb +426 -0
- data/test/new_relic/transaction_analysis/segment_summary_test.rb +91 -0
- data/test/new_relic/transaction_analysis_test.rb +121 -0
- data/test/new_relic/transaction_sample/composite_segment_test.rb +35 -0
- data/test/new_relic/transaction_sample/fake_segment_test.rb +17 -0
- data/test/new_relic/transaction_sample/segment_test.rb +389 -0
- data/test/new_relic/transaction_sample/summary_segment_test.rb +31 -0
- data/test/new_relic/transaction_sample_subtest_test.rb +56 -0
- data/test/new_relic/transaction_sample_test.rb +164 -0
- data/test/new_relic/version_number_test.rb +89 -0
- data/test/test_contexts.rb +29 -0
- data/test/test_helper.rb +154 -0
- data/ui/helpers/developer_mode_helper.rb +357 -0
- data/ui/helpers/google_pie_chart.rb +48 -0
- data/ui/views/layouts/newrelic_default.rhtml +47 -0
- data/ui/views/newrelic/_explain_plans.rhtml +27 -0
- data/ui/views/newrelic/_sample.rhtml +20 -0
- data/ui/views/newrelic/_segment.rhtml +28 -0
- data/ui/views/newrelic/_segment_limit_message.rhtml +1 -0
- data/ui/views/newrelic/_segment_row.rhtml +12 -0
- data/ui/views/newrelic/_show_sample_detail.rhtml +24 -0
- data/ui/views/newrelic/_show_sample_sql.rhtml +24 -0
- data/ui/views/newrelic/_show_sample_summary.rhtml +3 -0
- data/ui/views/newrelic/_sql_row.rhtml +16 -0
- data/ui/views/newrelic/_stack_trace.rhtml +15 -0
- data/ui/views/newrelic/_table.rhtml +12 -0
- data/ui/views/newrelic/explain_sql.rhtml +43 -0
- data/ui/views/newrelic/file/images/arrow-close.png +0 -0
- data/ui/views/newrelic/file/images/arrow-open.png +0 -0
- data/ui/views/newrelic/file/images/blue_bar.gif +0 -0
- data/ui/views/newrelic/file/images/file_icon.png +0 -0
- data/ui/views/newrelic/file/images/gray_bar.gif +0 -0
- data/ui/views/newrelic/file/images/new-relic-rpm-desktop.gif +0 -0
- data/ui/views/newrelic/file/images/new_relic_rpm_desktop.gif +0 -0
- data/ui/views/newrelic/file/images/textmate.png +0 -0
- data/ui/views/newrelic/file/javascript/jquery-1.4.2.js +6240 -0
- data/ui/views/newrelic/file/javascript/transaction_sample.js +120 -0
- data/ui/views/newrelic/file/stylesheets/style.css +490 -0
- data/ui/views/newrelic/index.rhtml +71 -0
- data/ui/views/newrelic/sample_not_found.rhtml +2 -0
- data/ui/views/newrelic/show_sample.rhtml +80 -0
- data/ui/views/newrelic/show_source.rhtml +3 -0
- data/ui/views/newrelic/threads.rhtml +53 -0
- data/vendor/gems/dependency_detection-0.0.1.build/LICENSE +5 -0
- data/vendor/gems/dependency_detection-0.0.1.build/lib/dependency_detection/version.rb +3 -0
- data/vendor/gems/dependency_detection-0.0.1.build/lib/dependency_detection.rb +62 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/metric_parser.rb +1 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/action_mailer.rb +14 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/active_merchant.rb +31 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/active_record.rb +33 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/apdex.rb +89 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/background_transaction.rb +7 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/client.rb +46 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/controller.rb +67 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/controller_cpu.rb +43 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/controller_ext.rb +17 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/database.rb +48 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/database_pool.rb +24 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/dot_net.rb +28 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/dot_net_parser.rb +17 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/errors.rb +11 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/external.rb +55 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/frontend.rb +40 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/gc.rb +20 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/hibernate_session.rb +7 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/java.rb +31 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/java_parser.rb +17 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/jsp.rb +34 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/jsp_tag.rb +7 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/mem_cache.rb +55 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/metric_parser.rb +122 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/orm.rb +27 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/other_transaction.rb +40 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/servlet.rb +7 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/servlet_context_listener.rb +7 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/servlet_filter.rb +7 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/solr.rb +27 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/solr_request_handler.rb +15 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/spring.rb +54 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/spring_controller.rb +6 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/spring_view.rb +6 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/struts_action.rb +20 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/struts_result.rb +20 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/version.rb +5 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/view.rb +70 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/web_frontend.rb +18 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/web_service.rb +14 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/web_transaction.rb +133 -0
- data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser.rb +64 -0
- 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
|