如何在每个操作的基础上禁用 Ruby on Rails 的登录?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2196828/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I disable logging in Ruby on Rails on a per-action basis?
提问by archbishop
I have a Rails application which has an action which is invoked frequently enough to be inconvenient when I am developing, as it results in a lot of extra log output I don't care about. How can I get rails not to log anything (controller, action, parameters, complection time, etc.) for just this one action? I'd like to conditionalize it on RAILS_ENV as well, so logs in production are complete.
我有一个 Rails 应用程序,它有一个动作,它被频繁调用,在我开发时很不方便,因为它会导致很多我不关心的额外日志输出。我怎样才能让 rails 不为这一个动作记录任何东西(控制器、动作、参数、完成时间等)?我也想在 RAILS_ENV 上对其进行条件化,因此生产中的日志已完成。
Thanks!
谢谢!
采纳答案by archbishop
The answer turns out to be a lot harder than I expected, since rails really does provide no hook to do this. Instead, you need to wrap some of the guts of ActionController::Base. In the common base class for my controllers, I do
结果证明答案比我预期的要困难得多,因为 rails 确实没有提供任何钩子来做到这一点。相反,您需要包装 ActionController::Base 的一些内容。在我的控制器的公共基类中,我做
def silent?(action)
false
end
# this knows more than I'd like about the internals of process, but
# the other options require knowing even more. It would have been
# nice to be able to use logger.silence, but there isn't a good
# method to hook that around, due to the way benchmarking logs.
def log_processing_with_silence_logs
if logger && silent?(action_name) then
@old_logger_level, logger.level = logger.level, Logger::ERROR
end
log_processing_without_silence_logs
end
def process_with_silence_logs(request, response, method = :perform_action, *arguments)
ret = process_without_silence_logs(request, response, method, *arguments)
if logger && silent?(action_name) then
logger.level = @old_logger_level
end
ret
end
alias_method_chain :log_processing, :silence_logs
alias_method_chain :process, :silence_logs
then, in the controller with the method I want to suppress logging on:
然后,在控制器中使用我想禁止登录的方法:
def silent?(action)
RAILS_ENV == "development" && ['my_noisy_action'].include?(action)
end
回答by Josh Delsman
You can silence the Rails logger object:
您可以使 Rails 记录器对象静音:
def action
Rails.logger.silence do
# Things within this block will not be logged...
end
end
回答by merqlove
回答by Neil Stockbridge
The following works with at least Rails 3.1.0:
以下至少适用于 Rails 3.1.0:
Make a custom logger that can be silenced:
制作一个可以静音的自定义记录器:
# selective_logger.rb
class SelectiveLogger < Rails::Rack::Logger
def initialize app, opts = {}
@app = app
@opts = opts
@opts[:silenced] ||= []
end
def call env
if @opts[:silenced].include?(env['PATH_INFO']) || @opts[:silenced].any? {|silencer| silencer.is_a?( Regexp) && silencer.match( env['PATH_INFO']) }
Rails.logger.silence do
@app.call env
end
else
super env
end
end
end
Tell Rails to use it:
告诉 Rails 使用它:
# application.rb
config.middleware.swap Rails::Rack::Logger, SelectiveLogger, :silenced => ["/remote/every_minute", %r"^/assets/"]
The example above shows silencing asset serving requests, which in the development environment means less ( and sometimes no) scrolling back is required to see the actual request.
上面的示例显示了静默资产服务请求,这在开发环境中意味着查看实际请求所需的回滚更少(有时甚至不需要)。
回答by micred
You can add the gem to the Gemfile silencer.
您可以将 gem 添加到 Gemfile消音器。
gem 'silencer', '>= 1.0.1'
And in your config/initializers/silencer.rb :
在你的 config/initializers/silencer.rb 中:
require 'silencer/logger'
Rails.application.configure do
config.middleware.swap Rails::Rack::Logger, Silencer::Logger, silence: ['/api/notifications']
end
回答by Tombart
With Rails 5 it gets more complicated request processing is logged in several classes. Firstly we need to override call_appin Loggerclass, let's call this file lib/logger.rb:
在 Rails 5 中,更复杂的请求处理记录在几个类中。首先我们需要call_app在Logger类中覆盖,让我们调用这个文件lib/logger.rb:
# original class:
# https://github.com/rails/rails/blob/master/railties/lib/rails/rack/logger.rb
require 'rails/rack/logger'
module Rails
module Rack
class Logger < ActiveSupport::LogSubscriber
def call_app(request, env) # :doc:
unless Rails.configuration.logger_exclude.call(request.filtered_path)
instrumenter = ActiveSupport::Notifications.instrumenter
instrumenter.start "request.action_dispatch", request: request
logger.info { started_request_message(request) }
end
status, headers, body = @app.call(env)
body = ::Rack::BodyProxy.new(body) { finish(request) }
[status, headers, body]
rescue Exception
finish(request)
raise
ensure
ActiveSupport::LogSubscriber.flush_all!
end
end
end
end
Then follow with lib/silent_log_subscriber.rb:
然后跟随lib/silent_log_subscriber.rb:
require 'active_support/log_subscriber'
require 'action_view/log_subscriber'
require 'action_controller/log_subscriber'
# original class:
# https://github.com/rails/rails/blob/master/actionpack/lib/action_controller/log_subscriber.rb
class SilentLogSubscriber < ActiveSupport::LogSubscriber
def start_processing(event)
return unless logger.info?
payload = event.payload
return if Rails.configuration.logger_exclude.call(payload[:path])
params = payload[:params].except(*ActionController::LogSubscriber::INTERNAL_PARAMS)
format = payload[:format]
format = format.to_s.upcase if format.is_a?(Symbol)
info "Processing by #{payload[:controller]}##{payload[:action]} as #{format}"
info " Parameters: #{params.inspect}" unless params.empty?
end
def process_action(event)
return if Rails.configuration.logger_exclude.call(event.payload[:path])
info do
payload = event.payload
additions = ActionController::Base.log_process_action(payload)
status = payload[:status]
if status.nil? && payload[:exception].present?
exception_class_name = payload[:exception].first
status = ActionDispatch::ExceptionWrapper.status_code_for_exception(exception_class_name)
end
additions << "Allocations: #{event.allocations}" if event.respond_to? :allocations
message = +"Completed #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]} in #{event.duration.round}ms"
message << " (#{additions.join(" | ")})" unless additions.empty?
message << "\n\n" if defined?(Rails.env) && Rails.env.development?
message
end
end
def self.setup
# unsubscribe default processors
ActiveSupport::LogSubscriber.log_subscribers.each do |subscriber|
case subscriber
when ActionView::LogSubscriber
self.unsubscribe(:action_view, subscriber)
when ActionController::LogSubscriber
self.unsubscribe(:action_controller, subscriber)
end
end
end
def self.unsubscribe(component, subscriber)
events = subscriber.public_methods(false).reject { |method| method.to_s == 'call' }
events.each do |event|
ActiveSupport::Notifications.notifier.listeners_for("#{event}.#{component}").each do |listener|
if listener.instance_variable_get('@delegate') == subscriber
ActiveSupport::Notifications.unsubscribe listener
end
end
end
end
end
# subscribe this class
SilentLogSubscriber.attach_to :action_controller
SilentLogSubscriber.setup
Make sure to load modified modules e.g. in config/application.rbafter loading rails:
确保在加载config/application.rb后加载修改后的模块rails:
require_relative '../lib/logger'
require_relative '../lib/silent_log_subscriber'
Finally configure excluded paths:
最后配置排除路径:
Rails.application.configure do
config.logger_exclude = ->(path) { path == "/health" }
end
As we're modifying core code of Rails it's always good idea to check original classes in Rails version you're using.
当我们正在修改 Rails 的核心代码时,检查您正在使用的 Rails 版本中的原始类总是一个好主意。
If this looks like too many modifications, you can simply use logragegem which does pretty much the same with few other modifications. Although the Rack::Logggercode has changed since Rails 3, so you might be loosing some functionality.
如果这看起来太多修改,您可以简单地使用logragegem,它几乎没有其他修改。尽管Rack::Loggger自 Rails 3 以来代码已更改,但您可能会丢失一些功能。
回答by Neil Stockbridge
The following works with Rails 2.3.14:
以下适用于 Rails 2.3.14:
Make a custom logger that can be silenced:
制作一个可以静音的自定义记录器:
#selective_logger.rb
require "active_support"
class SelectiveLogger < ActiveSupport::BufferedLogger
attr_accessor :silent
def initialize path_to_log_file
super path_to_log_file
end
def add severity, message = nil, progname = nil, &block
super unless @silent
end
end
Tell Rails to use it:
告诉 Rails 使用它:
#environment.rb
config.logger = SelectiveLogger.new config.log_path
Intercept the log output at the beginning of each action and (re)configure the logger depending on whether the action should be silent or not:
在每个动作开始时截取日志输出,并根据动作是否应该静默来(重新)配置记录器:
#application_controller.rb
# This method is invoked in order to log the lines that begin "Processing..."
# for each new request.
def log_processing
logger.silent = %w"ping time_zone_table".include? params[:action]
super
end
回答by shev.vadim.net
Sprockets-railsgem starting from version 3.1.0introduces implementation of quiet assets. Unfortunately it's not flexible at this moment, but can be extended easy enough.
Sprockets-railsgem 从 version 开始3.1.0引入了quiet assets 的实现。不幸的是,目前它并不灵活,但可以很容易地扩展。
Create config/initializers/custom_quiet_assets.rbfile:
创建config/initializers/custom_quiet_assets.rb文件:
class CustomQuietAssets < ::Sprockets::Rails::QuietAssets
def initialize(app)
super
@assets_regex = %r(\A/{0,2}#{quiet_paths})
end
def quiet_paths
[
::Rails.application.config.assets.prefix, # remove if you don't need to quiet assets
'/ping',
].join('|')
end
end
Add it to middleware in config/application.rb:
将它添加到中间件中config/application.rb:
# NOTE: that config.assets.quiet must be set to false (its default value).
initializer :quiet_assets do |app|
app.middleware.insert_before ::Rails::Rack::Logger, CustomQuietAssets
end
Tested with Rails 4.2
使用 Rails 4.2 测试

