module Mmtrix::Agent::MethodTracer::ClassMethods::AddMethodTracer

contains methods refactored out of the add_method_tracer method

Constants

ALLOWED_KEYS
DEFAULT_SETTINGS
DEPRECATED_KEYS

Public Instance Methods

assemble_code_header(method_name, metric_name_code, options) click to toggle source

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/mmtrix/agent/method_tracer.rb, line 231
def assemble_code_header(method_name, metric_name_code, options)
  header = "return #{_untraced_method_name(method_name, metric_name_code)}(*args, &block) unless Mmtrix::Agent.tl_is_execution_traced?\n"
  header += options[:code_header].to_s
  header
end
check_for_illegal_keys!(method_name, options) click to toggle source

raises an error when the Mmtrix::Agent::MethodTracer::ClassMethods#add_method_tracer method is called with improper keys. This aids in debugging new instrumentation by failing fast

# File lib/mmtrix/agent/method_tracer.rb, line 160
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?
    Mmtrix::Agent.logger.warn("Deprecated options when adding method tracer to #{method_name}: "+
      deprecated_keys.join(', '))
  end
end
check_for_push_scope_and_metric(options) click to toggle source

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/mmtrix/agent/method_tracer.rb, line 178
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
code_to_eval(method_name, metric_name_code, options) click to toggle source

Decides which code snippet we should be eval’ing in this context, based on the options.

# File lib/mmtrix/agent/method_tracer.rb, line 270
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_metric_name_code(method_name) click to toggle source

Default to the class where the method is defined.

Example:

Foo.default_metric_name_code('bar') #=> "Custom/#{Foo.name}/bar"
# File lib/mmtrix/agent/method_tracer.rb, line 204
def default_metric_name_code(method_name)
  "Custom/#{self.name}/#{method_name.to_s}"
end
method_with_push_scope(method_name, metric_name_code, options) click to toggle source

returns an eval-able string that contains the tracing code for a fully traced metric including scoping

# File lib/mmtrix/agent/method_tracer.rb, line 256
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 = ::Mmtrix::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
method_without_push_scope(method_name, metric_name_code, options) click to toggle source

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/mmtrix/agent/method_tracer.rb, line 240
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
      Mmtrix::Agent.record_metric(\"#{metric_name_code}\", duration)
      #{options[:code_footer]}
    end
  end"
end
mmtrix_method_exists?(method_name) click to toggle source

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/mmtrix/agent/method_tracer.rb, line 211
def mmtrix_method_exists?(method_name)
  exists = method_defined?(method_name) || private_method_defined?(method_name)
  ::Mmtrix::Agent.logger.error("Did not trace #{self.name}##{method_name} because that method does not exist") unless exists
  exists
end
traced_method_exists?(method_name, metric_name_code) click to toggle source

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/mmtrix/agent/method_tracer.rb, line 221
def traced_method_exists?(method_name, metric_name_code)
  exists = method_defined?(_traced_method_name(method_name, metric_name_code))
  ::Mmtrix::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
validate_options(method_name, options) click to toggle source

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/mmtrix/agent/method_tracer.rb, line 190
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