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
NR_TRANSACTION_CATEGORY

Public Class Methods

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

Public Instance Methods

_dispatch_with_newrelic_trace(*args) click to toggle source
# File lib/new_relic/agent/instrumentation/merb/controller.rb, line 31
def _dispatch_with_newrelic_trace(*args)
  options = {}
  options[:params] = params
  perform_action_with_newrelic_trace(options) do
    _dispatch_without_newrelic_trace(*args)
  end
end
call(*args, &block) click to toggle source
# File lib/new_relic/agent/instrumentation/redis.rb, line 30
def call(*args, &block)
  operation = args[0][0]
  statement = ::NewRelic::Agent::Datastores::Redis.format_command(args[0])

  if statement
    callback = Proc.new do |result, _, elapsed|
      NewRelic::Agent::Datastores.notice_statement(statement, elapsed)
    end
  end

  NewRelic::Agent::Datastores.wrap(NewRelic::Agent::Datastores::Redis::PRODUCT_NAME, operation, nil, callback) do
    call_without_new_relic(*args, &block)
  end
end
call_pipeline(*args, &block) click to toggle source
# File lib/new_relic/agent/instrumentation/redis.rb, line 47
def call_pipeline(*args, &block)
  pipeline = args[0]
  operation = pipeline.is_a?(::Redis::Pipeline::Multi) ? NewRelic::Agent::Datastores::Redis::MULTI_OPERATION : NewRelic::Agent::Datastores::Redis::PIPELINE_OPERATION
  statement = ::NewRelic::Agent::Datastores::Redis.format_pipeline_commands(pipeline.commands)

  callback = Proc.new do |result, _, elapsed|
    NewRelic::Agent::Datastores.notice_statement(statement, elapsed)
  end

  NewRelic::Agent::Datastores.wrap(NewRelic::Agent::Datastores::Redis::PRODUCT_NAME, operation, nil, callback) do
    call_pipeline_without_new_relic(*args, &block)
  end
end
call_with_new_relic(env) click to toggle source
# File lib/new_relic/agent/instrumentation/grape.rb, line 90
def call_with_new_relic(env)
  begin
    response = call_without_new_relic(env)
  ensure
    begin
      endpoint = env[::NewRelic::Agent::Instrumentation::GrapeInstrumentation::API_ENDPOINT]
      ::NewRelic::Agent::Instrumentation::GrapeInstrumentation.handle_transaction(endpoint, self.class.name)
    rescue => e
      ::NewRelic::Agent.logger.warn("Error in Grape instrumentation", e)
    end
  end

  response
end
connect(*args, &block) click to toggle source
# File lib/new_relic/agent/instrumentation/redis.rb, line 63
def connect(*args, &block)
  NewRelic::Agent::Datastores.wrap(NewRelic::Agent::Datastores::Redis::PRODUCT_NAME, NewRelic::Agent::Datastores::Redis::CONNECT) do
    connect_without_new_relic(*args, &block)
  end
end
ensure_index_with_new_relic_trace(spec, opts = {}, &block) click to toggle source
# File lib/new_relic/agent/instrumentation/mongo.rb, line 115
def ensure_index_with_new_relic_trace(spec, opts = {}, &block)
  metrics = new_relic_generate_metrics(:ensureIndex)
  trace_execution_scoped(metrics) do
    t0 = Time.now

    result = NewRelic::Agent.disable_all_tracing do
      ensure_index_without_new_relic_trace(spec, opts, &block)
    end

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

    new_relic_notice_statement(t0, spec, :ensureIndex)
    result
  end
end
hook_instrument_method(target_class) click to toggle source
# File lib/new_relic/agent/instrumentation/mongo.rb, line 52
def hook_instrument_method(target_class)
  target_class.class_eval do
    include NewRelic::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 new_relic_notice_statement(t0, payload, name)
      statement = NewRelic::Agent::Datastores::Mongo::StatementFormatter.format(payload, name)
      if statement
        NewRelic::Agent.instance.transaction_sampler.notice_nosql_statement(statement, (Time.now - t0).to_f)
      end
    rescue => e
      NewRelic::Agent.logger.debug("Exception during Mongo statement gathering", e)
    end

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

    def instrument_with_new_relic_trace(name, payload = {}, &block)
      metrics = new_relic_generate_metrics(name, payload)

      trace_execution_scoped(metrics) do
        t0 = Time.now

        result = NewRelic::Agent.disable_all_tracing do
          instrument_without_new_relic_trace(name, payload, &block)
        end

        new_relic_notice_statement(t0, payload, name)
        result
      end
    end

    alias_method :instrument_without_new_relic_trace, :instrument
    alias_method :instrument, :instrument_with_new_relic_trace
  end
end
hook_instrument_methods() click to toggle source
# File lib/new_relic/agent/instrumentation/mongo.rb, line 45
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_new_relic
initialize_with_new_relic(*args) click to toggle source
# File lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb, line 91
def initialize_with_new_relic(*args)
  initialize_without_new_relic(*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
  NewRelic::DelayedJobInjection.worker_name = worker_name

  if defined?(::Delayed::Job) && ::Delayed::Job.method_defined?(:invoke_job)
    ::NewRelic::Agent.logger.info 'Installing DelayedJob instrumentation [part 2/2]'
    install_newrelic_job_tracer
    NewRelic::Control.instance.init_plugin :dispatcher => :delayed_job
  else
    NewRelic::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_new_relic(*args)
Alias for: initialize
install_excon_instrumentation(excon_version) click to toggle source
# File lib/new_relic/agent/instrumentation/excon.rb, line 43
def install_excon_instrumentation(excon_version)
  require 'new_relic/agent/cross_app_tracing'
  require 'new_relic/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/new_relic/agent/instrumentation/excon.rb, line 66
def install_legacy_excon_instrumentation
  ::NewRelic::Agent.logger.info 'Installing legacy Excon instrumentation'
  require 'new_relic/agent/instrumentation/excon/connection'
  ::Excon::Connection.install_newrelic_instrumentation
end
install_middleware_excon_instrumentation() click to toggle source
# File lib/new_relic/agent/instrumentation/excon.rb, line 54
def install_middleware_excon_instrumentation
  ::NewRelic::Agent.logger.info 'Installing middleware-based Excon instrumentation'
  require 'new_relic/agent/instrumentation/excon/middleware'
  defaults = Excon.defaults

  if defaults[:middlewares]
    defaults[:middlewares] << ::Excon::Middleware::NewRelicCrossAppTracing
  else
    ::NewRelic::Agent.logger.warn("Did not find :middlewares key in Excon.defaults, skipping Excon instrumentation")
  end
end
install_mongo_command_subscriber() click to toggle source
# File lib/new_relic/agent/instrumentation/mongo.rb, line 28
def install_mongo_command_subscriber
  require 'new_relic/agent/instrumentation/mongodb_command_subscriber'
  Mongo::Monitoring::Global.subscribe(
    Mongo::Monitoring::COMMAND,
    NewRelic::Agent::Instrumentation::MongodbCommandSubscriber.new
  )
end
install_mongo_instrumentation() click to toggle source
# File lib/new_relic/agent/instrumentation/mongo.rb, line 36
def install_mongo_instrumentation
  require 'new_relic/agent/datastores/mongo/metric_translator'
  require 'new_relic/agent/datastores/mongo/statement_formatter'

  hook_instrument_methods
  instrument_save
  instrument_ensure_index
end
install_newrelic_job_tracer() click to toggle source
# File lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb, line 113
def install_newrelic_job_tracer
  Delayed::Job.class_eval do
    include NewRelic::Agent::Instrumentation::ControllerInstrumentation

    alias_method :invoke_job_without_new_relic, :invoke_job

    def invoke_job(*args, &block)
      options = {
        :category => NR_TRANSACTION_CATEGORY,
        :path => ::NewRelic::Agent::Instrumentation::DelayedJob::Naming.name_from_payload(payload_object)
      }

      perform_action_with_newrelic_trace(options) do
        invoke_job_without_new_relic(*args, &block)
      end
    end
  end
end
instrument_call() click to toggle source
# File lib/new_relic/agent/instrumentation/grape.rb, line 88
def instrument_call
  ::Grape::API.class_eval do
    def call_with_new_relic(env)
      begin
        response = call_without_new_relic(env)
      ensure
        begin
          endpoint = env[::NewRelic::Agent::Instrumentation::GrapeInstrumentation::API_ENDPOINT]
          ::NewRelic::Agent::Instrumentation::GrapeInstrumentation.handle_transaction(endpoint, self.class.name)
        rescue => e
          ::NewRelic::Agent.logger.warn("Error in Grape instrumentation", e)
        end
      end

      response
    end

    alias_method :call_without_new_relic, :call
    alias_method :call, :call_with_new_relic
  end
end
instrument_ensure_index() click to toggle source
# File lib/new_relic/agent/instrumentation/mongo.rb, line 113
def instrument_ensure_index
  ::Mongo::Collection.class_eval do
    def ensure_index_with_new_relic_trace(spec, opts = {}, &block)
      metrics = new_relic_generate_metrics(:ensureIndex)
      trace_execution_scoped(metrics) do
        t0 = Time.now

        result = NewRelic::Agent.disable_all_tracing do
          ensure_index_without_new_relic_trace(spec, opts, &block)
        end

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

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

    alias_method :ensure_index_without_new_relic_trace, :ensure_index
    alias_method :ensure_index, :ensure_index_with_new_relic_trace
  end
end
instrument_save() click to toggle source
# File lib/new_relic/agent/instrumentation/mongo.rb, line 92
def instrument_save
  ::Mongo::Collection.class_eval do
    def save_with_new_relic_trace(doc, opts = {}, &block)
      metrics = new_relic_generate_metrics(:save)
      trace_execution_scoped(metrics) do
        t0 = Time.now

        result = NewRelic::Agent.disable_all_tracing do
          save_without_new_relic_trace(doc, opts, &block)
        end

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

    alias_method :save_without_new_relic_trace, :save
    alias_method :save, :save_with_new_relic_trace
  end
end
instrument_with_new_relic_trace(name, payload = {}, &block) click to toggle source
# File lib/new_relic/agent/instrumentation/mongo.rb, line 72
def instrument_with_new_relic_trace(name, payload = {}, &block)
  metrics = new_relic_generate_metrics(name, payload)

  trace_execution_scoped(metrics) do
    t0 = Time.now

    result = NewRelic::Agent.disable_all_tracing do
      instrument_without_new_relic_trace(name, payload, &block)
    end

    new_relic_notice_statement(t0, payload, name)
    result
  end
end
instrument_with_newrelic(name, payload = {}, &block) click to toggle source
# File lib/new_relic/agent/instrumentation/rails3/action_controller.rb, line 162
def instrument_with_newrelic(name, payload = {}, &block)
  identifier = payload[:identifier]
  scope_name = "View/#{NewRelic::Agent::Instrumentation::Rails3::ActionView::NewRelic.template_metric(identifier)}/Partial"
  trace_execution_scoped(scope_name) do
    instrument_without_newrelic(name, payload, &block)
  end
end
invoke_job(*args, &block) click to toggle source
# File lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb, line 119
def invoke_job(*args, &block)
  options = {
    :category => NR_TRANSACTION_CATEGORY,
    :path => ::NewRelic::Agent::Instrumentation::DelayedJob::Naming.name_from_payload(payload_object)
  }

  perform_action_with_newrelic_trace(options) do
    invoke_job_without_new_relic(*args, &block)
  end
end
lookup_changelog() click to toggle source
# File lib/new_relic/recipes/capistrano3.rb, line 54
def lookup_changelog
  debug "Retrieving changelog for New Relic Deployment details"
  previous_revision = fetch(:previous_revision)
  current_revision = fetch(:current_revision)

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

    rev = rev[0..6] if scm == :git
  end
  rev
end
new_relic_generate_metrics(operation, payload = nil) click to toggle source
# File lib/new_relic/agent/instrumentation/mongo.rb, line 67
def new_relic_generate_metrics(operation, payload = nil)
  payload ||= { :collection => self.name, :database => self.db.name }
  NewRelic::Agent::Datastores::Mongo::MetricTranslator.metrics_for(operation, payload)
end
new_relic_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/new_relic/agent/instrumentation/mongo.rb, line 58
def new_relic_notice_statement(t0, payload, name)
  statement = NewRelic::Agent::Datastores::Mongo::StatementFormatter.format(payload, name)
  if statement
    NewRelic::Agent.instance.transaction_sampler.notice_nosql_statement(statement, (Time.now - t0).to_f)
  end
rescue => e
  NewRelic::Agent.logger.debug("Exception during Mongo statement gathering", e)
end
newrelic_metric_path() click to toggle source

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

# File lib/new_relic/agent/instrumentation/merb/controller.rb, line 25
def newrelic_metric_path
  "#{controller_name}/#{action_name}"
end
newrelic_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 NewRelic::Agent#notice_error. Use that one instead.

@api public @deprecated

# File lib/new_relic/agent/instrumentation/rails/errors.rb, line 30
def newrelic_notice_error(exception, custom_params = {})
  NewRelic::Agent::Deprecator.deprecate("ActionController#newrelic_notice_error",
                                        "NewRelic::Agent#notice_error")

  NewRelic::Agent::Transaction.notice_error exception, :custom_params => custom_params
end
perform_action_with_newrelic_trace_wrapper() click to toggle source
# File lib/new_relic/agent/instrumentation/rails/action_controller.rb, line 99
def perform_action_with_newrelic_trace_wrapper
  munged_params = (respond_to?(:filter_parameters)) ? filter_parameters(params) : params
  munged_params = NewRelic::Agent::ParameterFiltering.filter_rails_request_parameters(munged_params)

  perform_action_with_newrelic_trace(:params => munged_params) do
    perform_action_without_newrelic_trace
  end
end
render_with_newrelic(*args, &block) click to toggle source
# File lib/new_relic/agent/instrumentation/rails3/action_controller.rb, line 104
def render_with_newrelic(*args, &block)
  options = if @virtual_path && @virtual_path.starts_with?('/') # file render
    {:file => true }
  else
    {}
  end
  str = "View/#{NewRelic::Agent::Instrumentation::Rails3::ActionView::NewRelic.template_metric(@identifier, options)}/#{NewRelic::Agent::Instrumentation::Rails3::ActionView::NewRelic.render_type(@identifier)}"
  trace_execution_scoped str do
    render_without_newrelic(*args, &block)
  end
end
rescue_action_with_newrelic_trace(exception) click to toggle source
# File lib/new_relic/agent/instrumentation/rails/errors.rb, line 37
def rescue_action_with_newrelic_trace(exception)
  rescue_action_without_newrelic_trace exception
  NewRelic::Agent::Transaction.notice_error exception
end
save_with_new_relic_trace(doc, opts = {}, &block) click to toggle source
# File lib/new_relic/agent/instrumentation/mongo.rb, line 94
def save_with_new_relic_trace(doc, opts = {}, &block)
  metrics = new_relic_generate_metrics(:save)
  trace_execution_scoped(metrics) do
    t0 = Time.now

    result = NewRelic::Agent.disable_all_tracing do
      save_without_new_relic_trace(doc, opts, &block)
    end

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