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,58 @@
|
|
|
1
|
+
require 'new_relic/agent/instrumentation/controller_instrumentation'
|
|
2
|
+
|
|
3
|
+
DependencyDetection.defer do
|
|
4
|
+
depends_on do
|
|
5
|
+
defined?(::Sinatra) && defined?(::Sinatra::Base)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
executes do
|
|
9
|
+
NewRelic::Agent.logger.debug 'Installing Sinatra instrumentation'
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
executes do
|
|
13
|
+
::Sinatra::Base.class_eval do
|
|
14
|
+
include NewRelic::Agent::Instrumentation::Sinatra
|
|
15
|
+
alias route_eval_without_newrelic route_eval
|
|
16
|
+
alias route_eval route_eval_with_newrelic
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
module NewRelic
|
|
23
|
+
module Agent
|
|
24
|
+
module Instrumentation
|
|
25
|
+
# NewRelic instrumentation for Sinatra applications. Sinatra actions will
|
|
26
|
+
# appear in the UI similar to controller actions, and have breakdown charts
|
|
27
|
+
# and transaction traces.
|
|
28
|
+
#
|
|
29
|
+
# The actions in the UI will correspond to the pattern expression used
|
|
30
|
+
# to match them. HTTP operations are not distinguished. Multiple matches
|
|
31
|
+
# will all be tracked as separate actions.
|
|
32
|
+
module Sinatra
|
|
33
|
+
|
|
34
|
+
include NewRelic::Agent::Instrumentation::ControllerInstrumentation
|
|
35
|
+
|
|
36
|
+
def route_eval_with_newrelic(&block_arg)
|
|
37
|
+
path = unescape(@request.path_info)
|
|
38
|
+
name = path
|
|
39
|
+
# Go through each route and look for a match
|
|
40
|
+
if routes = self.class.routes[@request.request_method]
|
|
41
|
+
routes.detect do |pattern, keys, conditions, block|
|
|
42
|
+
if block_arg.equal? block
|
|
43
|
+
name = pattern.source
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
# strip off leading ^ and / chars and trailing $ and /
|
|
48
|
+
name.gsub!(%r{^[/^]*(.*?)[/\$\?]*$}, '\1')
|
|
49
|
+
name = 'root' if name.empty?
|
|
50
|
+
name = @request.request_method + ' ' + name if @request && @request.respond_to?(:request_method)
|
|
51
|
+
perform_action_with_newrelic_trace(:category => :sinatra, :name => name, :params => @request.params) do
|
|
52
|
+
route_eval_without_newrelic(&block_arg)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
DependencyDetection.defer do
|
|
2
|
+
@name = :sunspot
|
|
3
|
+
|
|
4
|
+
depends_on do
|
|
5
|
+
defined?(::Sunspot)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
executes do
|
|
9
|
+
NewRelic::Agent.logger.debug 'Installing Rails Sunspot instrumentation'
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
executes do
|
|
13
|
+
::Sunspot.module_eval do
|
|
14
|
+
class << self
|
|
15
|
+
%w(index index!).each do |method|
|
|
16
|
+
add_method_tracer method, 'SolrClient/Sunspot/index'
|
|
17
|
+
end
|
|
18
|
+
add_method_tracer :commit, 'SolrClient/Sunspot/commit'
|
|
19
|
+
|
|
20
|
+
%w[search more_like_this].each do |method|
|
|
21
|
+
add_method_tracer method, 'SolrClient/Sunspot/query'
|
|
22
|
+
end
|
|
23
|
+
%w[remove remove! remove_by_id remove_by_id! remove_all remove_all!].each do |method|
|
|
24
|
+
add_method_tracer method, 'SolrClient/Sunspot/delete'
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
DependencyDetection.defer do
|
|
2
|
+
@name = :unicorn
|
|
3
|
+
|
|
4
|
+
depends_on do
|
|
5
|
+
defined?(::Unicorn) && defined?(::Unicorn::HttpServer)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
executes do
|
|
9
|
+
NewRelic::Agent.logger.debug 'Installing Unicorn instrumentation'
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
executes do
|
|
13
|
+
Unicorn::HttpServer.class_eval do
|
|
14
|
+
old_worker_loop = instance_method(:worker_loop)
|
|
15
|
+
define_method(:worker_loop) do | worker |
|
|
16
|
+
NewRelic::Agent.after_fork(:force_reconnect => true)
|
|
17
|
+
old_worker_loop.bind(self).call(worker)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
require 'new_relic/control'
|
|
2
|
+
module NewRelic
|
|
3
|
+
module Agent
|
|
4
|
+
# This module contains class methods added to support installing custom
|
|
5
|
+
# metric tracers and executing for individual metrics.
|
|
6
|
+
#
|
|
7
|
+
# == Examples
|
|
8
|
+
#
|
|
9
|
+
# When the agent initializes, it extends Module with these methods.
|
|
10
|
+
# However if you want to use the API in code that might get loaded
|
|
11
|
+
# before the agent is initialized you will need to require
|
|
12
|
+
# this file:
|
|
13
|
+
#
|
|
14
|
+
# require 'new_relic/agent/method_tracer'
|
|
15
|
+
# class A
|
|
16
|
+
# include NewRelic::Agent::MethodTracer
|
|
17
|
+
# def process
|
|
18
|
+
# ...
|
|
19
|
+
# end
|
|
20
|
+
# add_method_tracer :process
|
|
21
|
+
# end
|
|
22
|
+
#
|
|
23
|
+
# To instrument a class method:
|
|
24
|
+
#
|
|
25
|
+
# require 'new_relic/agent/method_tracer'
|
|
26
|
+
# class An
|
|
27
|
+
# def self.process
|
|
28
|
+
# ...
|
|
29
|
+
# end
|
|
30
|
+
# class << self
|
|
31
|
+
# include NewRelic::Agent::MethodTracer
|
|
32
|
+
# add_method_tracer :process
|
|
33
|
+
# end
|
|
34
|
+
# end
|
|
35
|
+
|
|
36
|
+
module MethodTracer
|
|
37
|
+
|
|
38
|
+
def self.included clazz #:nodoc:
|
|
39
|
+
clazz.extend ClassMethods
|
|
40
|
+
clazz.send :include, InstanceMethods
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def self.extended clazz #:nodoc:
|
|
44
|
+
clazz.extend ClassMethods
|
|
45
|
+
clazz.extend InstanceMethods
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Defines modules used at instrumentation runtime, to do the
|
|
49
|
+
# actual tracing of time spent
|
|
50
|
+
module InstanceMethods
|
|
51
|
+
# Deprecated: original method preserved for API backward compatibility.
|
|
52
|
+
# Use either #trace_execution_scoped or #trace_execution_unscoped
|
|
53
|
+
def trace_method_execution(metric_names, push_scope, produce_metric, deduct_call_time_from_parent, &block) #:nodoc:
|
|
54
|
+
if push_scope
|
|
55
|
+
trace_execution_scoped(metric_names, :metric => produce_metric,
|
|
56
|
+
:deduct_call_time_from_parent => deduct_call_time_from_parent, &block)
|
|
57
|
+
else
|
|
58
|
+
trace_execution_unscoped(metric_names, &block)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Trace a given block with stats assigned to the given metric_name. It does not
|
|
63
|
+
# provide scoped measurements, meaning whatever is being traced will not 'blame the
|
|
64
|
+
# Controller'--that is to say appear in the breakdown chart.
|
|
65
|
+
# This is code is inlined in #add_method_tracer.
|
|
66
|
+
# * <tt>metric_names</tt> is a single name or an array of names of metrics
|
|
67
|
+
# * <tt>:force => true</tt> will force the metric to be captured even when
|
|
68
|
+
# tracing is disabled with NewRelic::Agent#disable_all_tracing
|
|
69
|
+
#
|
|
70
|
+
def trace_execution_unscoped(metric_names, options={})
|
|
71
|
+
return yield unless NewRelic::Agent.is_execution_traced?
|
|
72
|
+
t0 = Time.now
|
|
73
|
+
stats = Array(metric_names).map do | metric_name |
|
|
74
|
+
NewRelic::Agent.instance.stats_engine.get_stats_no_scope metric_name
|
|
75
|
+
end
|
|
76
|
+
begin
|
|
77
|
+
NewRelic::Agent.instance.push_trace_execution_flag(true) if options[:force]
|
|
78
|
+
yield
|
|
79
|
+
ensure
|
|
80
|
+
NewRelic::Agent.instance.pop_trace_execution_flag if options[:force]
|
|
81
|
+
duration = (Time.now - t0).to_f # for some reason this is 3 usec faster than Time - Time
|
|
82
|
+
stats.each { |stat| stat.trace_call(duration) }
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Deprecated. Use #trace_execution_scoped, a version with an options hash.
|
|
87
|
+
def trace_method_execution_with_scope(metric_names, produce_metric, deduct_call_time_from_parent, scoped_metric_only=false, &block) #:nodoc:
|
|
88
|
+
trace_execution_scoped(metric_names,
|
|
89
|
+
:metric => produce_metric,
|
|
90
|
+
:deduct_call_time_from_parent => deduct_call_time_from_parent,
|
|
91
|
+
:scoped_metric_only => scoped_metric_only, &block)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
alias trace_method_execution_no_scope trace_execution_unscoped #:nodoc:
|
|
95
|
+
|
|
96
|
+
# Refactored out of the previous trace_execution_scoped
|
|
97
|
+
# method, most methods in this module relate to code used in
|
|
98
|
+
# the #trace_execution_scoped method in this module
|
|
99
|
+
module TraceExecutionScoped
|
|
100
|
+
# Shorthand to return the NewRelic::Agent.instance
|
|
101
|
+
def agent_instance
|
|
102
|
+
NewRelic::Agent.instance
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Shorthand to return the status of tracing
|
|
106
|
+
def traced?
|
|
107
|
+
NewRelic::Agent.is_execution_traced?
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Tracing is disabled if we are not in a traced context and
|
|
111
|
+
# no force option is supplied
|
|
112
|
+
def trace_disabled?(options)
|
|
113
|
+
!(traced? || options[:force])
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Shorthand to return the current statistics engine
|
|
117
|
+
def stat_engine
|
|
118
|
+
agent_instance.stats_engine
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# returns a scoped metric stat for the specified name
|
|
122
|
+
def get_stats_scoped(first_name, scoped_metric_only)
|
|
123
|
+
stat_engine.get_stats(first_name, true, scoped_metric_only)
|
|
124
|
+
end
|
|
125
|
+
# Shorthand method to get stats from the stat engine
|
|
126
|
+
def get_stats_unscoped(name)
|
|
127
|
+
stat_engine.get_stats_no_scope(name)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# the main statistic we should record in
|
|
131
|
+
# #trace_execution_scoped - a scoped metric provided by the
|
|
132
|
+
# first item in the metric array
|
|
133
|
+
def main_stat(metric, options)
|
|
134
|
+
get_stats_scoped(metric, options[:scoped_metric_only])
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# returns an array containing the first metric, and an array
|
|
138
|
+
# of other unscoped statistics we should also record along
|
|
139
|
+
# side it
|
|
140
|
+
def get_metric_stats(metrics, options)
|
|
141
|
+
metrics = Array(metrics)
|
|
142
|
+
first_name = metrics.shift
|
|
143
|
+
stats = metrics.map do | name |
|
|
144
|
+
get_stats_unscoped(name)
|
|
145
|
+
end
|
|
146
|
+
stats.unshift(main_stat(first_name, options)) if options[:metric]
|
|
147
|
+
[first_name, stats]
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Helper for setting a hash key if the hash key is nil,
|
|
151
|
+
# instead of the default ||= behavior which sets if it is
|
|
152
|
+
# false as well
|
|
153
|
+
def set_if_nil(hash, key)
|
|
154
|
+
hash[key] = true if hash[key].nil?
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# delegates to #agent_instance to push a trace execution
|
|
158
|
+
# flag, only if execution of this metric is forced.
|
|
159
|
+
#
|
|
160
|
+
# This causes everything scoped inside this metric to be
|
|
161
|
+
# recorded, even if the parent transaction is generally not.
|
|
162
|
+
def push_flag!(forced)
|
|
163
|
+
agent_instance.push_trace_execution_flag(true) if forced
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# delegates to #agent_instance to pop the trace execution
|
|
167
|
+
# flag, only if execution of this metric is
|
|
168
|
+
# forced. otherwise this is taken care of for us
|
|
169
|
+
# automatically.
|
|
170
|
+
#
|
|
171
|
+
# This ends the forced recording of metrics within the
|
|
172
|
+
# #trace_execution_scoped block
|
|
173
|
+
def pop_flag!(forced)
|
|
174
|
+
agent_instance.pop_trace_execution_flag if forced
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# helper for logging errors to the newrelic_agent.log
|
|
178
|
+
# properly. Logs the error at error level, and includes a
|
|
179
|
+
# backtrace if we're running at debug level
|
|
180
|
+
def log_errors(code_area, metric)
|
|
181
|
+
yield
|
|
182
|
+
rescue => e
|
|
183
|
+
NewRelic::Control.instance.log.error("Caught exception in #{code_area}. Metric name = #{metric}, exception = #{e}")
|
|
184
|
+
NewRelic::Control.instance.log.error(e.backtrace.join("\n"))
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# provides the header for our traced execution scoped
|
|
188
|
+
# method - gets the initial time, sets the tracing flag if
|
|
189
|
+
# needed, and pushes the scope onto the metric stack
|
|
190
|
+
# logs any errors that occur and returns the start time and
|
|
191
|
+
# the scope so that we can check for it later, to maintain
|
|
192
|
+
# sanity. If the scope stack becomes unbalanced, this
|
|
193
|
+
# transaction loses meaning.
|
|
194
|
+
def trace_execution_scoped_header(metric, options, t0=Time.now.to_f)
|
|
195
|
+
scope = log_errors("trace_execution_scoped header", metric) do
|
|
196
|
+
push_flag!(options[:force])
|
|
197
|
+
scope = stat_engine.push_scope(metric, t0, options[:deduct_call_time_from_parent])
|
|
198
|
+
end
|
|
199
|
+
# needed in case we have an error, above, to always return
|
|
200
|
+
# the start time.
|
|
201
|
+
[t0, scope]
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# Handles the end of the #trace_execution_scoped method -
|
|
205
|
+
# calculating the time taken, popping the tracing flag if
|
|
206
|
+
# needed, deducting time taken by children, and tracing the
|
|
207
|
+
# subsidiary unscoped metrics if any
|
|
208
|
+
#
|
|
209
|
+
# this method fails safely if the header does not manage to
|
|
210
|
+
# push the scope onto the stack - it simply does not trace
|
|
211
|
+
# any metrics.
|
|
212
|
+
def trace_execution_scoped_footer(t0, first_name, metric_stats, expected_scope, forced, t1=Time.now.to_f)
|
|
213
|
+
log_errors("trace_method_execution footer", first_name) do
|
|
214
|
+
duration = t1 - t0
|
|
215
|
+
|
|
216
|
+
pop_flag!(forced)
|
|
217
|
+
if expected_scope
|
|
218
|
+
scope = stat_engine.pop_scope(expected_scope, duration, t1)
|
|
219
|
+
exclusive = duration - scope.children_time
|
|
220
|
+
metric_stats.each { |stats| stats.trace_call(duration, exclusive) }
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# Trace a given block with stats and keep track of the caller.
|
|
226
|
+
# See NewRelic::Agent::MethodTracer::ClassMethods#add_method_tracer for a description of the arguments.
|
|
227
|
+
# +metric_names+ is either a single name or an array of metric names.
|
|
228
|
+
# If more than one metric is passed, the +produce_metric+ option only applies to the first. The
|
|
229
|
+
# others are always recorded. Only the first metric is pushed onto the scope stack.
|
|
230
|
+
#
|
|
231
|
+
# Generally you pass an array of metric names if you want to record the metric under additional
|
|
232
|
+
# categories, but generally this *should never ever be done*. Most of the time you can aggregate
|
|
233
|
+
# on the server.
|
|
234
|
+
|
|
235
|
+
def trace_execution_scoped(metric_names, options={})
|
|
236
|
+
return yield if trace_disabled?(options)
|
|
237
|
+
set_if_nil(options, :metric)
|
|
238
|
+
set_if_nil(options, :deduct_call_time_from_parent)
|
|
239
|
+
first_name, metric_stats = get_metric_stats(metric_names, options)
|
|
240
|
+
start_time, expected_scope = trace_execution_scoped_header(first_name, options)
|
|
241
|
+
begin
|
|
242
|
+
yield
|
|
243
|
+
ensure
|
|
244
|
+
trace_execution_scoped_footer(start_time, first_name, metric_stats, expected_scope, options[:force])
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
end
|
|
249
|
+
include TraceExecutionScoped
|
|
250
|
+
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
# Defines methods used at the class level, for adding instrumentation
|
|
254
|
+
module ClassMethods
|
|
255
|
+
# contains methods refactored out of the #add_method_tracer method
|
|
256
|
+
module AddMethodTracer
|
|
257
|
+
ALLOWED_KEYS = [:force, :metric, :push_scope, :deduct_call_time_from_parent, :code_header, :code_footer, :scoped_metric_only].freeze
|
|
258
|
+
|
|
259
|
+
# used to verify that the keys passed to
|
|
260
|
+
# NewRelic::Agent::MethodTracer::ClassMethods#add_method_tracer
|
|
261
|
+
# are valid. Returns a list of keys that were unexpected
|
|
262
|
+
def unrecognized_keys(expected, given)
|
|
263
|
+
given.keys - expected
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
# used to verify that the keys passed to
|
|
267
|
+
# NewRelic::Agent::MethodTracer::ClassMethods#add_method_tracer
|
|
268
|
+
# are valid. checks the expected list against the list
|
|
269
|
+
# actually provided
|
|
270
|
+
def any_unrecognized_keys?(expected, given)
|
|
271
|
+
unrecognized_keys(expected, given).any?
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
# raises an error when the
|
|
275
|
+
# NewRelic::Agent::MethodTracer::ClassMethods#add_method_tracer
|
|
276
|
+
# method is called with improper keys. This aids in
|
|
277
|
+
# debugging new instrumentation by failing fast
|
|
278
|
+
def check_for_illegal_keys!(options)
|
|
279
|
+
if any_unrecognized_keys?(ALLOWED_KEYS, options)
|
|
280
|
+
raise "Unrecognized options in add_method_tracer_call: #{unrecognized_keys(ALLOWED_KEYS, options).join(', ')}"
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
# Sets the options for deducting call time from
|
|
285
|
+
# parents. This defaults to true if we are recording a metric, but
|
|
286
|
+
# can be overridden by the user if desired.
|
|
287
|
+
#
|
|
288
|
+
# has the effect of not allowing overlapping times, and
|
|
289
|
+
# should generally be true
|
|
290
|
+
def set_deduct_call_time_based_on_metric(options)
|
|
291
|
+
{:deduct_call_time_from_parent => !!options[:metric]}.merge(options)
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
# validity checking - add_method_tracer must receive either
|
|
295
|
+
# push scope or metric, or else it would record no
|
|
296
|
+
# data. Raises an error if this is the case
|
|
297
|
+
def check_for_push_scope_and_metric(options)
|
|
298
|
+
unless options[:push_scope] || options[:metric]
|
|
299
|
+
raise "Can't add a tracer where push_scope is false and metric is false"
|
|
300
|
+
end
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
DEFAULT_SETTINGS = {:push_scope => true, :metric => true, :force => false, :code_header => "", :code_footer => "", :scoped_metric_only => false}.freeze
|
|
304
|
+
|
|
305
|
+
# Checks the provided options to make sure that they make
|
|
306
|
+
# sense. Raises an error if the options are incorrect to
|
|
307
|
+
# assist with debugging, so that errors occur at class
|
|
308
|
+
# construction time rather than instrumentation run time
|
|
309
|
+
def validate_options(options)
|
|
310
|
+
raise TypeError.new("provided options must be a Hash") unless options.is_a?(Hash)
|
|
311
|
+
check_for_illegal_keys!(options)
|
|
312
|
+
options = set_deduct_call_time_based_on_metric(DEFAULT_SETTINGS.merge(options))
|
|
313
|
+
check_for_push_scope_and_metric(options)
|
|
314
|
+
options
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
# Default to the class where the method is defined.
|
|
318
|
+
#
|
|
319
|
+
# Example:
|
|
320
|
+
# Foo.default_metric_name_code('bar') #=> "Custom/#{Foo.name}/bar"
|
|
321
|
+
def default_metric_name_code(method_name)
|
|
322
|
+
"Custom/#{self.name}/#{method_name.to_s}"
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
# Checks to see if the method we are attempting to trace
|
|
326
|
+
# actually exists or not. #add_method_tracer can't do
|
|
327
|
+
# anything if the method doesn't exist.
|
|
328
|
+
def newrelic_method_exists?(method_name)
|
|
329
|
+
exists = method_defined?(method_name) || private_method_defined?(method_name)
|
|
330
|
+
NewRelic::Control.instance.log.warn("Did not trace #{self.name}##{method_name} because that method does not exist") unless exists
|
|
331
|
+
exists
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
# Checks to see if we have already traced a method with a
|
|
335
|
+
# given metric by checking to see if the traced method
|
|
336
|
+
# exists. Warns the user if methods are being double-traced
|
|
337
|
+
# to help with debugging custom instrumentation.
|
|
338
|
+
def traced_method_exists?(method_name, metric_name_code)
|
|
339
|
+
exists = method_defined?(_traced_method_name(method_name, metric_name_code))
|
|
340
|
+
NewRelic::Control.instance.log.warn("Attempt to trace a method twice with the same metric: Method = #{method_name}, Metric Name = #{metric_name_code}") if exists
|
|
341
|
+
exists
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
# Returns a code snippet to be eval'd that skips tracing
|
|
345
|
+
# when the agent is not tracing execution. turns
|
|
346
|
+
# instrumentation into effectively one method call overhead
|
|
347
|
+
# when the agent is disabled
|
|
348
|
+
def assemble_code_header(method_name, metric_name_code, options)
|
|
349
|
+
unless options[:force]
|
|
350
|
+
"return #{_untraced_method_name(method_name, metric_name_code)}(*args, &block) unless NewRelic::Agent.is_execution_traced?\n"
|
|
351
|
+
end.to_s + options[:code_header].to_s
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
# returns an eval-able string that contains the traced
|
|
355
|
+
# method code used if the agent is not creating a scope for
|
|
356
|
+
# use in scoped metrics.
|
|
357
|
+
def method_without_push_scope(method_name, metric_name_code, options)
|
|
358
|
+
"def #{_traced_method_name(method_name, metric_name_code)}(*args, &block)
|
|
359
|
+
#{assemble_code_header(method_name, metric_name_code, options)}
|
|
360
|
+
t0 = Time.now
|
|
361
|
+
stats = NewRelic::Agent.instance.stats_engine.get_stats_no_scope \"#{metric_name_code}\"
|
|
362
|
+
begin
|
|
363
|
+
#{"NewRelic::Agent.instance.push_trace_execution_flag(true)\n" if options[:force]}
|
|
364
|
+
#{_untraced_method_name(method_name, metric_name_code)}(*args, &block)\n
|
|
365
|
+
ensure
|
|
366
|
+
#{"NewRelic::Agent.instance.pop_trace_execution_flag\n" if options[:force] }
|
|
367
|
+
duration = (Time.now - t0).to_f
|
|
368
|
+
stats.trace_call(duration)
|
|
369
|
+
#{options[:code_footer]}
|
|
370
|
+
end
|
|
371
|
+
end"
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
# returns an eval-able string that contains the tracing code
|
|
375
|
+
# for a fully traced metric including scoping
|
|
376
|
+
def method_with_push_scope(method_name, metric_name_code, options)
|
|
377
|
+
klass = (self === Module) ? "self" : "self.class"
|
|
378
|
+
|
|
379
|
+
"def #{_traced_method_name(method_name, metric_name_code)}(*args, &block)
|
|
380
|
+
#{options[:code_header]}
|
|
381
|
+
result = #{klass}.trace_execution_scoped(\"#{metric_name_code}\",
|
|
382
|
+
:metric => #{options[:metric]},
|
|
383
|
+
:forced => #{options[:force]},
|
|
384
|
+
:deduct_call_time_from_parent => #{options[:deduct_call_time_from_parent]},
|
|
385
|
+
:scoped_metric_only => #{options[:scoped_metric_only]}) do
|
|
386
|
+
#{_untraced_method_name(method_name, metric_name_code)}(*args, &block)
|
|
387
|
+
end
|
|
388
|
+
#{options[:code_footer]}
|
|
389
|
+
result
|
|
390
|
+
end"
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
# Decides which code snippet we should be eval'ing in this
|
|
394
|
+
# context, based on the options.
|
|
395
|
+
def code_to_eval(method_name, metric_name_code, options)
|
|
396
|
+
options = validate_options(options)
|
|
397
|
+
if options[:push_scope]
|
|
398
|
+
method_with_push_scope(method_name, metric_name_code, options)
|
|
399
|
+
else
|
|
400
|
+
method_without_push_scope(method_name, metric_name_code, options)
|
|
401
|
+
end
|
|
402
|
+
end
|
|
403
|
+
end
|
|
404
|
+
include AddMethodTracer
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
# Add a method tracer to the specified method.
|
|
409
|
+
#
|
|
410
|
+
# === Common Options
|
|
411
|
+
#
|
|
412
|
+
# * <tt>:push_scope => false</tt> specifies this method tracer should not
|
|
413
|
+
# keep track of the caller; it will not show up in controller breakdown
|
|
414
|
+
# pie charts.
|
|
415
|
+
# * <tt>:metric => false</tt> specifies that no metric will be recorded.
|
|
416
|
+
# Instead the call will show up in transaction traces as well as traces
|
|
417
|
+
# shown in Developer Mode.
|
|
418
|
+
#
|
|
419
|
+
# === Uncommon Options
|
|
420
|
+
#
|
|
421
|
+
# * <tt>:scoped_metric_only => true</tt> indicates that the unscoped metric
|
|
422
|
+
# should not be recorded. Normally two metrics are potentially created
|
|
423
|
+
# on every invocation: the aggregate method where statistics for all calls
|
|
424
|
+
# of that metric are stored, and the "scoped metric" which records the
|
|
425
|
+
# statistics for invocations in a particular scope--generally a controller
|
|
426
|
+
# action. This option indicates that only the second type should be recorded.
|
|
427
|
+
# The effect is similar to <tt>:metric => false</tt> but in addition you
|
|
428
|
+
# will also see the invocation in breakdown pie charts.
|
|
429
|
+
# * <tt>:deduct_call_time_from_parent => false</tt> indicates that the method invocation
|
|
430
|
+
# time should never be deducted from the time reported as 'exclusive' in the
|
|
431
|
+
# caller. You would want to use this if you are tracing a recursive method
|
|
432
|
+
# or a method that might be called inside another traced method.
|
|
433
|
+
# * <tt>:code_header</tt> and <tt>:code_footer</tt> specify ruby code that
|
|
434
|
+
# is inserted into the tracer before and after the call.
|
|
435
|
+
# * <tt>:force = true</tt> will ensure the metric is captured even if called inside
|
|
436
|
+
# an untraced execution call. (See NewRelic::Agent#disable_all_tracing)
|
|
437
|
+
#
|
|
438
|
+
# === Overriding the metric name
|
|
439
|
+
#
|
|
440
|
+
# +metric_name_code+ is a string that is eval'd to get the
|
|
441
|
+
# name of the metric associated with the call, so if you want to
|
|
442
|
+
# use interpolaion evaluated at call time, then single quote
|
|
443
|
+
# the value like this:
|
|
444
|
+
#
|
|
445
|
+
# add_method_tracer :foo, 'Custom/#{self.class.name}/foo'
|
|
446
|
+
#
|
|
447
|
+
# This would name the metric according to the class of the runtime
|
|
448
|
+
# intance, as opposed to the class where +foo+ is defined.
|
|
449
|
+
#
|
|
450
|
+
# If not provided, the metric name will be <tt>Custom/ClassName/method_name</tt>.
|
|
451
|
+
#
|
|
452
|
+
# === Examples
|
|
453
|
+
#
|
|
454
|
+
# Instrument +foo+ only for custom views--will not show up in transaction traces or caller breakdown graphs:
|
|
455
|
+
#
|
|
456
|
+
# add_method_tracer :foo, :push_scope => false
|
|
457
|
+
#
|
|
458
|
+
# Instrument +foo+ just for transaction traces only:
|
|
459
|
+
#
|
|
460
|
+
# add_method_tracer :foo, :metric => false
|
|
461
|
+
#
|
|
462
|
+
# Instrument +foo+ so it shows up in transaction traces and caller breakdown graphs
|
|
463
|
+
# for actions:
|
|
464
|
+
#
|
|
465
|
+
# add_method_tracer :foo
|
|
466
|
+
#
|
|
467
|
+
# which is equivalent to:
|
|
468
|
+
#
|
|
469
|
+
# add_method_tracer :foo, 'Custom/#{self.class.name}/foo', :push_scope => true, :metric => true
|
|
470
|
+
#
|
|
471
|
+
# Instrument the class method +foo+ with the metric name 'Custom/People/fetch':
|
|
472
|
+
#
|
|
473
|
+
# class << self
|
|
474
|
+
# add_method_tracer :foo, 'Custom/People/fetch'
|
|
475
|
+
# end
|
|
476
|
+
#
|
|
477
|
+
def add_method_tracer(method_name, metric_name_code=nil, options = {})
|
|
478
|
+
return unless newrelic_method_exists?(method_name)
|
|
479
|
+
metric_name_code ||= default_metric_name_code(method_name)
|
|
480
|
+
return if traced_method_exists?(method_name, metric_name_code)
|
|
481
|
+
|
|
482
|
+
traced_method = code_to_eval(method_name, metric_name_code, options)
|
|
483
|
+
|
|
484
|
+
class_eval traced_method, __FILE__, __LINE__
|
|
485
|
+
alias_method _untraced_method_name(method_name, metric_name_code), method_name
|
|
486
|
+
alias_method method_name, _traced_method_name(method_name, metric_name_code)
|
|
487
|
+
NewRelic::Control.instance.log.debug("Traced method: class = #{self.name},"+
|
|
488
|
+
"method = #{method_name}, "+
|
|
489
|
+
"metric = '#{metric_name_code}'")
|
|
490
|
+
end
|
|
491
|
+
|
|
492
|
+
# For tests only because tracers must be removed in reverse-order
|
|
493
|
+
# from when they were added, or else other tracers that were added to the same method
|
|
494
|
+
# may get removed as well.
|
|
495
|
+
def remove_method_tracer(method_name, metric_name_code) # :nodoc:
|
|
496
|
+
return unless NewRelic::Control.instance.agent_enabled?
|
|
497
|
+
if method_defined? "#{_traced_method_name(method_name, metric_name_code)}"
|
|
498
|
+
alias_method method_name, "#{_untraced_method_name(method_name, metric_name_code)}"
|
|
499
|
+
undef_method "#{_traced_method_name(method_name, metric_name_code)}"
|
|
500
|
+
NewRelic::Control.instance.log.debug("removed method tracer #{method_name} #{metric_name_code}\n")
|
|
501
|
+
else
|
|
502
|
+
raise "No tracer for '#{metric_name_code}' on method '#{method_name}'"
|
|
503
|
+
end
|
|
504
|
+
end
|
|
505
|
+
private
|
|
506
|
+
|
|
507
|
+
# given a method and a metric, this method returns the
|
|
508
|
+
# untraced alias of the method name
|
|
509
|
+
def _untraced_method_name(method_name, metric_name)
|
|
510
|
+
"#{_sanitize_name(method_name)}_without_trace_#{_sanitize_name(metric_name)}"
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
# given a method and a metric, this method returns the traced
|
|
514
|
+
# alias of the method name
|
|
515
|
+
def _traced_method_name(method_name, metric_name)
|
|
516
|
+
"#{_sanitize_name(method_name)}_with_trace_#{_sanitize_name(metric_name)}"
|
|
517
|
+
end
|
|
518
|
+
|
|
519
|
+
# makes sure that method names do not contain characters that
|
|
520
|
+
# might break the interpreter, for example ! or ? characters
|
|
521
|
+
# that are not allowed in the middle of method names
|
|
522
|
+
def _sanitize_name(name)
|
|
523
|
+
name.to_s.tr_s('^a-zA-Z0-9', '_')
|
|
524
|
+
end
|
|
525
|
+
end
|
|
526
|
+
end
|
|
527
|
+
end
|
|
528
|
+
end
|