Module: NewRelic::Agent::Instrumentation::ControllerInstrumentation
- Defined in:
- lib/new_relic/agent/instrumentation/controller_instrumentation.rb
Overview
NewRelic instrumentation for controllers
This instrumentation is applied to the action controller by default if the agent is actively collecting statistics. It will collect statistics for the given action.
In cases where you don’t want to instrument the top level action, but instead have other methods which are dispatched to by your action, and you want to treat these as distinct actions, then what you need to do is use #perform_action_with_newrelic_trace
Defined Under Namespace
Modules: ClassMethods, ClassMethodsShim, Shim
Constant Summary collapse
- @@newrelic_java_classes_missing =
false
Class Method Summary collapse
-
.included(clazz) ⇒ Object
:nodoc:.
Instance Method Summary collapse
-
#newrelic_metric_path(action_name_override = nil) ⇒ Object
Must be implemented in the controller class: Determine the path that is used in the metric name for the called controller action.
-
#perform_action_with_newrelic_profile(metric_name, path, args) ⇒ Object
Experimental.
-
#perform_action_with_newrelic_trace(*args, &block) ⇒ Object
Yield to the given block with NewRelic tracing.
Class Method Details
.included(clazz) ⇒ Object
:nodoc:
27 28 29 |
# File 'lib/new_relic/agent/instrumentation/controller_instrumentation.rb', line 27 def self.included(clazz) # :nodoc: clazz.extend(ClassMethods) end |
Instance Method Details
#newrelic_metric_path(action_name_override = nil) ⇒ Object
Must be implemented in the controller class: Determine the path that is used in the metric name for the called controller action. Of the form controller_path/action_name
166 167 168 |
# File 'lib/new_relic/agent/instrumentation/controller_instrumentation.rb', line 166 def newrelic_metric_path(action_name_override = nil) # :nodoc: raise "Not implemented!" end |
#perform_action_with_newrelic_profile(metric_name, path, args) ⇒ Object
Experimental
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 |
# File 'lib/new_relic/agent/instrumentation/controller_instrumentation.rb', line 328 def perform_action_with_newrelic_profile(metric_name, path, args) agent = NewRelic::Agent.instance stats_engine = agent.stats_engine NewRelic::Agent.trace_execution_scoped [metric_name, "Controller"] do stats_engine.transaction_name = metric_name NewRelic::Agent.disable_all_tracing do available_params = self.respond_to?(:params) ? params : {} # Not sure if we need to get the params and request... filtered_params = (respond_to? :filter_parameters) ? filter_parameters(available_params) : available_params available_request = (respond_to? :request) ? request : nil agent.transaction_sampler.notice_transaction(path, available_request, filtered_params) # turn on profiling profile = RubyProf.profile do if block_given? yield else perform_action_without_newrelic_trace(*args) end end agent.transaction_sampler.notice_profile profile end end end |
#perform_action_with_newrelic_trace(*args, &block) ⇒ Object
Yield to the given block with NewRelic tracing. Used by default instrumentation on controller actions in Rails and Merb. But it can also be used in custom instrumentation of controller methods and background tasks.
Here’s a more verbose version of the example shown in ClassMethods#add_transaction_tracer
using this method instead of #add_transaction_tracer.
Below is a controller with an invoke_operation
action which dispatches to more specific operation methods based on a parameter (very dangerous, btw!). With this instrumentation, the invoke_operation
action is ignored but the operation methods show up in RPM as if they were first class controller actions
MyController < ActionController::Base
include NewRelic::Agent::Instrumentation::ControllerInstrumentation
# dispatch the given op to the method given by the service parameter.
def invoke_operation
op = params['operation']
perform_action_with_newrelic_trace(:name => op) do
send op, params['message']
end
end
# Ignore the invoker to avoid double counting
newrelic_ignore :only => 'invoke_operation'
end
By passing a block in combination with specific arguments, you can invoke this directly to capture high level information in several contexts:
-
Pass
:category => :controller
and:name => actionname
to treat the block as if it were a controller action, invoked inside a real action.:name
is the name of the method, and is used in the metric name.
When invoked directly, pass in a block to measure with some combination of options:
-
:category => :controller
indicates that this is a controller action and will appear with all the other actions. This is the default. -
:category => :task
indicates that this is a background task and will show up in RPM with other background tasks instead of in the controllers list -
:category => :rack
if you are instrumenting a rack middleware call. The:name
is optional, useful if you have more than one potential transaction in the #call. -
:category => :uri
indicates that this is a web transaction whose name is a normalized URI, where ‘normalized’ means the URI does not have any elements with data in them such as in many REST URIs. -
:params => {...}
to provide information about the context of the call, used in transaction trace display, for example::params => { :account => @account.name, :file => file.name }
-
:name => action_name
is used to specify the action name used as part of the metric name -
:force => true
indicates you should capture all metrics even if the #newrelic_ignore directive was specified -
:class_name => aClass.name
is used to override the name of the class when used inside the metric name. Default is the current class. -
:path => metric_path
is deprecated in the public API. It allows you to set the entire metric after the category part. Overrides all the other options.
If a single argument is passed in, it is treated as a metric path. This form is deprecated.
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 |
# File 'lib/new_relic/agent/instrumentation/controller_instrumentation.rb', line 240 def perform_action_with_newrelic_trace(*args, &block) # Skip instrumentation based on the value of 'do_not_trace' and if # we aren't calling directly with a block. if !block_given? && _is_filtered?('do_not_trace') # Tell the dispatcher instrumentation that we ignored this action and it shouldn't # be counted for the overall HTTP operations measurement. Thread.current[:newrelic_ignore_controller] = true # Also ignore all instrumentation in the call sequence NewRelic::Agent.disable_all_tracing do return perform_action_without_newrelic_trace(*args) end end agent = NewRelic::Agent.instance stats_engine = agent.stats_engine # reset this in case we came through a code path where the top level controller is ignored Thread.current[:newrelic_ignore_controller] = nil apdex_start = (Thread.current[:started_on] || Thread.current[:newrelic_dispatcher_start] || Time.now).to_f force = false # If a block was passed in, then the arguments represent options for the instrumentation, # not app method arguments. if block_given? && args.any? force = args.last.is_a?(Hash) && args.last[:force] category, path, available_params = _convert_args_to_path(args) else category = 'Controller' path = newrelic_metric_path available_params = self.respond_to?(:params) ? self.params : {} end metric_name = category + '/' + path return perform_action_with_newrelic_profile(metric_name, path, args, &block) if NewRelic::Control.instance.profiling? filtered_params = (respond_to? :filter_parameters) ? filter_parameters(available_params) : available_params agent.ensure_worker_thread_started NewRelic::Agent.trace_execution_scoped [metric_name, "Controller"], :force => force do # Last one (innermost) to set the transaction name on the call stack wins. stats_engine.transaction_name = metric_name available_request = (respond_to? :request) ? request : nil agent.transaction_sampler.notice_transaction(path, available_request, filtered_params) jruby_cpu_start = _jruby_cpu_time process_cpu_start = _process_cpu failed = false begin # run the action if block_given? yield else perform_action_without_newrelic_trace(*args) end rescue Exception => e NewRelic::Agent.instance.error_collector.notice_error(e, nil, metric_name, filtered_params) failed = true raise e ensure if NewRelic::Agent.is_execution_traced? cpu_burn = nil if process_cpu_start cpu_burn = _process_cpu - process_cpu_start elsif jruby_cpu_start cpu_burn = _jruby_cpu_time - jruby_cpu_start stats_engine.get_stats_no_scope(NewRelic::Metrics::USER_TIME).record_data_point(cpu_burn) end agent.transaction_sampler.notice_transaction_cpu_time(cpu_burn) if cpu_burn # do the apdex bucketing # unless _is_filtered?('ignore_apdex') ending = Time.now.to_f # this uses the start of the dispatcher or the mongrel # thread: causes apdex to show too little capacity apdex_overall(apdex_start, ending, failed) # this uses the start time of the controller action: # does not include capacity problems since those aren't # per controller apdex_controller(apdex_start, ending, failed, path) end end end end end |