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