This howto shows how to modify some of the defaults in rails’ logging configuration. For background about what the logger is and how to use it, see logger.
You can control some aspects of the logger through the config object in config/environment.rb for a change in all environments
Log Level
The available log levels are: :debug, :info, :warn, :error, :fatal. The ruby Logger class normally also accepts :any, but that doesn’t seem to work with rails.
config.log_level = :debug
Log Path
The log file path is relative to the RAILS_ROOT directory. Make sure that the file exists and has permissions that allow writing for the user that rails will run under.
config.log_path = 'log/debug.log'
Setting config.log_level in a per environment file (such a development.rb) appears to no longer work. the solution appears to be:
RAILS_DEFAULT_LOGGER.level = Logger::INFO if defined? RAILS_DEFAULT_LOGGER
The rest of this document is if you want more fine-level control over the logger or want to use something other than the default Logger object.
This does not seem to happen in environment.rb as stated.
environment.rb defines the loggers used by the components of rails. First it defines the default logger for the application :
begin
RAILS_DEFAULT_LOGGER = Logger.new("#{RAILS_ROOT}/log/#{RAILS_ENV}.log")
rescue StandardError
RAILS_DEFAULT_LOGGER = Logger.new(STDERR)
RAILS_DEFAULT_LOGGER.level = Logger::WARN
RAILS_DEFAULT_LOGGER.warn(
"Rails Error: Unable to access log file. Please ensure that log/#{RAILS_ENV}.log exists and is chmod 0666. " +
"The log level has been raised to WARN and the output directed to STDERR until the problem is fixed."
)
end
Then it assigns this logger to its friends :
[ActiveRecord, ActionController, ActionMailer].each { |mod| mod::Base.logger ||= RAILS_DEFAULT_LOGGER }
Say you want Active record to log in database.log instead of the default #{RAILS_ENV}.log file. You can add the following to the end of your #{RAILS_ROOT}/config/#{RAILS_ENV}.rb file (for example to developement.rb):
ActiveRecord::Base.logger = Logger.new("#{RAILS_ROOT}/log/#{RAILS_ENV}_database.log")
Say you want Active record to only log warnings when your application is running in production mode. You can add the following to the end of your #{RAILS_ROOT}/config/production.rb file:
config.log_level = :warn
The above method is for
Removing the colour escape sequences that are used by default is quite simple. Simply set colorize_logging to false:
ActiveRecord::Base.colorize_logging = false
Note that the colorize_logging method doesn’t appear in ActionController (why?[because the only module in rails that adds color to the logs is ActiveRecord -jean]).
As said in the logger.rb source file:
> There is currently no supported way to change the overall format, but you may
> have some luck hacking the Format constant.
This, when added to the end of environment.rb, puts the timestamp and PID in the log.
class Logger
def format_message(severity, timestamp, progname, msg)
"#{timestamp} (#{$$}) #{msg}\n"
end
end
(Note that the Rails 2.0 default logger has been changed from Ruby’s own logger with the clean_logger extensions described below to ActiveSupport::BufferedLogger. From the CHANGELOG: “You can change it back with config.logger = Logger.new(”/path/to/log”, level)”. Rails::Initializer.initialize_logger() documentation also indicates you can set RAILS_DEFAULT_LOGGER.)
Look at the source to what Rails 1.2 does to mung the standard Logger object to do what it wants. Can you see anything wrong with this picture? If Rails wants a Logger object that behaves this way, it should subclass Logger, or inject its own Logger::Formatter into the picture rather than this mess.
What this accomplishes is utterly evil. If you’re adding things to a rails app that expect Logger to behave as documented, you’ll configure your logging date formats all day long and never have any impact. Worse, the code is flagged :nodoc:, so after screwing around with expected behavior, we’re left with no indication as to why a Logger instance created from the Rails console will behave different than a Logger created from IRB.
Mixins are a great feature of Ruby, but a mixin that irrevocably alters a core library class just to avoid the minor pain of creating a proper subclass where it it obviously necessary is just plain wrong, no matter how $!#^$% pragmatic you’re claiming to be.
This code added to environment.rb will restore the default logger behavior under 1.8.4, Rails 1.2:
class Logger def format_message(severity, timestamp, progname, msg) if <a href="mailto:!@formatter.nil">!@formatter.nil</a>? @formatter.call(severity, timestamp, progname, msg) else @default_formatter.call(severity, timestamp, progname, msg) end end end class RailsFormatter < Logger::Formatter def call(severity, timestamp, progname, msg) "#{msg}\n" end end RAILS_DEFAULT_LOGGER.formatter = RailsFormatter.new
If you need something similar to log4j , then you should take a look at the log4r project It allows more advanced logging than the standard logger.
However, log4r doesn’t work with the current version of Rails because of incompatibilities between the benchmarking module and log4r. See ticket 3512 for more information.
As of 2/20/07, log4r has been idle for several years. It looks like no-one has been able to contact the original developer for some time, and a replacement project, http://logging.rubyforge.org has been created that solves the above mentioned problem.
I ran into problems with logging on Apache 2 with Fcgi resulting in a “could not access {RAILS_ENV}/log/development.log” message in the Apache Error log and suggesting I made sure the log file existed and was chmodded 0666. Changine permissions on the files had no effect but setting a 777 permission on the /log directory fixed it.
Thank you for these useful informations. However I’d like to know if it’s possible to display the logs in the console rather than using the ”debug.log” file .
The ActiveRecord #format_log_entry method looks like this:
def format_log_entry(message, dump = nil)
if ActiveRecord::Base.colorize_logging
if @@row_even
@@row_even = false
message_color, dump_color = "4;36;1", "0;1"
else
@@row_even = true
message_color, dump_color = "4;35;1", "0"
end
log_entry = " \e[#{message_color}m#{message}\e[0m "
log_entry << "\e[#{dump_color}m%#{String === dump ? 's' : 'p'}\e[0m" % dump if dump
log_entry
else
"%s %s" % [message, dump]
end
end
it’s actually found in active_record/connection_adapters/abstract_adapter.rb
Question: I am running Rails 1.2.3 with Mongrel and Ruby 1.8.6 on Windows. No matter what I set the value of log_level in environment.rb or environments/development.rb, my logfile always contains the same output. How do I begin to track down why its doing so?
Answer: config.log_level = :info will not work if you are setting config.logger. In that case, you will want to set config.logger.log_level = (Logger::INFO or whatever). I have also seen cases where ./script/server will setup one logger and RAILS_DEFAULT_LOGGER will not get reset. You can assert this by keeping a global reference to the logger you setup in environment.rb, and later on doing a `throw “Lame” unless $my_logger == RAILS_DEFAULT_LOGGER`
Pretty logs for rails 1.2.x and 2.0
I use for creating pretty logggs on rails
next patches
config/environment.rb
require 'logger_core_ext'
file app/lib/logger_core_ext.rb
class Logger
# Used for rails 1.2.x
alias format_message old_format_message
class Formatter
def call(severity, time, progname, msg)
"[%s|#%5d|%s] %s: %s\n" % [severity[0..3], $$, time.to_s(:db), progname, msg2str(msg)]
end
end
end
module ActiveSupport
# Used for rails 2.0
class BufferedLogger
module Severity
def level_to_s(level)
case level
when 0
'DEBUG'
when 1
'INFO'
when 2
'WARN'
when 3
'ERROR'
when 4
'FATAL'
when 5
'UNKNOWN'
end
end
end
def add(severity, message = nil, progname = nil, &block)
return if @level > severity
# message = (message || (block && block.call) || progname).to_s
message = (message || (block && block.call) || progname).to_s
# If a newline is necessary then create a new message ending with a newline.
# Ensures that the original message is not mutated.
message = "#{message}\n" unless message[-1] == ?\n
message = "[%s|#%5d|%s] %s: %s" % [level_to_s(severity)[0..3], $$, Time.now.to_s(:db), progname, message]
@buffer << message
auto_flush
message
end
end
end