7

How would a process read its own output stream? I am writing automated tests which start a few application sub-processes (applications) in the same process as the test. Therefore, the standard out is a mix of test output and application output.

I want to read the output stream at runtime and fail the test if I see errors from the application. Is this possible/feasible? If so, how do I do it?

Note: I know I could start the applications as their own separate processes and then read their output streams. That's a lot of work from where I am now.

Also note, this is not a dupe of How to test a function's output (stdout/stderr) in Go unit tests, although that ticket is similar and helpful. The other ticket is about capturing output for a single function call. This ticket is about reading the entire stream, continuously. The correct answer is also a little different - it requires a pipe.

thebiggestlebowski
  • 2,610
  • 1
  • 33
  • 30
  • Possible duplicate of [How to test a function's output (stdout/stderr) in Go unit tests](https://stackoverflow.com/questions/26804642/how-to-test-a-functions-output-stdout-stderr-in-go-unit-tests) – Jonathan Hall Mar 15 '19 at 09:53
  • I don't think this is a dupe, although it is similar and helpful. Thank you for pointing me to it! The other ticket is about capturing output for a single function call. Here I want to read the entire stream, continuously. – thebiggestlebowski Mar 15 '19 at 13:19
  • The solution is the same. Every program is just a `main()` function, after all. – Jonathan Hall Mar 15 '19 at 13:19
  • The solution is similar, but not the same. The other solution has a definite start/stop whereas this is continuous streaming. Also, the other solution gets output after the function ends. I want a separate thread executing at the same time. – thebiggestlebowski Mar 15 '19 at 13:24
  • Go doesn't expose threads, so that's not really an option. – Jonathan Hall Mar 15 '19 at 13:25
  • As for the start/stop... if you want it to continue, just don't stop – Jonathan Hall Mar 15 '19 at 13:25
  • I've looked at the other question more closely. I agree mine is a duplicate. The other questions mentions a pipe and it's for capturing output from a test at runtime. – thebiggestlebowski Mar 15 '19 at 13:31
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/190092/discussion-between-thebiggestlebowski-and-flimzy). – thebiggestlebowski Mar 15 '19 at 13:33

2 Answers2

2

Yes, You may use os.Pipe() then process it yourself:

tmp := os.Stdout
r, w, err := os.Pipe()
if err != nil {
    panic(err)
}
os.Stdout = w

Or divert os.Stdout to a another file or strings.Builder.
Here is the detailed answer:
In Go, how do I capture stdout of a function into a string?

wasmup
  • 14,541
  • 6
  • 42
  • 58
0

A slightly modified version of an answer given in In Go, how do I capture stdout of a function into a string? using a os.Pipe (a form of IPC):

Pipe returns a connected pair of Files; reads from r return bytes written to w. It returns the files and an error, if any.

As os.Stdout is an *os.File, you could replace it with any file.

 package main

 import (
    "bytes"
    "fmt"
    "io"
    "log"
    "os"
 )

 func main() {
    old := os.Stdout
    r, w, _ := os.Pipe() // TODO: handle error.
    os.Stdout = w

    // All stdout will be caputered from here on.

    fmt.Println("this will be caputered")

    // Access output and restore previous stdout.
    outc := make(chan string)

    go func() {
        var buf bytes.Buffer
        io.Copy(&buf, r) // TODO: handle error
        outc <- buf.String()
    }()

    w.Close()
    os.Stdout = old

    out := <-outc
    log.Printf("captured: %s", out)
 }
miku
  • 181,842
  • 47
  • 306
  • 310