<p>Hi all,</p>
<p>I'm finding it a bit tricky to accomplish the objective of logging stdout+stderr to a file, for a long running child process started by cmd.Start().</p>
<p>All of the examples on the net focus on short-lived processes which can be expected to complete inside the example code block. My child process is a long-running server, and I need to continuously write the stdout to a log file while returning quickly in the outer block.</p>
<p>How would you do it?</p>
<hr/>**评论:**<br/><br/>TheMerovius: <pre><p>You can just open the logfile and set the Stdout/Stderr of the <a href="https://godoc.org/os/exec#Cmd">exec.Cmd</a> to this file. No need to do any Copying or piping.</p></pre>ejayben: <pre><p>Thanks to all who posted here. This was the solution I went for, it looks like this:</p>
<pre><code>cmd := exec.Command(
// program name and args here
)
// setup log file
file, err := os.Create("server.log")
if err != nil {
return err
}
cmd.Stdout = file
err = cmd.Start()
if err != nil {
return err
}
</code></pre>
<p>As mentioned above, the *File returned by os.Create() satisfies the io.Writer interface! It fits nicely as the writer for cmd.Stdout.</p></pre>karnd01: <pre><p>Here is another example on usage I usually create a wrapper function like so <a href="https://github.com/go-playground/generate/blob/master/misc.go#L12" rel="nofollow">https://github.com/go-playground/generate/blob/master/misc.go#L12</a> granted this example is just to the console but could be written anywhere</p></pre>mc_hammerd: <pre><p>the other posts dealt with logging so for the execution i would put it in a go routine</p>
<p><code>go cmd.Start()</code></p>
<p>if that doesnt work... use a function</p>
<pre><code>go func () {
cmd.start()
// log
}
fmt.Println("app continues")..
</code></pre>
<p>at least it will not block.</p>
<p>logging... from <a href="http://stackoverflow.com/questions/18986943/in-golang-how-can-i-write-the-stdout-of-an-exec-cmd-to-a-file" rel="nofollow">http://stackoverflow.com/questions/18986943/in-golang-how-can-i-write-the-stdout-of-an-exec-cmd-to-a-file</a></p>
<pre><code>go func () {
cmd := exec.Command(...)
outfile, err := os.Create("./out.txt")
if err != nil {
panic(err)
}
defer outfile.Close()
cmd.Stdout = outfile
cmd.Stderr = outfile
err = cmd.Start(); if err != nil {
panic(err)
}
cmd.Wait()
}
</code></pre>
<p>havent tested this =O. hopefully it helps</p></pre>SportingSnow21: <pre><p>You can grab pipes to stdout and stderr using <a href="https://golang.org/pkg/os/exec/#example_Cmd_StdoutPipe" rel="nofollow">os/exec</a>, then spawn off goroutines to redirect to a log file using <a href="https://golang.org/pkg/io/#Copy" rel="nofollow">Copy</a>. </p>
<p>Best design would be to set up the logging within that long-running process, so there's no need to double-handle the data stream.</p></pre>ejayben: <pre><p>Great advice, thank you.</p></pre>bmurphy1976: <pre><p>You're probably looking for Command.StdoutPipe() and StderrPipe(). You can spawn goroutines that read the output in the background and redirect it however you like or map those to files on the file system.</p>
<p>We have a similar problem where we spawn very long running processes (upwards of six hours) and we want to capture the output (very verbose, sometimes 10's of thousands of lines). We use this to capture the last 1,000 lines of output into a ring buffer and save the trace in our data store once the process exits.</p>
<p>Please be aware, if you call Command.Wait() this will sometimes exit before the the pipes are closed. You should wait for your goroutines to exit cleanly before continuing. If you don't do this, you could end up missing the last few lines of output or even worse introduce a race condition. </p>
<p>Here's some quick pseudo-code as an example, not expected to compile and please add appropriate error handling:</p>
<pre><code>stdoutDone := make(chan interface{})
stderrDone := make(chan interface{})
cmd := exec.Command(params)
stdout, _ := cmd.StdoutPipe()
stderr, _ := cmd.StderrPipe()
go func() {
// do something with stdout
close(stdoutDone)
}
go func() {
// do something with stderr
close(stderrDone)
}
cmd.Wait()
<-stdoutDone
<-stderrDone
// everything else
</code></pre></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传