I need to write a service calling a black box function. That function may produce errors pushed to Stderr. I need to intercept them and print them immediately. The code below outlines the general idea.
package main
import (
"bytes"
"fmt"
"io"
"os"
)
func doMagic(i int) {
fmt.Fprintf(os.Stderr, "%d stderr\n", i)
}
func main() {
ch := make(chan struct{})
var buf bytes.Buffer
var wr, r *os.File
i := 0
go func() {
for {
ch <- struct{}{}
i += 1
doMagic(i)
wr.Close()
size, _ := io.Copy(&buf, r)
if size != 0 {
fmt.Printf("Size: %d, Content: %s", size, buf.String())
} else {
fmt.Println("Empty")
}
}
}()
for {
r, wr, _ = os.Pipe()
os.Stderr = wr
<-ch
}
}
However, it doesn't work as expected. I expect that the first iteration of the "for" loop within the goroutine should print the size and content of the first error message generated by the doMagic functions. Instead, it prints "Empty." Why does this occur, and how can I fix it? How to change the code to print errors from the "DoMagic" function immediately? How can I prevent the creation of a new Pipe and the subsequent closure of its write channel on each loop iteration?
UPD (03-19-2024)
It requires the buffer reset:
...
size, _ := io.Copy(&buf, r)
if size != 0 {
fmt.Printf("Size: %d, Content: %s", size, buf.String())
} else {
fmt.Println("Empty")
}
buf.Reset() // reset the buffer
...
Create a pipe to capture os.Stderr. Copy pipe to a buffer in a goroutine. Run the magic function. Cleanup.
https://go.dev/play/p/bHwd9X_QWPy
To print immediately, use an io.MultiWriter to write to the original stderr and the buffer:
https://go.dev/play/p/egDsSLuFwOV