Как я могу отключить вход в Ruby on Rails для каждого отдельного действия? - PullRequest
34 голосов
/ 04 февраля 2010

У меня есть приложение Rails, которое выполняет действие, которое вызывается достаточно часто, чтобы быть неудобным при разработке, так как это приводит к большому количеству дополнительного вывода журнала, который меня не волнует.Как я могу заставить рельсы ничего не регистрировать (контроллер, действие, параметры, время завершения и т. Д.) Только для этого одного действия?Я также хотел бы поставить его в RAILS_ENV, чтобы завершить регистрацию.

Спасибо!

Ответы [ 7 ]

16 голосов
/ 06 февраля 2010

Вы можете отключить объект регистратора Rails:

def action
  Rails.logger.silence do
    # Things within this block will not be logged...
  end
end
9 голосов
/ 07 февраля 2017

Использование lograge самоцвет.

Gemfile:

gem 'lograge'

конфиг / application.rb:

config.lograge.enabled = true
config.lograge.ignore_actions = ['StatusController#nginx', ...]
9 голосов
/ 25 апреля 2012

Следующее работает по крайней мере с Rails 3.1.0:

Создайте собственный регистратор, который можно отключить:

# 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

Скажите Rails использовать его:

# application.rb
config.middleware.swap Rails::Rack::Logger, SelectiveLogger, :silenced => ["/remote/every_minute", %r"^/assets/"]

В приведенном выше примере показано отключение запросов на обслуживание активов, что в среде разработки означает, что для просмотра фактического запроса требуется меньше (а иногда и нет) прокрутка назад.

7 голосов
/ 11 февраля 2010

Ответ оказывается намного сложнее, чем я ожидал, так как рельсы действительно не предоставляют никакой возможности для этого.Вместо этого вам нужно обернуть некоторые элементы 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

, затем в контроллере с методом, который я хочу запретить входить в систему:

def silent?(action)
  RAILS_ENV == "development" && ['my_noisy_action'].include?(action)
end
3 голосов
/ 27 октября 2016

Вы можете добавить камень в Gemfile глушитель .

gem 'silencer', '>= 1.0.1'

И в вашем конфиге / инициализаторах / silencer.rb:

  require 'silencer/logger'

  Rails.application.configure do
    config.middleware.swap Rails::Rack::Logger, Silencer::Logger, silence: ['/api/notifications']
  end
1 голос
/ 22 сентября 2011

Следующее работает с Rails 2.3.14:

Создайте собственный регистратор, который можно отключить:

#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

Скажите Rails использовать его:

#environment.rb
  config.logger = SelectiveLogger.new  config.log_path

Перехватывать вывод журнала в начале каждого действия и (пере) настраивать регистратор в зависимости от того, должно ли действие быть тихим или нет:

#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
0 голосов
/ 29 марта 2019

С 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

Затем выполните 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

Убедитесь, чтозагрузить измененные модули, например, в config/application.rb после загрузки rails:

require_relative '../lib/logger'
require_relative '../lib/silent_log_subscriber'

Окончательно настроить исключенные пути:

Rails.application.configure do
  config.logger_exclude = ->(path) { path == "/health" }
end

Поскольку мы модифицируем основной код Rails, это всегда хорошая идеячтобы проверить исходные классы в используемой вами версии Rails.

Если это выглядит как слишком много модификаций, вы можете просто использовать lograge gem, который делает почти то же самое с несколькими другими модификациями,Хотя код Rack::Loggger изменился со времен Rails 3 , поэтому вы можете потерять некоторые функции.

...