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,80 @@
|
|
|
1
|
+
require 'new_relic/agent/instrumentation'
|
|
2
|
+
module NewRelic
|
|
3
|
+
module Agent
|
|
4
|
+
module Instrumentation
|
|
5
|
+
class MetricFrame
|
|
6
|
+
module Pop
|
|
7
|
+
|
|
8
|
+
def clear_thread_metric_frame!
|
|
9
|
+
Thread.current[:newrelic_metric_frame] = nil
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def set_new_scope!(metric)
|
|
13
|
+
agent.stats_engine.scope_name = metric
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def log_underflow
|
|
17
|
+
NewRelic::Agent.logger.error "Underflow in metric frames: #{caller.join("\n ")}"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def notice_scope_empty
|
|
21
|
+
transaction_sampler.notice_scope_empty
|
|
22
|
+
sql_sampler.notice_scope_empty
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def record_transaction_cpu
|
|
26
|
+
burn = cpu_burn
|
|
27
|
+
transaction_sampler.notice_transaction_cpu_time(burn) if burn
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def normal_cpu_burn
|
|
31
|
+
return unless @process_cpu_start
|
|
32
|
+
process_cpu - @process_cpu_start
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def jruby_cpu_burn
|
|
36
|
+
return unless @jruby_cpu_start
|
|
37
|
+
burn = (jruby_cpu_time - @jruby_cpu_start)
|
|
38
|
+
record_jruby_cpu_burn(burn)
|
|
39
|
+
burn
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# we need to do this here because the normal cpu sampler
|
|
43
|
+
# process doesn't work on JRuby. See the cpu_sampler.rb file
|
|
44
|
+
# to understand where cpu is recorded for non-jruby processes
|
|
45
|
+
def record_jruby_cpu_burn(burn)
|
|
46
|
+
NewRelic::Agent.get_stats_no_scope(NewRelic::Metrics::USER_TIME).record_data_point(burn)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def cpu_burn
|
|
50
|
+
normal_cpu_burn || jruby_cpu_burn
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def end_transaction!
|
|
54
|
+
agent.stats_engine.end_transaction
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def notify_transaction_sampler(web_transaction)
|
|
58
|
+
record_transaction_cpu
|
|
59
|
+
notice_scope_empty
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def traced?
|
|
63
|
+
NewRelic::Agent.is_execution_traced?
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def handle_empty_path_stack(metric)
|
|
67
|
+
raise 'path stack not empty' unless @path_stack.empty?
|
|
68
|
+
notify_transaction_sampler(metric.is_web_transaction?) if traced?
|
|
69
|
+
end_transaction!
|
|
70
|
+
clear_thread_metric_frame!
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def current_stack_metric
|
|
74
|
+
metric_name
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
require 'new_relic/agent/instrumentation/metric_frame/pop'
|
|
2
|
+
|
|
3
|
+
# A struct holding the information required to measure a controller
|
|
4
|
+
# action. This is put on the thread local. Handles the issue of
|
|
5
|
+
# re-entrancy, or nested action calls.
|
|
6
|
+
#
|
|
7
|
+
# This class is not part of the public API. Avoid making calls on it directly.
|
|
8
|
+
#
|
|
9
|
+
module NewRelic
|
|
10
|
+
module Agent
|
|
11
|
+
module Instrumentation
|
|
12
|
+
class MetricFrame
|
|
13
|
+
# helper module refactored out of the `pop` method
|
|
14
|
+
include Pop
|
|
15
|
+
|
|
16
|
+
attr_accessor :start # A Time instance for the start time, never nil
|
|
17
|
+
attr_accessor :apdex_start # A Time instance used for calculating the apdex score, which
|
|
18
|
+
# might end up being @start, or it might be further upstream if
|
|
19
|
+
# we can find a request header for the queue entry time
|
|
20
|
+
attr_accessor :exception,
|
|
21
|
+
:filtered_params, :force_flag,
|
|
22
|
+
:jruby_cpu_start, :process_cpu_start, :database_metric_name
|
|
23
|
+
|
|
24
|
+
# Give the current metric frame a request context. Use this to
|
|
25
|
+
# get the URI and referer. The request is interpreted loosely
|
|
26
|
+
# as a Rack::Request or an ActionController::AbstractRequest.
|
|
27
|
+
attr_accessor :request
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@@check_server_connection = false
|
|
31
|
+
def self.check_server_connection=(value)
|
|
32
|
+
@@check_server_connection = value
|
|
33
|
+
end
|
|
34
|
+
# Return the currently active metric frame, or nil. Call with +true+
|
|
35
|
+
# to create a new metric frame if one is not already on the thread.
|
|
36
|
+
def self.current(create_if_empty=nil)
|
|
37
|
+
f = Thread.current[:newrelic_metric_frame]
|
|
38
|
+
return f if f || !create_if_empty
|
|
39
|
+
|
|
40
|
+
# Reconnect to the server if necessary. This is only done
|
|
41
|
+
# for old versions of passenger that don't implement an explicit after_fork
|
|
42
|
+
# event.
|
|
43
|
+
agent.after_fork(:keep_retrying => false) if @@check_server_connection
|
|
44
|
+
|
|
45
|
+
Thread.current[:newrelic_metric_frame] = new
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# This is the name of the model currently assigned to database
|
|
49
|
+
# measurements, overriding the default.
|
|
50
|
+
def self.database_metric_name
|
|
51
|
+
current && current.database_metric_name
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def self.referer
|
|
55
|
+
current && current.referer
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def self.agent
|
|
59
|
+
NewRelic::Agent.instance
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
@@java_classes_loaded = false
|
|
63
|
+
|
|
64
|
+
if defined? JRuby
|
|
65
|
+
begin
|
|
66
|
+
require 'java'
|
|
67
|
+
include_class 'java.lang.management.ManagementFactory'
|
|
68
|
+
include_class 'com.sun.management.OperatingSystemMXBean'
|
|
69
|
+
@@java_classes_loaded = true
|
|
70
|
+
rescue Exception => e
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
attr_reader :depth
|
|
75
|
+
|
|
76
|
+
def initialize
|
|
77
|
+
Thread.current[:newrelic_start_time] = @start = Time.now
|
|
78
|
+
@path_stack = [] # stack of [controller, path] elements
|
|
79
|
+
@jruby_cpu_start = jruby_cpu_time
|
|
80
|
+
@process_cpu_start = process_cpu
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def agent
|
|
84
|
+
NewRelic::Agent.instance
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def transaction_sampler
|
|
88
|
+
agent.transaction_sampler
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def sql_sampler
|
|
92
|
+
agent.sql_sampler
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
private :agent
|
|
96
|
+
private :transaction_sampler
|
|
97
|
+
private :sql_sampler
|
|
98
|
+
|
|
99
|
+
# Indicate that we are entering a measured controller action or task.
|
|
100
|
+
# Make sure you unwind every push with a pop call.
|
|
101
|
+
def push(m)
|
|
102
|
+
transaction_sampler.notice_first_scope_push(start)
|
|
103
|
+
sql_sampler.notice_first_scope_push(start)
|
|
104
|
+
@path_stack.push NewRelic::MetricParser::MetricParser.for_metric_named(m)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Indicate that you don't want to keep the currently saved transaction
|
|
108
|
+
# information
|
|
109
|
+
def self.abort_transaction!
|
|
110
|
+
current.abort_transaction! if current
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# For the current web transaction, return the path of the URI minus the host part and query string, or nil.
|
|
114
|
+
def uri
|
|
115
|
+
@uri ||= self.class.uri_from_request(@request) unless @request.nil?
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# For the current web transaction, return the full referer, minus the host string, or nil.
|
|
119
|
+
def referer
|
|
120
|
+
@referer ||= self.class.referer_from_request(@request)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Call this to ensure that the current transaction is not saved
|
|
124
|
+
def abort_transaction!
|
|
125
|
+
transaction_sampler.ignore_transaction
|
|
126
|
+
end
|
|
127
|
+
# This needs to be called after entering the call to trace the
|
|
128
|
+
# controller action, otherwise the controller action blames
|
|
129
|
+
# itself. It gets reset in the normal #pop call.
|
|
130
|
+
def start_transaction
|
|
131
|
+
agent.stats_engine.start_transaction metric_name
|
|
132
|
+
# Only push the transaction context info once, on entry:
|
|
133
|
+
if @path_stack.size == 1
|
|
134
|
+
transaction_sampler.notice_transaction(metric_name, uri, filtered_params)
|
|
135
|
+
sql_sampler.notice_transaction(metric_name, uri, filtered_params)
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def current_metric
|
|
140
|
+
@path_stack.last
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Return the path, the part of the metric after the category
|
|
144
|
+
def path
|
|
145
|
+
@path_stack.last.last
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Unwind one stack level. It knows if it's back at the outermost caller and
|
|
149
|
+
# does the appropriate wrapup of the context.
|
|
150
|
+
def pop
|
|
151
|
+
metric = @path_stack.pop
|
|
152
|
+
log_underflow if metric.nil?
|
|
153
|
+
if @path_stack.empty?
|
|
154
|
+
handle_empty_path_stack(metric)
|
|
155
|
+
else
|
|
156
|
+
set_new_scope!(current_stack_metric)
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# If we have an active metric frame, notice the error and increment the error metric.
|
|
161
|
+
# Options:
|
|
162
|
+
# * <tt>:request</tt> => Request object to get the uri and referer
|
|
163
|
+
# * <tt>:uri</tt> => The request path, minus any request params or query string.
|
|
164
|
+
# * <tt>:referer</tt> => The URI of the referer
|
|
165
|
+
# * <tt>:metric</tt> => The metric name associated with the transaction
|
|
166
|
+
# * <tt>:request_params</tt> => Request parameters, already filtered if necessary
|
|
167
|
+
# * <tt>:custom_params</tt> => Custom parameters
|
|
168
|
+
# Anything left over is treated as custom params
|
|
169
|
+
|
|
170
|
+
def self.notice_error(e, options={})
|
|
171
|
+
request = options.delete(:request)
|
|
172
|
+
if request
|
|
173
|
+
options[:referer] = referer_from_request(request)
|
|
174
|
+
options[:uri] = uri_from_request(request)
|
|
175
|
+
end
|
|
176
|
+
if current
|
|
177
|
+
current.notice_error(e, options)
|
|
178
|
+
else
|
|
179
|
+
agent.error_collector.notice_error(e, options)
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Do not call this. Invoke the class method instead.
|
|
184
|
+
def notice_error(e, options={}) # :nodoc:
|
|
185
|
+
params = custom_parameters
|
|
186
|
+
options[:referer] = referer if referer
|
|
187
|
+
options[:request_params] = filtered_params if filtered_params
|
|
188
|
+
options[:uri] = uri if uri
|
|
189
|
+
options[:metric] = metric_name
|
|
190
|
+
options.merge!(custom_parameters)
|
|
191
|
+
if exception != e
|
|
192
|
+
result = agent.error_collector.notice_error(e, options)
|
|
193
|
+
self.exception = result if result
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# Add context parameters to the metric frame. This information will be passed in to errors
|
|
198
|
+
# and transaction traces. Keys and Values should be strings, numbers or date/times.
|
|
199
|
+
def self.add_custom_parameters(p)
|
|
200
|
+
current.add_custom_parameters(p) if current
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def self.custom_parameters
|
|
204
|
+
(current && current.custom_parameters) ? current.custom_parameters : {}
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def record_apdex()
|
|
208
|
+
return unless recording_web_transaction? && NewRelic::Agent.is_execution_traced?
|
|
209
|
+
t = Time.now
|
|
210
|
+
self.class.record_apdex(current_metric, t - start, t - apdex_start, !exception.nil?)
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def metric_name
|
|
214
|
+
return nil if @path_stack.empty?
|
|
215
|
+
current_metric.name
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# Return the array of metrics to record for the current metric frame.
|
|
219
|
+
def recorded_metrics
|
|
220
|
+
metrics = [ metric_name ]
|
|
221
|
+
metrics += current_metric.summary_metrics if @path_stack.size == 1
|
|
222
|
+
metrics
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# Yield to a block that is run with a database metric name context. This means
|
|
226
|
+
# the Database instrumentation will use this for the metric name if it does not
|
|
227
|
+
# otherwise know about a model. This is re-entrant.
|
|
228
|
+
#
|
|
229
|
+
# * <tt>model</tt> is the DB model class
|
|
230
|
+
# * <tt>method</tt> is the name of the finder method or other method to identify the operation with.
|
|
231
|
+
#
|
|
232
|
+
def with_database_metric_name(model, method)
|
|
233
|
+
previous = @database_metric_name
|
|
234
|
+
model_name = case model
|
|
235
|
+
when Class
|
|
236
|
+
model.name
|
|
237
|
+
when String
|
|
238
|
+
model
|
|
239
|
+
else
|
|
240
|
+
model.to_s
|
|
241
|
+
end
|
|
242
|
+
@database_metric_name = "ActiveRecord/#{model_name}/#{method}"
|
|
243
|
+
yield
|
|
244
|
+
ensure
|
|
245
|
+
@database_metric_name=previous
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
def custom_parameters
|
|
249
|
+
@custom_parameters ||= {}
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def add_custom_parameters(p)
|
|
253
|
+
custom_parameters.merge!(p)
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def self.recording_web_transaction?
|
|
257
|
+
c = Thread.current[:newrelic_metric_frame]
|
|
258
|
+
if c
|
|
259
|
+
c.recording_web_transaction?
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
def recording_web_transaction?
|
|
264
|
+
current_metric && current_metric.is_web_transaction?
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
def is_web_transaction?(metric)
|
|
268
|
+
0 == metric.index("Controller")
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
# Make a safe attempt to get the referer from a request object, generally successful when
|
|
272
|
+
# it's a Rack request.
|
|
273
|
+
def self.referer_from_request(request)
|
|
274
|
+
if request && request.respond_to?(:referer)
|
|
275
|
+
request.referer.to_s.split('?').first
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
# Make a safe attempt to get the URI, without the host and query string.
|
|
280
|
+
def self.uri_from_request(request)
|
|
281
|
+
approximate_uri = case
|
|
282
|
+
when request.respond_to?(:fullpath) then request.fullpath
|
|
283
|
+
when request.respond_to?(:path) then request.path
|
|
284
|
+
when request.respond_to?(:request_uri) then request.request_uri
|
|
285
|
+
when request.respond_to?(:uri) then request.uri
|
|
286
|
+
when request.respond_to?(:url) then request.url
|
|
287
|
+
end
|
|
288
|
+
return approximate_uri[%r{^(https?://.*?)?(/[^?]*)}, 2] || '/' if approximate_uri # '
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
def self.record_apdex(current_metric, action_duration, total_duration, is_error)
|
|
292
|
+
summary_stat = agent.stats_engine.get_custom_stats("Apdex", NewRelic::ApdexStats)
|
|
293
|
+
controller_stat = agent.stats_engine.get_custom_stats(current_metric.apdex_metric_path, NewRelic::ApdexStats)
|
|
294
|
+
update_apdex(summary_stat, total_duration, is_error)
|
|
295
|
+
update_apdex(controller_stat, action_duration, is_error)
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
# Record an apdex value for the given stat. when `failed`
|
|
299
|
+
# the apdex should be recorded as a failure regardless of duration.
|
|
300
|
+
def self.update_apdex(stat, duration, failed)
|
|
301
|
+
duration = duration.to_f
|
|
302
|
+
apdex_t = NewRelic::Control.instance.apdex_t
|
|
303
|
+
case
|
|
304
|
+
when failed
|
|
305
|
+
stat.record_apdex_f
|
|
306
|
+
when duration <= apdex_t
|
|
307
|
+
stat.record_apdex_s
|
|
308
|
+
when duration <= 4 * apdex_t
|
|
309
|
+
stat.record_apdex_t
|
|
310
|
+
else
|
|
311
|
+
stat.record_apdex_f
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
private
|
|
316
|
+
|
|
317
|
+
def process_cpu
|
|
318
|
+
return nil if defined? JRuby
|
|
319
|
+
p = Process.times
|
|
320
|
+
p.stime + p.utime
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
def jruby_cpu_time # :nodoc:
|
|
324
|
+
return nil unless @@java_classes_loaded
|
|
325
|
+
threadMBean = ManagementFactory.getThreadMXBean()
|
|
326
|
+
java_utime = threadMBean.getCurrentThreadUserTime() # ns
|
|
327
|
+
-1 == java_utime ? 0.0 : java_utime/1e9
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
DependencyDetection.defer do
|
|
2
|
+
@name = :net
|
|
3
|
+
|
|
4
|
+
depends_on do
|
|
5
|
+
defined?(Net) && defined?(Net::HTTP)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
executes do
|
|
9
|
+
NewRelic::Agent.logger.debug 'Installing Net instrumentation'
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
executes do
|
|
13
|
+
Net::HTTP.class_eval do
|
|
14
|
+
def request_with_newrelic_trace(*args, &block)
|
|
15
|
+
metrics = ["External/#{@address}/Net::HTTP/#{args[0].method}", "External/#{@address}/all", "External/all"]
|
|
16
|
+
if NewRelic::Agent::Instrumentation::MetricFrame.recording_web_transaction?
|
|
17
|
+
metrics << "External/allWeb"
|
|
18
|
+
else
|
|
19
|
+
metrics << "External/allOther"
|
|
20
|
+
end
|
|
21
|
+
self.class.trace_execution_scoped metrics do
|
|
22
|
+
request_without_newrelic_trace(*args, &block)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
alias request_without_newrelic_trace request
|
|
26
|
+
alias request request_with_newrelic_trace
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
DependencyDetection.defer do
|
|
2
|
+
@name = :passenger
|
|
3
|
+
|
|
4
|
+
depends_on do
|
|
5
|
+
defined?(PhusionPassenger)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
executes do
|
|
9
|
+
NewRelic::Agent.logger.debug "Installing Passenger event hooks."
|
|
10
|
+
|
|
11
|
+
PhusionPassenger.on_event(:stopping_worker_process) do
|
|
12
|
+
NewRelic::Agent.logger.debug "Passenger stopping this process, shutdown the agent."
|
|
13
|
+
NewRelic::Agent.instance.shutdown
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
PhusionPassenger.on_event(:starting_worker_process) do |forked|
|
|
17
|
+
# We want to reset the stats from the stats engine in case any carried
|
|
18
|
+
# over into the spawned process. Don't clear them in case any were
|
|
19
|
+
# cached. We do this even in conservative spawning.
|
|
20
|
+
NewRelic::Agent.after_fork(:force_reconnect => true)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
DependencyDetection.defer do
|
|
26
|
+
depends_on do
|
|
27
|
+
defined?(::Passenger) && defined?(::Passenger::AbstractServer) || defined?(::IN_PHUSION_PASSENGER)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
executes do
|
|
31
|
+
# We're on an older version of passenger
|
|
32
|
+
NewRelic::Agent.logger.warn "An older version of Phusion Passenger has been detected. We recommend using at least release 2.1.1."
|
|
33
|
+
|
|
34
|
+
NewRelic::Agent::Instrumentation::MetricFrame.check_server_connection = true
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
module NewRelic
|
|
2
|
+
module Agent
|
|
3
|
+
module Instrumentation
|
|
4
|
+
module QueueTime
|
|
5
|
+
unless defined?(MAIN_HEADER)
|
|
6
|
+
MAIN_HEADER = 'HTTP_X_REQUEST_START'
|
|
7
|
+
MIDDLEWARE_HEADER = 'HTTP_X_MIDDLEWARE_START'
|
|
8
|
+
QUEUE_HEADER = 'HTTP_X_QUEUE_START'
|
|
9
|
+
ALT_QUEUE_HEADER = 'HTTP_X_QUEUE_TIME'
|
|
10
|
+
HEROKU_QUEUE_HEADER = 'HTTP_X_HEROKU_QUEUE_WAIT_TIME'
|
|
11
|
+
APP_HEADER = 'HTTP_X_APPLICATION_START'
|
|
12
|
+
|
|
13
|
+
HEADER_REGEX = /([^\s\/,(t=)]+)? ?t=([0-9]+)/
|
|
14
|
+
SERVER_METRIC = 'WebFrontend/WebServer/'
|
|
15
|
+
MIDDLEWARE_METRIC = 'Middleware/'
|
|
16
|
+
# no individual queue metric - more than one queue?!
|
|
17
|
+
ALL_SERVER_METRIC = 'WebFrontend/WebServer/all'
|
|
18
|
+
ALL_MIDDLEWARE_METRIC = 'Middleware/all'
|
|
19
|
+
ALL_QUEUE_METRIC = 'WebFrontend/QueueTime'
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def parse_frontend_headers(headers)
|
|
23
|
+
# these methods add internal state, so we dup so other parts
|
|
24
|
+
# of the app don't have to worry about it.
|
|
25
|
+
# May have performance implications with very large env hashes
|
|
26
|
+
env = headers.dup
|
|
27
|
+
add_end_time_header(Time.now, env)
|
|
28
|
+
middleware_start = parse_middleware_time_from(env)
|
|
29
|
+
queue_start = parse_queue_time_from(env)
|
|
30
|
+
server_start = parse_server_time_from(env)
|
|
31
|
+
# returned for the controller instrumentation
|
|
32
|
+
[middleware_start, queue_start, server_start].min
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
# main method to extract server time info from env hash,
|
|
38
|
+
# records individual server metrics and one roll-up for all servers
|
|
39
|
+
def parse_server_time_from(env)
|
|
40
|
+
end_time = parse_end_time(env)
|
|
41
|
+
matches = get_matches_from_header(MAIN_HEADER, env)
|
|
42
|
+
|
|
43
|
+
record_individual_server_stats(end_time, matches)
|
|
44
|
+
record_rollup_server_stat(end_time, matches)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def parse_middleware_time_from(env)
|
|
48
|
+
end_time = parse_end_time(env)
|
|
49
|
+
matches = get_matches_from_header(MIDDLEWARE_HEADER, env)
|
|
50
|
+
|
|
51
|
+
record_individual_middleware_stats(end_time, matches)
|
|
52
|
+
oldest_time = record_rollup_middleware_stat(end_time, matches)
|
|
53
|
+
# notice this bit: we reset the end time to the earliest
|
|
54
|
+
# middleware tag so that other frontend metrics don't
|
|
55
|
+
# include this time.
|
|
56
|
+
add_end_time_header(oldest_time, env)
|
|
57
|
+
oldest_time
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def parse_queue_time_from(env)
|
|
61
|
+
oldest_time = nil
|
|
62
|
+
end_time = parse_end_time(env)
|
|
63
|
+
alternate_length = check_for_alternate_queue_length(env)
|
|
64
|
+
if alternate_length
|
|
65
|
+
# skip all that fancy-dan stuff
|
|
66
|
+
NewRelic::Agent.get_stats(ALL_QUEUE_METRIC).trace_call(alternate_length)
|
|
67
|
+
oldest_time = (end_time - alternate_length) # should be a time
|
|
68
|
+
else
|
|
69
|
+
matches = get_matches_from_header(QUEUE_HEADER, env)
|
|
70
|
+
oldest_time = record_rollup_queue_stat(end_time, matches)
|
|
71
|
+
end
|
|
72
|
+
# notice this bit: we reset the end time to the earliest
|
|
73
|
+
# queue tag or the start time minus the queue time so that
|
|
74
|
+
# other frontend metrics don't include this time.
|
|
75
|
+
add_end_time_header(oldest_time, env)
|
|
76
|
+
oldest_time
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def check_for_alternate_queue_length(env)
|
|
80
|
+
heroku_length = check_for_heroku_queue_length(env)
|
|
81
|
+
return heroku_length if heroku_length
|
|
82
|
+
header = env[ALT_QUEUE_HEADER]
|
|
83
|
+
return nil unless header
|
|
84
|
+
(header.gsub('t=', '').to_i / 1_000_000.0)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def check_for_heroku_queue_length(env)
|
|
88
|
+
header = env[HEROKU_QUEUE_HEADER]
|
|
89
|
+
return nil unless header
|
|
90
|
+
(header.gsub(/[^0-9]/, '').to_i / 1_000.0)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def get_matches_from_header(header, env)
|
|
94
|
+
return [] if env.nil?
|
|
95
|
+
get_matches(env[header]).map do |name, time|
|
|
96
|
+
convert_to_name_time_pair(name, time)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def get_matches(string)
|
|
101
|
+
string.to_s.scan(HEADER_REGEX)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def convert_to_name_time_pair(name, time)
|
|
105
|
+
[name, convert_from_microseconds(time.to_i)]
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def record_individual_stat_of_type(type, end_time, matches)
|
|
109
|
+
matches = matches.sort_by {|name, time| time }
|
|
110
|
+
matches.reverse!
|
|
111
|
+
matches.inject(end_time) {|end_time, pair|
|
|
112
|
+
name, time = pair
|
|
113
|
+
self.send(type, name, time, end_time) if name
|
|
114
|
+
time
|
|
115
|
+
}
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# goes through the list of servers and records each one in
|
|
119
|
+
# reverse order, subtracting the time for each successive
|
|
120
|
+
# server from the earlier ones in the list.
|
|
121
|
+
# an example because it's complicated:
|
|
122
|
+
# start data:
|
|
123
|
+
# [['a', Time.at(1000)], ['b', Time.at(1001)]], start time: Time.at(1002)
|
|
124
|
+
# initial run: Time.at(1002), ['b', Time.at(1001)]
|
|
125
|
+
# next: Time.at(1001), ['a', Time.at(1000)]
|
|
126
|
+
# see tests for more
|
|
127
|
+
def record_individual_server_stats(end_time, matches) # (Time, [[String, Time]]) -> nil
|
|
128
|
+
record_individual_stat_of_type(:record_server_time_for, end_time, matches)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def record_individual_middleware_stats(end_time, matches)
|
|
132
|
+
record_individual_stat_of_type(:record_middleware_time_for, end_time, matches)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# records the total time for all servers in a rollup metric
|
|
136
|
+
def record_rollup_server_stat(end_time, matches) # (Time, [String, Time]) -> nil
|
|
137
|
+
record_rollup_stat_of_type(ALL_SERVER_METRIC, end_time, matches)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def record_rollup_middleware_stat(end_time, matches)
|
|
141
|
+
record_rollup_stat_of_type(ALL_MIDDLEWARE_METRIC, end_time, matches)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def record_rollup_queue_stat(end_time, matches)
|
|
145
|
+
record_rollup_stat_of_type(ALL_QUEUE_METRIC, end_time, matches)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def record_rollup_stat_of_type(metric, end_time, matches)
|
|
149
|
+
oldest_time = find_oldest_time(matches) || end_time
|
|
150
|
+
record_time_stat(metric, oldest_time, end_time)
|
|
151
|
+
oldest_time
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# searches for the first server to touch a request
|
|
155
|
+
def find_oldest_time(matches) # [[String, Time]] -> Time
|
|
156
|
+
matches.map do |name, time|
|
|
157
|
+
time
|
|
158
|
+
end.min
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# basically just assembles the metric name
|
|
162
|
+
def record_server_time_for(name, start_time, end_time) # (Maybe String, Time, Time) -> nil
|
|
163
|
+
record_time_stat(SERVER_METRIC + name, start_time, end_time) if name
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def record_middleware_time_for(name, start_time, end_time)
|
|
167
|
+
record_time_stat(MIDDLEWARE_METRIC + name, start_time, end_time)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Checks that the time is not negative, and does the actual
|
|
171
|
+
# data recording
|
|
172
|
+
def record_time_stat(name, start_time, end_time) # (String, Time, Time) -> nil
|
|
173
|
+
total_time = end_time - start_time
|
|
174
|
+
if total_time < 0
|
|
175
|
+
raise "should not provide an end time less than start time: #{end_time} is less than #{start_time}"
|
|
176
|
+
else
|
|
177
|
+
NewRelic::Agent.get_stats(name).trace_call(total_time)
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def add_end_time_header(end_time, env) # (Time, Env) -> nil
|
|
182
|
+
return unless end_time
|
|
183
|
+
env[APP_HEADER] = "t=#{convert_to_microseconds(end_time)}"
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def parse_end_time(env)
|
|
187
|
+
header = env[APP_HEADER]
|
|
188
|
+
return Time.now unless header
|
|
189
|
+
convert_from_microseconds(header.gsub('t=', '').to_i)
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# convert a time to the value provided by the header, for convenience
|
|
193
|
+
def convert_to_microseconds(time) # Time -> Int
|
|
194
|
+
raise TypeError.new('Cannot convert a non-time into microseconds') unless time.is_a?(Time) || time.is_a?(Numeric)
|
|
195
|
+
return time if time.is_a?(Numeric)
|
|
196
|
+
(time.to_f * 1_000_000).to_i
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# convert a time from the header value (time in microseconds)
|
|
200
|
+
# into a ruby time object
|
|
201
|
+
def convert_from_microseconds(int) # Int -> Time
|
|
202
|
+
raise TypeError.new('Cannot convert a non-number into a time') unless int.is_a?(Time) || int.is_a?(Numeric)
|
|
203
|
+
return int if int.is_a?(Time)
|
|
204
|
+
Time.at((int / 1_000_000.0))
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|