Capturing output written to STDOUT (standard output) can be accomplished with the following code.
import (
"bytes"
"io"
"os"
)
// not thread safe
func captureStdout(f func()) string {
old := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w
f()
w.Close()
os.Stdout = old
var buf bytes.Buffer
io.Copy(&buf, r)
return buf.String()
}
The code here is fairly straight forward. First, a reference to the Writer
that’s assigned to os.Stdout
is stashed for later. Next a Pipe is created,
which provides a connected pair of Files. The writer created by the Pipe is
assigned to os.Stdout
. Perhaps you can see where this is going.
Next, we invoke the function provided to captureStdout
. The writer is closed
and os.Stdout
gets the original Writer
assigned back to it.
The final steps are to copy the data from the reader, created from the Pipe, and return the string as the result.
You should note, this code is not thread safe. Why? Because of that
global reference, os.Stdout
.
An example using it would look something like this:
func doSomething() {
fmt.Println("This goes to STDOUT")
}
func example() {
// invoke doSomething and return whatever it writes to STDOUT
message := captureStdout(doSomething)
}
The example shown is trivial. I had a use case where I had to execute an executable on the system that wrote data to STDOUT which I needed to process.