Logging to multiple destinations using ActiveSupport 4+
Logging to multiple destinations is something I seem to have to do all the time, and until now,
I’ve never really been able to find an approach I’m happy with. Almost always, I’m writing some kind
of developer-script, and I want to write messages to both the terminal (to let the dev know what is
going on), and to a log file (for future reference/audit). I don’t normally want to use
Rails.logger for this - I prefer to have a brand new logger specifically for my output. Having
said that, I have verified that the approach described in this post does work with a standard Rails
logger (defined in
config.logger depending on where you’re trying to work with
This approach relies on a method added to ActiveSupport version ~> 4.0. Versions of ActiveSupport map directly to Rails versions (ActiveSupport is part of the
rails/railsrepository after all), so Rails 4+ will also work here.
When working with logging in Ruby, the
Logger class is normally the
one is used. This is completely reasonable, as it’s part of the standard library, and is almost
always sufficient. For those scenarios where something more is needed,
available. The API for ActiveSupport’s Logger is broadly the same as Ruby’s Logger, with a few
bonuses, such as tagged
the ability to extend loggers with other loggers!
Extending any logger is possible using the
broadcast method available on
ActiveSupport::Logger. Unfortunately, I can’t link to documentation for either of these methods,
as they don’t seem to be documented.
Here’s an example not using any Rails stuff, just ActiveSupport, as an example:
require "active_support/logger" console_logger = ActiveSupport::Logger.new(STDOUT) file_logger = ActiveSupport::Logger.new("my_log.log") combined_logger = console_logger.extend(ActiveSupport::Logger.broadcast(file_logger)) combined_logger.debug "Debug level" combined_logger.info "Info level" combined_logger.error "Error level"
With the console output being:
Debug level Info level Error level
# Logfile created on 2018-08-16 15:24:10 +1200 by logger.rb/61378 Debug level Info level Error level
Usage in Rails really isn’t that different, the only difference is that you will already have a
logger set up to log somewhere defined in
config.logger if you are modifying
a config file). You can just go ahead and extend that logger to add another logging destination:
# NOTE: The actual config file doesn't really matter here. # config/application.rb extra_logger = ActiveSupport::Logger.new("extra.log") config.logger.extend(ActiveSupport::Logger.broadcast(extra_logger))
Multiple logging is a handy trick to keep in mind, as there’s a few places it can come in handy. As mentioned at the start of this post, my usual use case is to log to a file and STDOUT at the same time, but there’s all sorts of times you might want to post a log message multiple places. Maybe you want logs to go to a third party service, as well as local log file, as well as STDOUT for good measure? Sure!