class Object

Constants

CAS_CLIENT_METHODS
CURB_MIN_VERSION
EXCON_MIDDLEWARE_MIN_VERSION
EXCON_MIN_VERSION

We have two ways of instrumenting Excon:

  • For newer versions, use the middleware mechanism Excon exposes

  • For older versions, monkey-patch Excon::Connection#request

EXCON_MIN_VERSION is the minimum version we attempt to instrument at all. EXCON_MIDDLEWARE_MIN_VERSION is the min version we use the newer

instrumentation for.

Note that middlewares were added to Excon prior to 0.19, but we don’t use middleware-based instrumentation prior to that version because it didn’t expose a way for middlewares to know about request failures.

Why don’t we use Excon.defaults? While this might seem a perfect fit, it unfortunately isn’t suitable in current form. Someone might reasonably set the default instrumentor to something else after we install our instrumentation. Ideally, excon would itself conform to the subscribe interface of ActiveSupport::Notifications, so we could safely subscribe and not be clobbered by future subscribers, but alas, it does not yet.

HTTPCLIENT_MIN_VERSION

Public Class Methods

new(*args) click to toggle source
Calls superclass method
# File lib/mmtrix/agent/instrumentation/resque.rb, line 67
def self.new(*args)
  super(*args).extend Mmtrix::Agent::Instrumentation::ResqueInstrumentationInstaller
end

Public Instance Methods

_dispatch_with_mmtrix_trace(*args) click to toggle source
# File lib/mmtrix/agent/instrumentation/merb/controller.rb, line 32
def _dispatch_with_mmtrix_trace(*args)
  options = {}
  options[:params] = params
  perform_action_with_mmtrix_trace(options) do
    _dispatch_without_mmtrix_trace(*args)
  end
end
call_with_mmtrix(env) click to toggle source
# File lib/mmtrix/agent/instrumentation/grape.rb, line 91
def call_with_mmtrix(env)
  begin
    response = call_without_mmtrix(env)
  ensure
    begin
      endpoint = env[::Mmtrix::Agent::Instrumentation::GrapeInstrumentation::API_ENDPOINT]
      ::Mmtrix::Agent::Instrumentation::GrapeInstrumentation.handle_transaction(endpoint, self.class.name)
    rescue => e
      ::Mmtrix::Agent.logger.warn("Error in Grape instrumentation", e)
    end
  end

  response
end
ensure_index_with_mmtrix_trace(spec, opts = {}, &block) click to toggle source
# File lib/mmtrix/agent/instrumentation/mongo.rb, line 101
def ensure_index_with_mmtrix_trace(spec, opts = {}, &block)
  metrics = mmtrix_generate_metrics(:ensureIndex)
  trace_execution_scoped(metrics) do
    t0 = Time.now

    result = Mmtrix::Agent.disable_all_tracing do
      ensure_index_without_mmtrix_trace(spec, opts, &block)
    end

    spec = case spec
           when Array
             Hash[spec]
           when String, Symbol
             { spec => 1 }
           else
             spec.dup
           end

    mmtrix_notice_statement(t0, spec, :ensureIndex)
    result
  end
end
hook_instrument_method(target_class) click to toggle source
# File lib/mmtrix/agent/instrumentation/mongo.rb, line 38
def hook_instrument_method(target_class)
  target_class.class_eval do
    include Mmtrix::Agent::MethodTracer

    # It's key that this method eats all exceptions, as it rests between the
    # Mongo operation the user called and us returning them the data. Be safe!
    def mmtrix_notice_statement(t0, payload, name)
      statement = Mmtrix::Agent::Datastores::Mongo::StatementFormatter.format(payload, name)
      if statement
        Mmtrix::Agent.instance.transaction_sampler.notice_nosql_statement(statement, (Time.now - t0).to_f)
      end
    rescue => e
      Mmtrix::Agent.logger.debug("Exception during Mongo statement gathering", e)
    end

    def mmtrix_generate_metrics(operation, payload = nil)
      payload ||= { :collection => self.name, :database => self.db.name }
      Mmtrix::Agent::Datastores::Mongo::MetricTranslator.metrics_for(operation, payload)
    end

    def instrument_with_mmtrix_trace(name, payload = {}, &block)
      metrics = mmtrix_generate_metrics(name, payload)

      trace_execution_scoped(metrics) do
        t0 = Time.now

        result = Mmtrix::Agent.disable_all_tracing do
          instrument_without_mmtrix_trace(name, payload, &block)
        end

        mmtrix_notice_statement(t0, payload, name)
        result
      end
    end

    alias_method :instrument_without_mmtrix_trace, :instrument
    alias_method :instrument, :instrument_with_mmtrix_trace
  end
end
hook_instrument_methods() click to toggle source
# File lib/mmtrix/agent/instrumentation/mongo.rb, line 31
def hook_instrument_methods
  hook_instrument_method(::Mongo::Collection)
  hook_instrument_method(::Mongo::Connection)
  hook_instrument_method(::Mongo::Cursor)
  hook_instrument_method(::Mongo::CollectionWriter) if defined?(::Mongo::CollectionWriter)
end
initialize(*args)
Also aliased as: initialize_without_mmtrix
initialize_with_mmtrix(*args) click to toggle source
# File lib/mmtrix/agent/instrumentation/delayed_job_instrumentation.rb, line 24
def initialize_with_mmtrix(*args)
  initialize_without_mmtrix(*args)
  worker_name = case
                when self.respond_to?(:name) then self.name
                when self.class.respond_to?(:default_name) then self.class.default_name
                end
  Mmtrix::DelayedJobInjection.worker_name = worker_name

  if defined?(::Delayed::Job) && ::Delayed::Job.method_defined?(:invoke_job)
    ::Mmtrix::Agent.logger.info 'Installing DelayedJob instrumentation [part 2/2]'
    install_mmtrix_job_tracer
    Mmtrix::Control.instance.init_plugin :dispatcher => :delayed_job
  else
    Mmtrix::Agent.logger.warn("Did not find a Delayed::Job class responding to invoke_job, aborting DJ instrumentation")
  end
end
Also aliased as: initialize
initialize_without_mmtrix(*args)
Alias for: initialize
install_excon_instrumentation(excon_version) click to toggle source
# File lib/mmtrix/agent/instrumentation/excon.rb, line 44
def install_excon_instrumentation(excon_version)
  require 'mmtrix/agent/cross_app_tracing'
  require 'mmtrix/agent/http_clients/excon_wrappers'

  if excon_version >= EXCON_MIDDLEWARE_MIN_VERSION
    install_middleware_excon_instrumentation
  else
    install_legacy_excon_instrumentation
  end
end
install_legacy_excon_instrumentation() click to toggle source
# File lib/mmtrix/agent/instrumentation/excon.rb, line 67
def install_legacy_excon_instrumentation
  ::Mmtrix::Agent.logger.info 'Installing legacy Excon instrumentation'
  require 'mmtrix/agent/instrumentation/excon/connection'
  ::Excon::Connection.install_mmtrix_instrumentation
end
install_middleware_excon_instrumentation() click to toggle source
# File lib/mmtrix/agent/instrumentation/excon.rb, line 55
def install_middleware_excon_instrumentation
  ::Mmtrix::Agent.logger.info 'Installing middleware-based Excon instrumentation'
  require 'mmtrix/agent/instrumentation/excon/middleware'
  defaults = Excon.defaults

  if defaults[:middlewares]
    defaults[:middlewares] << ::Excon::Middleware::MmtrixCrossAppTracing
  else
    ::Mmtrix::Agent.logger.warn("Did not find :middlewares key in Excon.defaults, skipping Excon instrumentation")
  end
end
install_mmtrix_job_tracer() click to toggle source
# File lib/mmtrix/agent/instrumentation/delayed_job_instrumentation.rb, line 44
def install_mmtrix_job_tracer
  Delayed::Job.class_eval do
    include Mmtrix::Agent::Instrumentation::ControllerInstrumentation
    if self.instance_methods.include?('name') || self.instance_methods.include?(:name)
      add_transaction_tracer "invoke_job", :category => 'OtherTransaction/DelayedJob', :path => '#{self.name}'
    else
      add_transaction_tracer "invoke_job", :category => 'OtherTransaction/DelayedJob'
    end
  end
end
install_mongo_instrumentation() click to toggle source
# File lib/mmtrix/agent/instrumentation/mongo.rb, line 22
def install_mongo_instrumentation
  require 'mmtrix/agent/datastores/mongo/metric_translator'
  require 'mmtrix/agent/datastores/mongo/statement_formatter'

  hook_instrument_methods
  instrument_save
  instrument_ensure_index
end
instrument_call() click to toggle source
# File lib/mmtrix/agent/instrumentation/grape.rb, line 89
def instrument_call
  ::Grape::API.class_eval do
    def call_with_mmtrix(env)
      begin
        response = call_without_mmtrix(env)
      ensure
        begin
          endpoint = env[::Mmtrix::Agent::Instrumentation::GrapeInstrumentation::API_ENDPOINT]
          ::Mmtrix::Agent::Instrumentation::GrapeInstrumentation.handle_transaction(endpoint, self.class.name)
        rescue => e
          ::Mmtrix::Agent.logger.warn("Error in Grape instrumentation", e)
        end
      end

      response
    end

    alias_method :call_without_mmtrix, :call
    alias_method :call, :call_with_mmtrix
  end
end
instrument_ensure_index() click to toggle source
# File lib/mmtrix/agent/instrumentation/mongo.rb, line 99
def instrument_ensure_index
  ::Mongo::Collection.class_eval do
    def ensure_index_with_mmtrix_trace(spec, opts = {}, &block)
      metrics = mmtrix_generate_metrics(:ensureIndex)
      trace_execution_scoped(metrics) do
        t0 = Time.now

        result = Mmtrix::Agent.disable_all_tracing do
          ensure_index_without_mmtrix_trace(spec, opts, &block)
        end

        spec = case spec
               when Array
                 Hash[spec]
               when String, Symbol
                 { spec => 1 }
               else
                 spec.dup
               end

        mmtrix_notice_statement(t0, spec, :ensureIndex)
        result
      end
    end

    alias_method :ensure_index_without_mmtrix_trace, :ensure_index
    alias_method :ensure_index, :ensure_index_with_mmtrix_trace
  end
end
instrument_save() click to toggle source
# File lib/mmtrix/agent/instrumentation/mongo.rb, line 78
def instrument_save
  ::Mongo::Collection.class_eval do
    def save_with_mmtrix_trace(doc, opts = {}, &block)
      metrics = mmtrix_generate_metrics(:save)
      trace_execution_scoped(metrics) do
        t0 = Time.now

        result = Mmtrix::Agent.disable_all_tracing do
          save_without_mmtrix_trace(doc, opts, &block)
        end

        mmtrix_notice_statement(t0, doc, :save)
        result
      end
    end

    alias_method :save_without_mmtrix_trace, :save
    alias_method :save, :save_with_mmtrix_trace
  end
end
instrument_with_mmtrix(name, payload = {}, &block) click to toggle source
# File lib/mmtrix/agent/instrumentation/rails3/action_controller.rb, line 161
def instrument_with_mmtrix(name, payload = {}, &block)
  identifier = payload[:identifier]
  scope_name = "View/#{Mmtrix::Agent::Instrumentation::Rails3::ActionView::Mmtrix.template_metric(identifier)}/Partial"
  trace_execution_scoped(scope_name) do
    instrument_without_mmtrix(name, payload, &block)
  end
end
instrument_with_mmtrix_trace(name, payload = {}, &block) click to toggle source
# File lib/mmtrix/agent/instrumentation/mongo.rb, line 58
def instrument_with_mmtrix_trace(name, payload = {}, &block)
  metrics = mmtrix_generate_metrics(name, payload)

  trace_execution_scoped(metrics) do
    t0 = Time.now

    result = Mmtrix::Agent.disable_all_tracing do
      instrument_without_mmtrix_trace(name, payload, &block)
    end

    mmtrix_notice_statement(t0, payload, name)
    result
  end
end
lookup_changelog() click to toggle source
# File lib/mmtrix/recipes/capistrano3.rb, line 55
def lookup_changelog
  debug "Retrieving changelog for Mmtrix Deployment details"
  previous_revision = fetch(:previous_revision)
  current_revision = fetch(:current_revision)

  if scm == :git
    log_command = "git log --no-color --pretty=format:'  * %an: %s' " +
                  "--abbrev-commit --no-merges #{previous_revision}..#{current_revision}"
    `#{log_command}`
  end
end
lookup_rev(rev) click to toggle source
# File lib/mmtrix/recipes/capistrano_legacy.rb, line 72
def lookup_rev(rev)
  if rev.nil?
    rev = source.query_revision(source.head()) do |cmd|
      logger.debug "executing locally: '#{cmd}'"
      `#{cmd}`
    end

    rev = rev[0..6] if scm == :git
  end
  rev
end
mmtrix_generate_metrics(operation, payload = nil) click to toggle source
# File lib/mmtrix/agent/instrumentation/mongo.rb, line 53
def mmtrix_generate_metrics(operation, payload = nil)
  payload ||= { :collection => self.name, :database => self.db.name }
  Mmtrix::Agent::Datastores::Mongo::MetricTranslator.metrics_for(operation, payload)
end
mmtrix_metric_path() click to toggle source

determine the path that is used in the metric name for the called controller action

# File lib/mmtrix/agent/instrumentation/merb/controller.rb, line 26
def mmtrix_metric_path
  "#{controller_name}/#{action_name}"
end
mmtrix_notice_error(exception, custom_params = {}) click to toggle source

Make a note of an exception associated with the currently executing controller action. Note that this used to be available on Object but we replaced that global method with Mmtrix::Agent#notice_error. Use that one instead.

@api public @deprecated

# File lib/mmtrix/agent/instrumentation/rails/errors.rb, line 31
def mmtrix_notice_error(exception, custom_params = {})
  Mmtrix::Agent::Deprecator.deprecate("ActionController#mmtrix_notice_error",
                                        "Mmtrix::Agent#notice_error")

  Mmtrix::Agent::Transaction.notice_error exception, :custom_params => custom_params
end
mmtrix_notice_statement(t0, payload, name) click to toggle source

It’s key that this method eats all exceptions, as it rests between the Mongo operation the user called and us returning them the data. Be safe!

# File lib/mmtrix/agent/instrumentation/mongo.rb, line 44
def mmtrix_notice_statement(t0, payload, name)
  statement = Mmtrix::Agent::Datastores::Mongo::StatementFormatter.format(payload, name)
  if statement
    Mmtrix::Agent.instance.transaction_sampler.notice_nosql_statement(statement, (Time.now - t0).to_f)
  end
rescue => e
  Mmtrix::Agent.logger.debug("Exception during Mongo statement gathering", e)
end
perform_action_with_mmtrix_trace_wrapper() click to toggle source
# File lib/mmtrix/agent/instrumentation/rails/action_controller.rb, line 98
def perform_action_with_mmtrix_trace_wrapper
  munged_params = (respond_to?(:filter_parameters)) ? filter_parameters(params) : params
  munged_params = Mmtrix::Agent::ParameterFiltering.filter_rails_request_parameters(munged_params)

  perform_action_with_mmtrix_trace(:params => munged_params) do
    perform_action_without_mmtrix_trace
  end
end
render_with_mmtrix(*args, &block) click to toggle source
# File lib/mmtrix/agent/instrumentation/rails3/action_controller.rb, line 103
def render_with_mmtrix(*args, &block)
  options = if @virtual_path && @virtual_path.starts_with?('/') # file render
    {:file => true }
  else
    {}
  end
  str = "View/#{Mmtrix::Agent::Instrumentation::Rails3::ActionView::Mmtrix.template_metric(@identifier, options)}/#{Mmtrix::Agent::Instrumentation::Rails3::ActionView::Mmtrix.render_type(@identifier)}"
  trace_execution_scoped str do
    render_without_mmtrix(*args, &block)
  end
end
rescue_action_with_mmtrix_trace(exception) click to toggle source
# File lib/mmtrix/agent/instrumentation/rails/errors.rb, line 38
def rescue_action_with_mmtrix_trace(exception)
  rescue_action_without_mmtrix_trace exception
  Mmtrix::Agent::Transaction.notice_error exception
end
save_with_mmtrix_trace(doc, opts = {}, &block) click to toggle source
# File lib/mmtrix/agent/instrumentation/mongo.rb, line 80
def save_with_mmtrix_trace(doc, opts = {}, &block)
  metrics = mmtrix_generate_metrics(:save)
  trace_execution_scoped(metrics) do
    t0 = Time.now

    result = Mmtrix::Agent.disable_all_tracing do
      save_without_mmtrix_trace(doc, opts, &block)
    end

    mmtrix_notice_statement(t0, doc, :save)
    result
  end
end
supported_sequel_version?() click to toggle source
# File lib/mmtrix/agent/instrumentation/sequel.rb, line 17
def supported_sequel_version?
  Sequel.const_defined?( :MAJOR ) &&
    ( Sequel::MAJOR > 3 ||
      Sequel::MAJOR == 3 && Sequel::MINOR >= 37 )
end