Golang - 将Exec输出复制到Log

Ric*_*ith 13 go

我想及时重定向流程的输出log.如果我等待这个过程完成,我可以这样做:

cmd := exec.Command("yes", "Go is awesome") // Prints "Go is awesome", forever 
out, err := cmd.CombinedOutput()
log.Printf("%s", out)
Run Code Online (Sandbox Code Playgroud)

但是,如果该过程需要很长时间或者没有完成,则这不太有用.我知道我可以像这样实时写入stdout:

cmd := exec.Command("yes")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Run()
Run Code Online (Sandbox Code Playgroud)

这并不能帮助我,因为我正在编写一个不写入终端的服务.我正在寻找能让我做类似的事情:

cmd := exec.Command("yes")
cmd.Stdout = log.Stdout
cmd.Stderr = log.Stdout
cmd.Run()
Run Code Online (Sandbox Code Playgroud)

log不能直接访问其作者,因此这是不可能的.当然我不是唯一遇到这个问题的人,这通常是怎么做的?

Sir*_*ius 28

你应该在这里使用一个管道,例如:

stdout, err := cmd.StdoutPipe()
if err != nil {
    return 0, err
}

// start the command after having set up the pipe
if err := cmd.Start(); err != nil {
    return 0, err
}

// read command's stdout line by line
in := bufio.NewScanner(stdout)

for in.Scan() {
    log.Printf(in.Text()) // write each line to your log, or anything you need
}
if err := in.Err(); err != nil {
    log.Printf("error: %s", err)
}
Run Code Online (Sandbox Code Playgroud)

Stdout这里只处理过,但可以同时处理Stderr,例如使用goroutine.

  • 几个建议:获取StderrPipe()然后执行`multi:= io.MultiReader(stdout,stderr)`.然后执行`in:= bufio.NewScanner(multi)`.这允许单个扫描仪,没有goroutine,我认为这是非常好的.我认为`scanner.Err()`应该是`in.Err()`.我拿出了`return 0,err`然后让它'返回错误'.很好的回答,谢谢! (5认同)
  • @Arcite 没有理由管道可能会颠倒行的顺序。这意味着正在管道传输的程序会在时间上向后运行,考虑到我们目前对时间旅行技术的了解,这是不太可能的。更严重的是,请针对您的确切可重现问题提出一个新问题。 (2认同)

Elw*_*nar 5

exec.Command和两者都log.Logger基于io.Writer. 您无权访问第二个,但您不需要这样做,因为您没有更改它,并且您正在使用或os.Stderr更改了它,并且io.Writer在创建时您手头有记录器。

\n\n

因此,您只需使用正确的io.Writer\xe2\x80\xa6来调整第二个示例

\n\n

编辑

\n\n

经过一番思考后,我认为您最好将 a 嵌入log.Logger到将实现io.Writer接口 \xe2\x80\xa6 的结构中

\n\n

例子:

\n\n
type LogWriter struct {\n    logger *log.Logger\n}\n\nfunc NewLogWriter(l *log.Logger) *LogWriter {\n    lw := &LogWriter{}\n    lw.logger = l\n    return lw\n}\n\nfunc (lw LogWriter) Write (p []byte) (n int, err error) {\n    lw.logger.Println(p)\n    return len(p), nil\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后将其传递到您的exec.Command输出\xe2\x80\xa6

\n\n
cmd := exec.Command(\xe2\x80\xa6)\ncmd.Stdout = NewLogWriter(log.New(\xe2\x80\xa6))\n
Run Code Online (Sandbox Code Playgroud)\n\n

您可以将它用于标准输出或错误输出,或者为每个输出创建新对象。

\n\n

编辑2

\n\n

由于我将在下一个项目中使用此技巧,因此我将其放入github上的一个包中。请随意提供反馈等。

\n