Replacing Rails Logger with Lograge

Among the biggest problems of the default Rails logger are that it's:

  • too verbose
  • not parsable

which makes it a bad fit for production.

Let's add a Lograge to fight those issues:

gem "lograge"

The configuration below is the one I use in my current project, config/initializers/lograge.rb:

# frozen_string_literal: true

Rails.application.configure do
  config.lograge.enabled = true
  config.lograge.keep_original_rails_log = true
  config.lograge.formatter = Lograge::Formatters::Json.new
  config.lograge.logger = ActiveSupport::Logger.new(STDOUT)
  config.lograge.ignore_actions = [
    'ActiveStorage::DiskController#show',
    'ActiveStorage::BlobsController#show',
    'ActiveStorage::RepresentationsController#show'
  ]
end

Additionaly I silenced the Active Record queries spam, by setting config/environments/production.rb

config.active_record.logger = nil

It works great, but does not allow to use the default Rails.logger.*severity* logger anymore. So I created a custom events logger lib/log.rb:

# frozen_string_literal: true

# Adds logger Log.*level* methods
module Log
  extend self

  %i[debug info warn error fatal unknown].each do |severity|
    define_method severity do |message, params = {}|
      raise ArgumentError, "Hash is expected as 'params'" unless params.is_a?(Hash)
      logger.public_send(severity, {
        m: message
      }.merge(params).to_json)
    end
  end

  private

  def logger
    Lograge.logger
  end
end

Now it's possible to logs events like this:

Log.info "SMS received", from: from, body: body, message_id: message_id

And get a neat parsable output:

{"method":"GET","path":"/","format":"html","controller":"HomeController","action":"index","status":200,"duration":28.47,"view":25.91,"db":0.0}
{"m":"SMS received","from":"+XXXXXXXXXX","body":"Your verification code is: 5752","message_id":19932478}
...

Part 2: Stream Rails Logs to Google Cloud Stackdriver