Module: NewRelic::Agent::MethodTracer::ClassMethods
- Defined in:
- lib/new_relic/agent/method_tracer.rb
Instance Method Summary collapse
-
#add_method_tracer(method_name, metric_name_code = nil, options = {}) ⇒ Object
Add a method tracer to the specified method.
-
#remove_method_tracer(method_name, metric_name_code) ⇒ Object
For tests only because tracers must be removed in reverse-order from when they were added, or else other tracers that were added to the same method may get removed as well.
Instance Method Details
#add_method_tracer(method_name, metric_name_code = nil, options = {}) ⇒ Object
Add a method tracer to the specified method.
Common Options
-
:push_scope => false
specifies this method tracer should not keep track of the caller; it will not show up in controller breakdown pie charts. -
:metric => false
specifies that no metric will be recorded. Instead the call will show up in transaction traces as well as traces shown in Developer Mode.
Uncommon Options
-
:scoped_metric_only => true
indicates that the unscoped metric should not be recorded. Normally two metrics are potentially created on every invocation: the aggregate method where statistics for all calls of that metric are stored, and the “scoped metric” which records the statistics for invocations in a particular scope–generally a controller action. This option indicates that only the second type should be recorded. The effect is similar to:metric => false
but in addition you will also see the invocation in breakdown pie charts. -
:deduct_call_time_from_parent => false
indicates that the method invocation time should never be deducted from the time reported as ‘exclusive’ in the caller. You would want to use this if you are tracing a recursive method or a method that might be called inside another traced method. -
:code_header
and:code_footer
specify ruby code that is inserted into the tracer before and after the call. -
:force = true
will ensure the metric is captured even if called inside an untraced execution call. (See NewRelic::Agent#disable_all_tracing)
Overriding the metric name
metric_name_code
is a string that is eval’d to get the name of the metric associated with the call, so if you want to use interpolaion evaluated at call time, then single quote the value like this:
add_method_tracer :foo, 'Custom/#{self.class.name}/foo'
This would name the metric according to the class of the runtime intance, as opposed to the class where foo
is defined.
If not provided, the metric name will be Custom/ClassName/method_name
.
Examples
Instrument foo
only for custom views–will not show up in transaction traces or caller breakdown graphs:
add_method_tracer :foo, :push_scope => false
Instrument foo
just for transaction traces only:
add_method_tracer :foo, :metric => false
Instrument foo
so it shows up in transaction traces and caller breakdown graphs for actions:
add_method_tracer :foo
which is equivalent to:
add_method_tracer :foo, 'Custom/#{self.class.name}/foo', :push_scope => true, :metric => true
Instrument the class method foo
with the metric name ‘Custom/People/fetch’:
class << self
add_method_tracer :foo, 'Custom/People/fetch'
end
232 233 234 235 236 237 238 239 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 |
# File 'lib/new_relic/agent/method_tracer.rb', line 232 def add_method_tracer(method_name, metric_name_code=nil, = {}) # for backward compatibility: if !.is_a?(Hash) = {:push_scope => } end # in case they omit the metric name code if metric_name_code.is_a?(Hash) .merge(metric_name_code) end if (unrecognized = .keys - [:force, :metric, :push_scope, :deduct_call_time_from_parent, :code_header, :code_footer, :scoped_metric_only]).any? fail "Unrecognized options in add_method_tracer_call: #{unrecognized.join(', ')}" end # options[:push_scope] true if we are noting the scope of this for # stats collection as well as the transaction tracing [:push_scope] = true if [:push_scope].nil? # options[:metric] true if you are tracking stats for a metric, otherwise # it's just for transaction tracing. [:metric] = true if [:metric].nil? [:force] = false if [:force].nil? [:deduct_call_time_from_parent] = false if [:deduct_call_time_from_parent].nil? && ![:metric] [:deduct_call_time_from_parent] = true if [:deduct_call_time_from_parent].nil? [:code_header] ||= "" [:code_footer] ||= "" [:scoped_metric_only] ||= false klass = (self === Module) ? "self" : "self.class" # Default to the class where the method is defined. metric_name_code = "Custom/#{self.name}/#{method_name.to_s}" unless metric_name_code unless method_defined?(method_name) || private_method_defined?(method_name) NewRelic::Control.instance.log.warn("Did not trace #{self.name}##{method_name} because that method does not exist") return end traced_method_name = _traced_method_name(method_name, metric_name_code) if method_defined? traced_method_name NewRelic::Control.instance.log.warn("Attempt to trace a method twice with the same metric: Method = #{method_name}, Metric Name = #{metric_name_code}") return end fail "Can't add a tracer where push_scope is false and metric is false" if [:push_scope] == false && ![:metric] header = "" if ![:force] header << "return #{_untraced_method_name(method_name, metric_name_code)}(*args, &block) unless NewRelic::Agent.is_execution_traced?\n" end header << [:code_header] if [:code_header] if [:push_scope] == false code = <<-CODE def #{_traced_method_name(method_name, metric_name_code)}(*args, &block) #{header} t0 = Time.now stats = NewRelic::Agent.instance.stats_engine.get_stats_no_scope "#{metric_name_code}" begin #{"NewRelic::Agent.instance.push_trace_execution_flag(true)\n" if [:force]} #{_untraced_method_name(method_name, metric_name_code)}(*args, &block)\n ensure #{"NewRelic::Agent.instance.pop_trace_execution_flag\n" if [:force] } duration = (Time.now - t0).to_f stats.trace_call(duration) #{[:]} end end CODE else code = <<-CODE def #{_traced_method_name(method_name, metric_name_code)}(*args, &block) #{[:code_header]} result = #{klass}.trace_execution_scoped("#{metric_name_code}", :metric => #{[:metric]}, :forced => #{[:force]}, :deduct_call_time_from_parent => #{[:deduct_call_time_from_parent]}, :scoped_metric_only => #{[:scoped_metric_only]}) do #{_untraced_method_name(method_name, metric_name_code)}(*args, &block) end #{[:]} result end CODE end class_eval code, __FILE__, __LINE__ alias_method _untraced_method_name(method_name, metric_name_code), method_name alias_method method_name, _traced_method_name(method_name, metric_name_code) NewRelic::Control.instance.log.debug("Traced method: class = #{self.name}, method = #{method_name}, "+ "metric = '#{metric_name_code}'") end |
#remove_method_tracer(method_name, metric_name_code) ⇒ Object
For tests only because tracers must be removed in reverse-order from when they were added, or else other tracers that were added to the same method may get removed as well.
324 325 326 327 328 329 330 331 332 333 |
# File 'lib/new_relic/agent/method_tracer.rb', line 324 def remove_method_tracer(method_name, metric_name_code) # :nodoc: return unless NewRelic::Control.instance.agent_enabled? if method_defined? "#{_traced_method_name(method_name, metric_name_code)}" alias_method method_name, "#{_untraced_method_name(method_name, metric_name_code)}" undef_method "#{_traced_method_name(method_name, metric_name_code)}" else raise "No tracer for '#{metric_name_code}' on method '#{method_name}'" end end |