Rails Logging Cheatcode

23 Dec 2012

Rails' logging has annoyed me for a very long time. Since I am not around to monitor GIVE anymore, I've decided that I'm gonna make logging more comprehensible, so that I can diagnose what has been going on within GIVE.

What I have done are:

  • Logging each day with a separate file
  • Add colors into it.
  • Stop logging the requests about assets (It's just annoying)

It's somewhat tricky to do these things… and surprisingly Rails doesn't seem to have a good way of dealing with it.

I've decided to use Log4r. It's like the only good logging library for Ruby, but its documentation is kind of hollow.

After guessing a lot of stuffs, I succeed at making it work.

First of all, please include it in your Gemfile:

gem 'log4r'

Now you have to write your configuration file and the initialization file. Here is my configuration file:

log4r: # define all loggers ... loggers: - name: production level: INFO trace: 'true' outputters: - datefile - name: staging level: INFO trace: 'true' outputters: - datefile - name: development level: DEBUG trace: 'true' outputters: - datefile # define all outputters (incl. formatters) outputters: - type: DateFileOutputter name: datefile dirname: "log" file: "my_log" # this will be overrided by rails' config. formatter: type: TaninFormatter

The content is self-explanatory, so I'm not gonna explain anything.

Now what we need to do next is to load the configuration YAML into Log4r. We can do it with:

require 'log4r' require 'log4r/yamlconfigurator' require 'log4r/outputter/datefileoutputter' # Initialize Log4r log4r_yaml = YAML.load_file(File.join(Rails.root, "config", "log4r.yml")) Log4r::YamlConfigurator.decode_yaml(log4r_yaml['log4r']) Rails.logger = Log4r::Logger[Rails.env]

For the colored logs, it seems there is no good way to do it. So, I decided to write my own formatter:

class Log4r::TaninFormatter < Log4r::Formatter def format(event) color = "\033[0m" case event.level when 1 color = "\033[0m" # No Color when 2 color = "\033[0;32m" # Green when 3 color = "\033[0;33m" # Yellow when 4 color = "\033[0;31m" # Red when 5 color = "\033[0;31m" # Red else color = "\033[0m" end unimportant_color = "\033[0;34m" buff = "\033[0m" buff += "#{unimportant_color}#{Time.now.strftime "%d-%b-%Y"}" buff += " #{color}#{Log4r::LNAMES[event.level]}" buff += "\033[0m" buff += ":" buff += " #{event.data.strip}" buff += " #{unimportant_color}(#{event.tracer[0]})\n" buff += "\033[0m" end end

This formatter will colorize the log very nicely :)

Now we need to quiet the logs about assets and RoutingError. On production, the assets' logs are already hidden, and we want the RoutingError's logs to be visible. Therefore, we only quiet them in the development environment. Here is the code:

if Rails.env.development? # This is to prevent logging for 404 class ActionDispatch::DebugExceptions alias_method :old_log_error, :log_error def log_error(env, wrapper) if wrapper.exception.is_a? ActionController::RoutingError return else old_log_error env, wrapper end end end # This is to prevent logging all the requests for assets Rails.application.assets.logger = Logger.new('/dev/null') Rails::Rack::Logger.class_eval do def call_with_quiet_assets(env) previous_level = Rails.logger.level Rails.logger.level = Logger::ERROR if env['PATH_INFO'] =~ %r{^/assets/} call_without_quiet_assets(env) ensure Rails.logger.level = previous_level end alias_method_chain :call, :quiet_assets end end

Have fun logging on Rails!

(The code comes from several threads that I don't remember anymore; I'm sorry I cannot cite them.)