# rails' logging setup is one of it's weakest points: it's troublesome to # configure, doesn't automatically roll log files, and isn't multi # process/thread safe. the rolling is particularly troublesome since the logs # also grow without bound, that is until disk is full and your server crashes. # # recently i wanted to setup rails to use tim pease's excellent logging.rb gem # and found that rails 2.1 has made configuring a *better* logger that much # harder. # # the following will accomplish the task, along with explaintion, and would # work with other non-standard loggers in addition to tim's library. # # # first off note that we're doing this in RAILS_ROOT/environment.rb and *not* # in config/initializers/*. this is because the initializer code does two # things that rule out using an intiializer: # # . it sets up the log file and initializes it with a logline *before* the # initializers are run # # . it relays the logger to a bunch of classes like ActiveRecord::Base which # then keep their own private copy of the logger # # all this happens *before* the initializers meaning setting up logging there # is too little too late # Rails::Initializer.run do |config| # the first thing you'll need to do is install your alternate logger. in my # case it's tim's lib so i did # # GEM_HOME=vendor GEM_PATH=vendor gem install logging # # which is the bash command to set two environment variables and install the # gem into RAILS_ROOT/gems/logging-VERSION/. the rest of the instructions # assume a local install of a gem or plugin, but will also work for a # system-wide gem install. make sure all of the following code is at the # very *end* of the config initializer block! # # we need to pull in our logging gem and it's supporting gem (lockfile). # there are two approaches we can take to do this, you only need to use one. # both of them are for picking a RAILS_ROOT/vendor/gems or # RAILS_ROOT/vendor/plugins install - if you have a system-wide install you # can skip this step # # method 1 # # we can use the rails initializer hooks, except we have to monkey-patch in # Symbol#to_proc because it's not *ready* yet and the gem loading methods # are defined in terms of it - aka they will actually blow up if you try to # use them here as they're half-baked. # begin Symbol.method(:to_proc) rescue Object class Symbol; def to_proc() lambda{|object| object.send to_s} end end end config.gem 'logging' config.gem 'lockfile' Rails::Initializer.run(:add_gem_load_paths, config) Rails::Initializer.run(:load_gems, config) # method 2 # # the roll your own approach is actually pretty simple, just get ruby to # look in the vendor and gem dirs in case Logging is installed locally # before the require # vendor_glob = File.join(RAILS_ROOT, 'vendor', 'plugins', 'logging*') gem_glob = File.join(RAILS_ROOT, 'vendor', 'gems', 'logging*') libs = ( Dir.glob(vendor_glob) + Dir.glob(gem_glob) ) libs.each{|lib| $LOAD_PATH.unshift File.join(lib, 'lib')} begin require 'logging' require 'lockfile' ensure libs.size.times{ $LOAD_PATH.shift } end # so... now that we've abused rails a little to make sure our alternate # logger is loaded it's simple to configure a new one. note that, because # we are doing this in the config block rails will relay it all over kingdom # come for us *after* this setup had occured, something we'd have to do by # hand in an initializer, and that this will short circuit rails setting up # it's own default logger and intializing a log and writing a line or two to # it before we'd get a chance to override it. # logpath = config.log_path number_of_log_files = 7 megabytes = 2 ** 20 max_size = 42 * megabytes options = { :safe => true } # for multi-process safe rolling logger = ::Logging.logger( logpath, number_of_log_files, max_size, options ) config.logger = logger # eh viola! the above setup will ensure that my logs auto-roll, even in the # with multiple mongrels, and that i never have more than 7 logs of not more # that 42 megabytes littering my log directory - for a total of no more that # about 1/4 gb of logs at maximum - with zero admin work done by anyone. end