Can a process read its own "standard out" stream?
Asked Answered
S

2

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.

Smectic answered 15/3, 2019 at 5:59 Comment(8)
Possible duplicate of How to test a function's output (stdout/stderr) in Go unit testsSubmerged
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.Smectic
The solution is the same. Every program is just a main() function, after all.Submerged
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.Smectic
Go doesn't expose threads, so that's not really an option.Submerged
As for the start/stop... if you want it to continue, just don't stopSubmerged
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.Smectic
Let us continue this discussion in chat.Smectic
A
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?

Ables answered 15/3, 2019 at 6:12 Comment(0)
C
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)
 }
Cheffetz answered 15/3, 2019 at 6:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.