跟踪/记录ActiveRecord回调

每次发生ActiveRecord回调时,有没有办法自动记录? 当记录有几个回调时,它将有助于追踪为什么某些事情发生了。

我希望看到自动日志消息,指示响应哪些回调调用哪些消息,例如: before_validation: calling update_capitalization

对于谷歌和后代(在Rails 3上):

 module CallbackTrace def self.included kls kls.send :alias_method_chain, :_compile_filter, :trace end def _compile_filter_with_trace filter generated_code = _compile_filter_without_trace(filter) return generated_code if filter.is_a?(Array) method_name = generated_code.to_s.split(%r{\(|\s}).first _klass = @klass prelogger = ->{ Rails.logger.info("START [#{filter.class}](#{generated_code})") Rails.logger.info("#{_klass} #{Time.now}") if imethod=(_klass.instance_method(method_name) rescue nil) begin Rails.logger.info(imethod.source) rescue MethodSource::SourceNotFoundError Rails.logger.info("NO SOURCE FOR #{generated_code}") end else Rails.logger.info("NO METHOD: #{method_name} for #{@klass}") end } postlogger = ->{ Rails.logger.info("ENDED #{generated_code} #{Time.now}") } @klass.send :define_method, "prelogger_#{method_name}", &prelogger @klass.send :define_method, "postlogger_#{method_name}", &postlogger "(prelogger_#{method_name}; retval = retval = #{generated_code}; " + "postlogger_#{method_name}; retval)" end end ActiveSupport::Callbacks::Callback.send :include, CallbackTrace 

我刚为此写了一个gem。

 # Gemfile gem "rails-callback_log", group: [:development, :test] 

更简单的方法是使用rails本机记录器方法:

调试Rails应用程序

像这样使用它:

 logger.debug "Person attributes hash: #{@person.attributes.inspect}" logger.info "Processing the request..." logger.fatal "Terminating application, raised unrecoverable error!!!" 

编辑:

检查发生exception时调用的内容也很有用

 logger.error("trace: #{ex.backtrace().join("\n")}") 

另一种方法是在所有模型上定义回调以进行记录。 为避免加载所有内容,您只需加载模型即可。 为简单起见,这会尝试加载与app/models/*.rb所有文件对应的类。 我也会使用puts ,但你可以使用Rails.logger.info或其他任何东西。 对于临时调试,您可以将其放入初始化程序,例如config/initializers/001_log_callbacks.rb

 # Log all callbacks Dir[Rails.root.join('app/models/*.rb').to_s].each do |filename| name = File.basename(filename, '.rb') begin model = name.camelize.constantize ActiveRecord::Callbacks::CALLBACKS.each do |callback| if callback.to_s.start_with?('around_') model.class_eval "#{callback} do |*args, &prc|; puts \"#{model}(\#{id}).#{callback} start\"; prc.call(*args) if prc; puts \"#{model}(\#{id}).#{callback} end\" end" else model.class_eval "#{callback} do; puts \"#{model}(\#{id}).#{callback}\" end" end end rescue end end