开发者

How can I log STDOUT and STDERR to a single file and show only STDERR in the console using Ruby?

I can do something like this in bash:

myCommand arg1 arg2 2>&1 >> myLogFolder/myLogFile.log | tee -a my开发者_如何学JAVALogFolder/myLogFile.log

I would like to be able to say this instead:

log.rb myLogFolder/myLogFile.log myCommand arg1 arg2

Using the log.rb script would accomplish two things:

  1. Result in a simpler statement with less redirection tricks and only a single specification of the log file.
  2. Create the log folder, if necessary.

I was looking at Ruby's popen and spawn options, but I don't see a way to split the STDERR stream to two destinations.


This Ruby script satisfies my needs, but maybe there is a better way.

logPath = ARGV[0]
logFolder = File.dirname(logPath)
command = ARGV.slice(1..-1).join(" ")
`mkdir -p #{logFolder}`
exec "#{command} 2>&1 >> #{logPath} | tee -a #{logPath}"


Try this article about implementing functionality similar to tee using Ruby. You should be able to use that as a starting point for a pure-ruby (or at least exec-free) implementation of your shell code.


You can use Open3 module (manual) It returns 3 objects: stdin, stdout, stderr

However, you are not able to preserve the order between stdout and stderr.

Example:

#include <stdio.h>

int main(int argc, char *argv[]) {
  fprintf(stdout, "Normal output\n");
  fprintf(stderr, "Error output\n");
  fprintf(stdout, "Normal output\n");
}

It is captured as:

Normal output
Normal output
Error output

The only way how to preserve order is to run program twice. :-(

Sample ruby code:

#!/usr/bin/env ruby

require 'open3'
require 'pathname'

logfile = ARGV.first()
cmd = ARGV.drop(1).join(" ")

dir = Pathname(logfile).dirname

if not File.directory?(dir)
    Dir.mkdir(dir)
end 

file = File.open(logfile, "w")
stdin, stdout, stderr = Open3.popen3(cmd)
stdin.close()

file.puts(stdout.read())
error = stderr.read()
file.puts(error)
puts error

file.close
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜