如何在每个操作的基础上禁用 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 22:14:43  来源:igfitidea点击:

How can I disable logging in Ruby on Rails on a per-action basis?

ruby-on-railsloggingconditionalaction

提问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

Use logragegem.

使用lograge宝石。

Gemfile:

宝石档案:

gem 'lograge'

config/application.rb:

配置/应用程序.rb:

config.lograge.enabled = true
config.lograge.ignore_actions = ['StatusController#nginx', ...]

回答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_appLogger类中覆盖,让我们调用这个文件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 测试