Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I do split logging in rails? (certain levels to stdout, and certain levels to stderr)

I want to be able to specify something like this in my config files with my rails logs:

logger(STDOUT).level = [:debug, :info, :warn]
logger(STDERR).level = [:error, :fatal]

so that my unicorn_app_server_stdout.log and unicorn_app_server_stderr.log are populated with the right kind of information ( Diagnostics in stdout and Errors in stderr ) I believe this is a pretty long standing model in Unix

but all the rails guides I seem to have found talk about defining a logger as logger.new(STDOUT) or logger.new(STDERR) but not together

Most webservers have this context of stderr and stdout but it seems rails only has a concept of stdout or stderr but not together is this correct? Do I need to use another logging gem to get this functionality? Or can I do this with standard rails? If so how?

like image 760
Jesse Whitham Avatar asked Oct 19 '22 23:10

Jesse Whitham


1 Answers

A few months ago I was researching this topic with the same goal. Now I went to investigate again, and I concluded that I taken right desicion.

I use the yell-rails gem, which is a wrapper of gem yell.

It is very easy to install and does the job:

  1. Add gem 'yell-rails' to Gemfile
  2. Run: rails generate yell: install
  3. Set your configuration at the file config/yell.yml

for production:

production:
  :adapters:
    - :file:
        :level: 'lte.warn'
        :filename: 'log/warn.log'
    - :file:
        :level: 'gte.error'
        :filename: 'log/error.log'

Also, it has several cool options.

Edit: that is the result of my research:

Rails 3.2

Since Rails use Rails.logger to log its information, it provides a setter for use other logger at its place. At Rails 3.2 the logger is a class instance variable @@logger, then only one logger is permited at the application.

At application bootstrap the logger is setted with an instance of ActiveSupport::TaggedLogging, which is a wrapper of ActiveSupport::BufferedLogger, and the last one uses ruby Logger of std-lib.

For send the log to console it uses a middleware: Rails::Rack::LogTailer

At this point you can get your achievement opening any of these classes (TaggedLogging, BufferedLogger, Logger) and writing some code to makes it works like you want, or you can replace the logger with the tools that Rails provide.

Rails 4

The BufferedLogger is no more used, and instead of Logger Rails use ActiveSupport::Logger < Logger. It includes a class method broadcast, that allow multiply the loggers. Also this method is used for send the log to the console.

I played around with these settings and I put in an initializer, I leave this as starting point for letting you get your goal:

warn = ActiveSupport::Logger.new('log/logfilewarn.log')
warn.level = Logger::DEBUG
Rails.logger.extend(ActiveSupport::Logger.broadcast(warn))

error = ActiveSupport::Logger.new('log/logfileerror.log')
error.level = Logger::ERROR
Rails.logger.extend(ActiveSupport::Logger.broadcast(error))
like image 93
Alejandro Babio Avatar answered Oct 23 '22 06:10

Alejandro Babio