有没有办法自动记录每次 ActiveRecord 回调发生的日志?当记录有多个回调时,这将有助于跟踪特定事情发生的原因。
我希望看到自动化日志消息,指示响应哪些回调而调用了哪些消息。例如:
我希望看到自动化日志消息,指示响应哪些回调而调用了哪些消息。例如:
before_validation:calling update_capitalization
before_validation:calling update_capitalization
我刚刚为此编写了一个宝石(gem)。
# Gemfile
gem "rails-callback_log", group: [:development, :test]
为了Google和后人(在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
更简单的方法是使用Rails本地记录器方法:
像这样使用它:
logger.debug "Person attributes hash: #{@person.attributes.inspect}"
logger.info "Processing the request..."
logger.fatal "Terminating application, raised unrecoverable error!!!"
编辑:
检查异常发生时调用了什么也是很有趣的用法。
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