Indentation in Rails logs

Viewed 252

When logging custom information, e.g. in a rake-task, I'd like to indent the log lines for better readability. For example:

Seeding database...
  Importing xyz.csv...
    Skipping row 5 due to invalid value 'Unknown' in column 'year'
  Finished importing xyz.csv
Finished seeding database

In my seeds.rb, I use the following for logging:

logger = Logger.new(STDOUT)
logger.info('Seeding database...')

However, the logging of Skipping row 5... takes place in a service, which does not necessarily have to be called from the seeds.rb, but could be called from anywhere. Thus I can not hardcode the correct indentation (which sounds like a bad idea, anyway).

One possibility would be to keep an "indentation counter", which I could increase when starting to import a file and decrease when finishing. I'm unsure though how to access this from anywhere in my application, or if this is the best solution. Any ideas?

1 Answers

Better solution is to provide your service object with a logger object along with data to process. This way it does not have to know anything about your logger preferences.

And use something like:

require 'logger'

class IndentedLogger < Logger

  INDENTATION_STR = '  '.freeze
  attr_accessor :indentation

  def initialize(io, *args, **params)
    self.indentation = 0
    super
  end

  def indented
    return self.dup.tap{|l| l.indentation += 1 } unless block_given?
    self.indentation += 1
    yield self
    self.indentation -= 1
  end

  protected

  def format_message(severity, datetime, progname, msg)
    (@formatter || @default_formatter).call(severity, datetime, progname, "#{INDENTATION_STR*indentation}#{msg}")
  end

end

# Example:
logger = IndentedLogger.new(STDOUT)

logger.info "Foo"
logger.indented{
  logger.info "Foo"
  logger.indented.info "Indented even more"
}
logger.info "Foo"

And for service call - YourService.new(some_data, logger: logger.indented).process_or_whatever

Related