module Airbrake::Rack::Instrumentable
def self.chain_capture_timing(klass, method_name, label)
- Api: - private
def self.chain_capture_timing(klass, method_name, label) args = method_signature visibility = method_visibility(klass, method_name) # Generate the wrapper method. aliased = method_name.to_s.sub(/([?!=])$/, '') punctuation = Regexp.last_match(1) wrapped_method_name = "#{aliased}_without_airbrake#{punctuation}" needs_removal = method_needs_removal(klass, method_name) klass.module_exec do alias_method wrapped_method_name, method_name remove_method method_name if needs_removal # rubocop:disable Style/DocumentDynamicEvalDefinition module_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{method_name}(#{args}) Airbrake::Rack.capture_timing(#{label.to_s.inspect}) do __send__("#{aliased}_without_airbrake#{punctuation}", #{args}) end end #{visibility} :#{method_name} RUBY # rubocop:enable Style/DocumentDynamicEvalDefinition end end
def self.method_needs_removal(klass, method_name)
def self.method_needs_removal(klass, method_name) klass.method_defined?(method_name, false) || klass.private_method_defined?(method_name, false) end
def self.method_needs_removal(klass, method_name)
def self.method_needs_removal(klass, method_name) klass.instance_methods(false).include?(method_name) || klass.private_instance_methods(false).include?(method_name) end
def self.method_signature
def self.method_signature "*args, **kw_args, &block" end
def self.method_signature
def self.method_signature "*args, &block" end
def self.method_visibility(klass, method_name)
- Api: - private
def self.method_visibility(klass, method_name) klass.module_exec do if protected_method_defined?(method_name) "protected" elsif private_method_defined?(method_name) "private" else "public" end end end
def self.prepend_capture_timing(klass, method_name, label)
- Api: - private
def self.prepend_capture_timing(klass, method_name, label) args = method_signature visibility = method_visibility(klass, method_name) # Generate the wrapper method. klass.module_exec do mod = __airbrake_capture_timing_module__ mod.module_exec do # rubocop:disable Style/DocumentDynamicEvalDefinition module_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{method_name}(#{args}) Airbrake::Rack.capture_timing(#{label.to_s.inspect}) do super end end #{visibility} :#{method_name} RUBY # rubocop:enable Style/DocumentDynamicEvalDefinition end prepend mod end end
def self.should_prepend?(klass, method_name)
- Api: - private
def self.should_prepend?(klass, method_name) # Don't chain already-prepended or operator methods. klass.module_exec do self_class_idx = ancestors.index(self) method_owner_idx = ancestors.index(instance_method(method_name).owner) method_owner_idx < self_class_idx || !(/\A\W/ =~ method_name).nil? end end
def __airbrake_capture_timing_module__
- Api: - private
def __airbrake_capture_timing_module__ # Module used to store prepended wrapper methods, saved as an instance # variable so each target class/module gets its own module. This just # a convenience to avoid prepending a lot of anonymous modules. @__airbrake_capture_timing_module__ ||= ::Module.new end
def airbrake_capture_timing(method_name, label: method_name.to_s)
def airbrake_capture_timing(method_name, label: method_name.to_s) instrumentable = ::Airbrake::Rack::Instrumentable if instrumentable.should_prepend?(self, method_name) instrumentable.prepend_capture_timing(self, method_name, label) else instrumentable.chain_capture_timing(self, method_name, label) end method_name end