module NewRelic::Agent::MethodTracer::ClassMethods
Defines methods used at the class level, for adding instrumentation @api public
Public Instance Methods
Source
# File lib/new_relic/agent/method_tracer.rb, line 246 def add_method_tracer(method_name, metric_name = nil, options = {}) ::NewRelic::Agent.add_or_defer_method_tracer(self, method_name, metric_name, options) end
Add a method tracer to the specified method.
By default, this will cause invocations of the traced method to be recorded in transaction traces, and in a metric named after the class and method. It will also make the method show up in transaction-level breakdown charts and tables.
Overriding the metric name¶ ↑
metric_name
is a String or Proc. If a Proc is given, it is bound to the object that called the traced method. For example:
add_method_tracer :foo, -> { "Custom/#{self.class.name}/foo" }
This would name the metric according to the class of the runtime instance, as opposed to the class where foo
is defined.
If not provided, the metric name will be Custom/ClassName/method_name
.
@param method_name [Symbol] the name of the method to trace @param metric_name [String,Proc,Array] the metric name to record calls to
the traced method under. This may be either a String, or a Proc to be evaluated at call-time in order to determine the metric name dynamically. This method also accepts an array of Strings/Procs, in which case the first metric given will be scoped, while the remaining metrics will be recorded as though passed with :push_scope => false. If an Array of metric names is given with :push_scope => false, all metrics will be unscoped.
@param [Hash] options additional options controlling how the method is
traced.
@option options [Boolean] :push_scope (true) If false, the traced method will
not appear in transaction traces or breakdown charts, and it will only be visible in custom dashboards.
@option options [Boolean] :metric (true) If false, the traced method will
only appear in transaction traces, but no metrics will be recorded for it.
@option options [Proc] :code_header (”) Ruby code to be inserted and run
before the tracer begins timing.
@option options [Proc] :code_footer (”) Ruby code to be inserted and run
after the tracer stops timing.
@example
add_method_tracer :foo # With a custom metric name add_method_tracer :foo, "Custom/MyClass/foo" add_method_tracer :bar, -> { "Custom/#{self.class.name}/bar" } # Instrument foo only for custom dashboards (not in transaction # traces or breakdown charts) add_method_tracer :foo, 'Custom/foo', :push_scope => false # Instrument foo in transaction traces only add_method_tracer :foo, 'Custom/foo', :metric => false
@api public
Private Instance Methods
Source
# File lib/new_relic/agent/method_tracer.rb, line 266 def _nr_add_method_tracer_now(method_name, metric_name, options) NewRelic::Agent.record_api_supportability_metric(:add_method_tracer) return unless newrelic_method_exists?(method_name) remove_method_tracer(method_name) if method_traced?(method_name) options = _nr_validate_method_tracer_options(method_name, options) visibility = NewRelic::Helper.instance_method_visibility(self, method_name) scoped_metric, unscoped_metrics = _nr_scoped_unscoped_metrics(metric_name, method_name, push_scope: options[:push_scope]) _nr_define_traced_method(method_name, scoped_metric: scoped_metric, unscoped_metrics: unscoped_metrics, code_header: options[:code_header], code_footer: options[:code_footer], record_metrics: options[:metric], visibility: visibility, code_information: options[:code_information]) prepend(_nr_traced_method_module) ::NewRelic::Agent.logger.debug("Traced method: class = #{_nr_derived_class_name}," + "method = #{method_name}, " + "metric = '#{metric_name}'") end
Source
# File lib/new_relic/agent/method_tracer.rb, line 303 def _nr_define_traced_method(method_name, scoped_metric: nil, unscoped_metrics: [], code_header: nil, code_footer: nil, record_metrics: true, visibility: :public, code_information: {}) _nr_traced_method_module.module_eval do define_method(method_name) do |*args, &block| return super(*args, &block) unless NewRelic::Agent.tl_is_execution_traced? scoped_metric_eval, unscoped_metrics_eval = nil, [] scoped_metric_eval = case scoped_metric when Proc instance_exec(*args, &scoped_metric) when String scoped_metric end unscoped_metrics_eval = unscoped_metrics.map do |metric| metric.kind_of?(Proc) ? instance_exec(*args, &metric) : metric.to_s end instance_exec(&code_header) if code_header.kind_of?(Proc) # NOTE: Calling ::NewRelic::Agent::MethodTracer.trace_execution_scoped and # .trace_execution_unscoped below relies on the fact that MethodTracer is included # in Module on agent startup. If/when this changes, these methods should be # explicitly namespaced and extended in MethodTracer. # If tracing multiple metrics on this method, nest one unscoped trace inside the scoped trace. begin if scoped_metric_eval ::NewRelic::Agent::MethodTracer.trace_execution_scoped(scoped_metric_eval, metric: record_metrics, internal: true, code_information: code_information) do if unscoped_metrics_eval.empty? super(*args, &block) else ::NewRelic::Agent::MethodTracer.trace_execution_unscoped(unscoped_metrics_eval, internal: true) do super(*args, &block) end end end elsif !unscoped_metrics_eval.empty? ::NewRelic::Agent::MethodTracer.trace_execution_unscoped(unscoped_metrics_eval, internal: true) do super(*args, &block) end end ensure instance_exec(&code_footer) if code_footer.kind_of?(Proc) end end send(visibility, method_name) ruby2_keywords(method_name) if respond_to?(:ruby2_keywords, true) end end
Source
# File lib/new_relic/agent/method_tracer.rb, line 293 def _nr_scoped_unscoped_metrics(metric_name, method_name, push_scope: true) if metric_name.is_a?(Array) && push_scope [metric_name.shift, metric_name] elsif push_scope [metric_name || _nr_default_metric_name(method_name), []] else [nil, Array(metric_name)] end end
See add_method_tracer
; if multiple metric names are given, the first is treated as scoped, the rest unscoped. If options is false, all given metrics are unscoped.