module NewRelic::Agent::MethodTracer::ClassMethods::AddMethodTracer
contains methods refactored out of the add_method_tracer method
Constants
- ALLOWED_KEYS
- DEFAULT_SETTINGS
- DEPRECATED_KEYS
Public Instance Methods
Returns a code snippet to be eval'd that skips tracing when the agent is not tracing execution. turns instrumentation into effectively one method call overhead when the agent is disabled
# File lib/new_relic/agent/method_tracer.rb, line 230 def assemble_code_header(method_name, metric_name_code, options) header = "return #{_untraced_method_name(method_name, metric_name_code)}(*args, &block) unless NewRelic::Agent.tl_is_execution_traced?\n" header += options[:code_header].to_s header end
raises an error when the NewRelic::Agent::MethodTracer::ClassMethods#add_method_tracer method is called with improper keys. This aids in debugging new instrumentation by failing fast
# File lib/new_relic/agent/method_tracer.rb, line 159 def check_for_illegal_keys!(method_name, options) unrecognized_keys = options.keys - ALLOWED_KEYS deprecated_keys = options.keys & DEPRECATED_KEYS if unrecognized_keys.any? raise "Unrecognized options when adding method tracer to #{method_name}: " + unrecognized_keys.join(', ') end if deprecated_keys.any? NewRelic::Agent.logger.warn("Deprecated options when adding method tracer to #{method_name}: "+ deprecated_keys.join(', ')) end end
validity checking - add_method_tracer must receive either push scope or metric, or else it would record no data. Raises an error if this is the case
# File lib/new_relic/agent/method_tracer.rb, line 177 def check_for_push_scope_and_metric(options) unless options[:push_scope] || options[:metric] raise "Can't add a tracer where push_scope is false and metric is false" end end
Decides which code snippet we should be eval'ing in this context, based on the options.
# File lib/new_relic/agent/method_tracer.rb, line 269 def code_to_eval(method_name, metric_name_code, options) options = validate_options(method_name, options) if options[:push_scope] method_with_push_scope(method_name, metric_name_code, options) else method_without_push_scope(method_name, metric_name_code, options) end end
Default to the class where the method is defined.
Example:
Foo.default_metric_name_code('bar') #=> "Custom/#{Foo.name}/bar"
# File lib/new_relic/agent/method_tracer.rb, line 203 def default_metric_name_code(method_name) "Custom/#{self.name}/#{method_name.to_s}" end
returns an eval-able string that contains the tracing code for a fully traced metric including scoping
# File lib/new_relic/agent/method_tracer.rb, line 255 def method_with_push_scope(method_name, metric_name_code, options) "def #{_traced_method_name(method_name, metric_name_code)}(*args, &block) #{options[:code_header]} result = ::NewRelic::Agent::MethodTracerHelpers.trace_execution_scoped(\"#{metric_name_code}\", :metric => #{options[:metric]}) do #{_untraced_method_name(method_name, metric_name_code)}(*args, &block) end #{options[:code_footer]} result end" end
returns an eval-able string that contains the traced method code used if the agent is not creating a scope for use in scoped metrics.
# File lib/new_relic/agent/method_tracer.rb, line 239 def method_without_push_scope(method_name, metric_name_code, options) "def #{_traced_method_name(method_name, metric_name_code)}(*args, &block) #{assemble_code_header(method_name, metric_name_code, options)} t0 = Time.now begin #{_untraced_method_name(method_name, metric_name_code)}(*args, &block)\n ensure duration = (Time.now - t0).to_f NewRelic::Agent.record_metric(\"#{metric_name_code}\", duration) #{options[:code_footer]} end end" end
Checks to see if the method we are attempting to trace actually exists or not. add_method_tracer can't do anything if the method doesn't exist.
# File lib/new_relic/agent/method_tracer.rb, line 210 def newrelic_method_exists?(method_name) exists = method_defined?(method_name) || private_method_defined?(method_name) ::NewRelic::Agent.logger.error("Did not trace #{self.name}##{method_name} because that method does not exist") unless exists exists end
Checks to see if we have already traced a method with a given metric by checking to see if the traced method exists. Warns the user if methods are being double-traced to help with debugging custom instrumentation.
# File lib/new_relic/agent/method_tracer.rb, line 220 def traced_method_exists?(method_name, metric_name_code) exists = method_defined?(_traced_method_name(method_name, metric_name_code)) ::NewRelic::Agent.logger.error("Attempt to trace a method twice with the same metric: Method = #{method_name}, Metric Name = #{metric_name_code}") if exists exists end
Checks the provided options to make sure that they make sense. Raises an error if the options are incorrect to assist with debugging, so that errors occur at class construction time rather than instrumentation run time
# File lib/new_relic/agent/method_tracer.rb, line 189 def validate_options(method_name, options) unless options.is_a?(Hash) raise TypeError.new("Error adding method tracer to #{method_name}: provided options must be a Hash") end check_for_illegal_keys!(method_name, options) options = DEFAULT_SETTINGS.merge(options) check_for_push_scope_and_metric(options) options end