修改Rails 3中默认ActionController LogSubscriber的日志格式和内容

语境:

在rails 3项目中,我想(大量)自定义ActionController中“Processing”和“Completed in”日志行的格式和内容。 这是为了让它们与旧版rails 2.3 app的(也是自定义)格式相匹配,允许重复使用各种分析工具。 使它们成为固定字段(通过在必要时使用占位符)也可以更容易地使用(例如)awk对它们进行即席查询,或者在没有智能解析的情况下将它们加载到db或splunk中。

我通过分叉导轨和修补有问题的LogSubscriber快速而严谨地实现了这个目标,但我现在正在寻找正确的方法。

这是我想我想做的事情:

  1. 创建一个inheritanceActionController::LogSubscriber
  2. 仅覆盖start_processingprocess_action方法。
  3. 取消订阅原始的ActionController::LogSubscriber ,它(遗憾地)在加载类后立即注册。 这是我坚持的步骤。
  4. 使用attach_to将我的自定义订阅者附加到:action_controller attach_to

我注意到,如果默认ActionController的日志订阅者的连接是作为配置步骤而不是类加载完成的,事情会更容易。

题:

假设上面概述的方法是合适的,我如何取消订阅或取消附加默认日志订阅者ActionController::LogSubscriber ? 基类ActiveSupport :: LogSubscriber提供了attach_to但没有分离的方法。

或者,在上面提到的类ActionController :: LogSubscriber中 ,改变(或完全抑制)两个方法(start_processing,process_action)的行为的最简洁方法是什么 。

当然,我也欢迎任何其他(可维护的)方法,它可以完全自由地定制所提到的两行的日志格式。

不合适的方法:

  • 我的问题不能通过添加仪器来解决,正如mnutt很好地记录的那样 。
  • 我想避免猴子修补,或者在rails实现(不是接口)改变时可能会破坏的方式进行黑客攻击。

参考文献:

  • ActiveSupport::LogSubscriber 文档和来源
  • ActionController::LogSubscriberActionController::LogSubscriber
  • ActiveSupport::Notifications Docs , Source和RailsCast

我已经找到了以下解决方案。

我对它的各个方面并不特别满意(例如,必须取消订阅所有对’process_action.action_controller’的兴趣),我当然会接受更好的答案。

我们将以下内容添加为config/initializers/custom_ac_log_subscriber.rb

 module MyApp class CustomAcLogSubscriber < ActiveSupport::LogSubscriber INTERNAL_PARAMS = ActionController::LogSubscriber::INTERNAL_PARAMS #Do your custom stuff here. (The following is much simplified). def start_processing(event) payload = event.payload params = payload[:params].except(*INTERNAL_PARAMS) info "Processing #{payload[:controller]}##{payload[:action]} (...)" info " Parameters: #{params.inspect}" unless params.empty? end def process_action(event) payload = event.payload message = "Completed in %.0fms [#{payload[:path]}]" % event.duration info(message) end def logger ActionController::Base.logger end end end #Prevent ActionController::LogSubscriber from also acting on these notifications #Note that the following undesireably unregisters *everyone's* #interest in these. We can't target one LogSubscriber, it seems(?) %w(process_action start_processing).each do |evt| ActiveSupport::Notifications.unsubscribe "#{evt}.action_controller" end #Register our own interest MyApp::CustomAcLogSubscriber.attach_to :action_controller 

关于中止初始方法的说明:

我最初尝试了取消注册默认LogSubscriber的方法,意图是我们的自定义将inheritance并完成所有工作(无需重新注册)。

但是,存在许多问题。

1)删除LogSubscriber是不够的,如下所示:

 ActiveSupport::LogSubscriber.log_subscribers.delete_if{ |ls| ls.instance_of? ActionController::LogSubscriber } 

由于通知请求仍在注册。

2)此外,当您inheritanceLogSubscriber并注册它时,似乎不会使用inheritance的实现调用任何未重写的方法。

为了取消订阅,我找到了这个解决方案:(Rails 3.0.10):

 notifier = ActiveSupport::Notifications.notifier subscribers = notifier.listeners_for("sql.active_record") subscribers.each {|s| ActiveSupport::Notifications.unsubscribe s } 

对于其他寻找此项目的人来说,Mathias Meyer有一个很好的写作

此外,他有一个gem ,可以作为如何取消订阅现有订阅者并替换自己的订阅者的一个很好的例子。

如果您想取消订阅与正则表达式匹配的模式,您可以这样做:

 ActiveSupport::Subscriber.subscribers.flat_map(&:patterns).grep(/sql/).map \ &ActiveSupport::Notifications.method(:unsubscribe)