# Copyright (c) 2016 SolarWinds, LLC.
# All rights reserved.
module AppOpticsAPM
module Inst
#
# RailsBase
#
# This module contains the instrumentation code common to
# many Rails versions.
#
module RailsBase
#
# has_handler?
#
# Determins if exception has a registered
# handler via rescue_from
#
def has_handler?(exception)
# Don't log exceptions if they have a rescue handler set
has_handler = false
rescue_handlers.detect do |klass_name, _handler|
# Rescue handlers can be specified as strings or constant names
klass = self.class.const_get(klass_name) rescue nil
klass ||= klass_name.constantize rescue nil
has_handler = exception.is_a?(klass) if klass
end
has_handler
rescue => e
AppOpticsAPM.logger.debug "[appoptics_apm/debug] Error searching Rails handlers: #{e.message}"
return false
end
#
# log_rails_error?
#
# Determins whether we should log a raised exception to the
# AppOptics dashboard. This is determined by whether the exception
# has a rescue handler setup and the value of
# AppOpticsAPM::Config[:report_rescued_errors]
#
def log_rails_error?(exception)
# As it's perculating up through the layers... make sure that
# we only report it once.
return false if exception.instance_variable_get(:@exn_logged)
return false if has_handler?(exception) && !AppOpticsAPM::Config[:report_rescued_errors]
true
end
##
# This method does the logging if we are tracing
# it `wraps` around the call to the original method
#
# This can't use the SDK trace() method because of the log_rails_error?(e) condition
def trace(layer)
return yield unless AppOpticsAPM.tracing?
begin
AppOpticsAPM::API.log_entry(layer)
yield
rescue Exception => e
AppOpticsAPM::API.log_exception(layer, e) if log_rails_error?(e)
raise
ensure
AppOpticsAPM::API.log_exit(layer)
end
end
#
# render_with_appoptics
#
# Our render wrapper that calls 'add_logging', which will log if we are tracing
#
def render_with_appoptics(*args, &blk)
trace('actionview') do
render_without_appoptics(*args, &blk)
end
end
end
end
end
# ActionController::Base
if defined?(ActionController::Base) && AppOpticsAPM::Config[:action_controller][:enabled] && Rails::VERSION::MAJOR < 6
AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting actioncontroller' if AppOpticsAPM::Config[:verbose]
require "appoptics_apm/frameworks/rails/inst/action_controller#{Rails::VERSION::MAJOR}"
if Rails::VERSION::MAJOR == 5
ActionController::Base.send(:prepend, ::AppOpticsAPM::Inst::ActionController)
elsif Rails::VERSION::MAJOR < 5
AppOpticsAPM::Util.send_include(::ActionController::Base, AppOpticsAPM::Inst::ActionController)
end
end
# ActionController::API - Rails 5 or via the rails-api gem
if defined?(ActionController::API) && AppOpticsAPM::Config[:action_controller_api][:enabled] && Rails::VERSION::MAJOR < 6
AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting actioncontroller api' if AppOpticsAPM::Config[:verbose]
require "appoptics_apm/frameworks/rails/inst/action_controller_api"
ActionController::API.send(:prepend, ::AppOpticsAPM::Inst::ActionControllerAPI)
end
# vim:set expandtab:tabstop=2