custom logger in rails4?

2019-05-21 14:50发布

It looks like Rails4's logger, unlike Rails3's, finally supports a custom formatter, like the ruby stdlib logger again.

Rails.logger.formatter  # => #<ActiveSupport::Logger::SimpleFormatter:0x007ff81757d890 @datetime_format=nil>
Rails.logger.formatter = SomeFormatterClass

However, when I try to give it a formatter class that would be sufficient for stdlib Logger formatter:

[2014-03-12 16:23:27] ERROR NoMethodError: undefined method `tagged' for #<FormattedRailsLoggerFormatter:0x007fd816545ad8>
/Users/jrochkind/.gem/ruby/1.9.3/gems/activesupport-4.0.3/lib/active_support/tagged_logging.rb:67:in `tagged'
/Users/jrochkind/.gem/ruby/1.9.3/gems/railties-4.0.3/lib/rails/rack/logger.rb:20:in `call'

Does anyone know, is a custom formatter actually a supported feature of Rails4? And is how you are meant to do it documented anywhere?

2条回答
地球回转人心会变
2楼-- · 2019-05-21 15:02

Answering my own question, I've figured it out.

Rails4 provides a config variable, config.log_formatter. You would probably set it in your config/application.rb, along with other application config.

You should set it to an object implementing the stdlib Logger Formatter interface: Basically, you have to provide a method call(severity, time, progname, msg) that returns the formatted log line.

Note you set it to an object, NOT the class name, eg:

config.log_formatter = MyFormatter.new

You should not try to set Rails.logger.formatter directly -- Rails expects you to set it via config, and does some tricky stuff to make your formatter and logger work properly with Rails when you use the config. You can see that, as well as see that indeed config.log_formatter is used, in Rails source code here. (Thanks to github and it's awesome code search and display ui, is how I tracked this down and figured out the existence of config.log_formatter)

In Rails4, you should not need to monkey-patch any parts of Rails just to use a custom log formatter, just use config.log_formatter instead. (In Rails3 you did need to monkey-patch one or another to get custom log formatting).

查看更多
放我归山
3楼-- · 2019-05-21 15:25

In case it helps anyone else, in Rails 4.2.6 and Ruby 2.3.0, this is what worked for me:

# config/application.rb
module MyRailsApp
  class Application < Rails::Application
    require 'my_log_formatter'
    ...
    # Custom log formatter that uses JSON
    config.log_formatter = MyLogFormatter.new
  end
end

To make this happen:

# lib/my_log_formatter.rb
class MyLogFormatter < ActiveSupport::Logger::SimpleFormatter
  def call(severity, timestamp, progname, message)
    if message.present? && message.exclude?('Started GET "/assets')
      {
          app: Rails.application.class.parent_name,
          process_id: Process.pid,
          level: severity,
          time: timestamp,
          progname: progname,
          message: message
      }.to_json + "\r\n"
    else
      ''
    end
  end
end

Some notes:

  • The if statement prevents log entries with no message, and log messages that log the serving of asset files.
  • The + "\r\n" adds a CR+LF to the end of the line, so it remains somewhat human-readable in the rails server console.
  • I added app because I am sharing a single log file among many apps. You could delete this in a system that uses just one Rails app.
  • I find process_id comes in handy when you are reviewing logs on a busy server.
查看更多
登录 后发表回答