将stderr重定向到Logger实例

Phr*_*ogz 9 ruby stderr

我有一个Logger实例:

require 'logger'
logger = Logger.new( 'foo.log', 'weekly' )
Run Code Online (Sandbox Code Playgroud)

我想将运行时错误(stderr输出)重定向到日志中.我发现这个论坛帖子有以下建议:

new_fd = logger.get_logger_file_descriptor
$stderr.reopen new_fd
Run Code Online (Sandbox Code Playgroud)

但是,Logger没有实例方法get_logger_file_descriptor,也无法找到任何公开的方法来获取对日志设备或文件的访问权限.

如何让所有$ stderr输出进入日志?

mat*_*att 17

如果您自己创建记录器,则可以先创建File对象,然后使用它创建记录器并将其分配给$stderr:

log_file = File.new('foo.log', 'a')
logger = Logger.new(log_file, 'weekly')
$stderr = log_file   #usually no need to use reopen
Run Code Online (Sandbox Code Playgroud)

请注意,这将导致日志输出混合了的输出$stderr,如果你输入的日志文件,期待它在一定的格式(这将与您的解决方案发生太大),这可能会导致问题.

如果您没有底层文件但只是logger从其他地方接收,那就有点棘手了.所需要的是一个IO类似的对象,可以将其分配给$stderr并将写入其中的任何内容传递给记录器.IO遗憾的是,Ruby中的类与底层的i/o系统(文件描述符等)密切相关,并且没有可用于创建输入和输出流的通用接口.(StringIO是值得注意的例外).

然而,大多数(如果不是全部)输出方法IO最终会通过#write,所以通过覆盖这一种方法,您可以接近您所追求的内容:

class IOToLog < IO

  def initialize(logger)
    @logger = logger
  end

  def write(string)
    #assume anything written to stderr is an error
    @logger.error(message)
  end

end

logger = get_logger_from_somewhere

$stderr = IOToLog.new(logger)
Run Code Online (Sandbox Code Playgroud)

现在写入的任何内容$stderr最终都会转到日志文件中.然而格式化将有点奇怪.任何时候任何写入方法#write都会在日志文件中调用新条目.例如,#puts使用数组调用将调用数组#write的每个条目,并在每个条目之间再次使用换行符,从而产生2n - 1个日志条目,其中n - 1将为空.

您可以使重写#write方法更复杂,可能使用内部缓冲区,并且只在您认为有完整消息时才调用记录器.或者,您可以覆盖各个方法以自行写入记录器.如果你这样做,那么这个IOToLog课不一定要继承IO.

您最好的解决方案将取决于您希望标准错误输出显示在日志文件中,程序如何使用$stderr以及您希望从中实现方法的工作量IO.