如何在实时输出时将命令的stdout和stderr重定向到控制台和日志文件?

时间:2015-06-23 04:11:16

标签: go io synchronization

下面的代码完全符合我的要求,除了它只打印到控制台。

cmd := exec.Command("php", "randomcommand.php")

cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr

if err := cmd.Run(); err != nil {
    log.Fatal(err)
}

randomcommand.php:

// randomcommand.php simply alternates output between stdout and stderr 20 times

$stdout = fopen('php://stdout', 'w+');
$stderr = fopen('php://stderr', 'w+');
for ($i = 1;$i <= 20; $i++) {
    fwrite($stdout, "stdout $i\n");
    fwrite($stderr, "stderr $i\n");
}

输出:

stdout 1
stderr 1
stdout 2
stderr 2
stdout 3
stderr 3
stdout 4
stderr 4
stdout 5
stderr 5
stdout 6
stderr 6
stdout 7
stderr 7
stdout 8
stderr 8
stdout 9
stderr 9
stdout 10
stderr 10
stdout 11
stderr 11
stdout 12
stderr 12
stdout 13
stderr 13
stdout 14
stderr 14
stdout 15
stderr 15
stdout 16
stderr 16
stdout 17
stderr 17
stdout 18
stderr 18
stdout 19
stderr 19
stdout 20
stderr 20

我想要实现的目标是:

  1. 将命令的stdout和stderr实时打印到控制台;
  2. 将命令的stdout和stderr记录到文件中,与控制台中显示的完全一致;
  3. 尊重写入stdout和stderr的确切顺序,并且;
  4. 不修改命令本身
  5. 我尝试将命令stdout和stderr连接到扫描仪或使用io.Copy,每个都在goroutine中,但输出的顺序没有得到维护。可能因为goroutines之间的交替必须在输出交替的同时发生,这几乎是不可能的。

    我也试过使用&#34;选择&#34;如here中的示例所示。但是没有保持产出的顺序。

    Logstreamer相同的问题。

    我必须尝试的另一个想法是看看我是否能以某种方式从控制台缓冲区中读取,但这感觉不对。

    有谁知道这是否可能并值得追求?

1 个答案:

答案 0 :(得分:8)

正如我在评论部分所说,这可以使用MultiWriter

来实现
    web.allowunsafeupdates = true;
    try
    {
     // Do your update
    }
    catch(Exception ex)
    {
    }
    finally
    {
        web.allowUnsafeUpdates = false;
    }

当您声明命令时,在运行它之前,只需指定Stdout和Stderr正在使用上面定义的MultiWriter。此MultiWriter实例包含日志文件和标准输出。