I have a Logger instance:
require 'logger'
logger = Logger.new( 'foo.log', 'weekly' )
I want to redirect runtime errors (stderr output) into the log as well. I found this forum thread which has the advice:
new_fd = logger.get_logger_file_descriptor
$stderr.reopen new_fd
However, Logger does not have an instance method get_logger_file_descriptor, nor can I find any exposed methods around gaining access to the log device or file.
How can I cause all $stderr output to go into the log?
If you’re creating the logger yourself, you can create the
Fileobject first, then use it to create the logger and assign it to$stderr:Note that this will result in the log output being mixed up with the output of
$stderr, which may cause problems if you’re parsing the log file expecting it to be in a certain format (this will happen with your solution too).If you don’t have the underlying file but just receive the
loggerfrom somewhere else, it’s a bit more tricky. What is needed is anIOlike object that can be assigned to$stderrand passes anything written to it to the logger. TheIOclass in Ruby is unfortunately fairly closely tied to the underlying i/o system (file descriptors and the like), and there’s no general interface that can be used to create input and output streams. (StringIObeing the notable exception).However most, if not all, of the output methods on
IOultimately go through#write, so by overriding this one method you can get close to what you’re after:Now anything written to
$stderrwill end up going to the log file. The formatting however will be a bit odd. Anytime any of the writing methods calls#writea new entry will be made in the logfile. For example,#putscalled with an array will call#writefor each entry of the array, and again with a newline character between each entry, resulting in 2n – 1 log entries, n – 1 of which will be blank.You could make the overridden
#writemethod more complex to handle this, perhaps using an internal buffer, and only call the logger when you think you have a full message. Alternatively you could override the individual methods to write to the logger themselves. If you did this theIOToLogclass wouldn’t necessarily have to inherit fromIO.Your best solution will depend on how you want to standard error output to appear in the logfile, how your program uses
$stderr, and how much work you want to do implementing methods fromIO.