我需要编写一个调用黑盒函数的服务。该函数可能会产生推送到 Stderr 的错误。我需要拦截它们并立即打印它们。下面的代码概述了总体思路。
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
}
}
但是,它并没有按预期工作。我希望 goroutine 中“for”循环的第一次迭代应该打印
doMagic
函数生成的第一条错误消息的大小和内容。相反,它打印“Empty”。为什么会发生这种情况?我该如何解决它?如何更改代码以立即从“DoMagic”函数打印错误?如何防止在每次循环迭代中创建新 Pipe 以及随后关闭其写入通道?
创建一个管道来捕获 os.Stderr。将管道复制到 Goroutine 中的缓冲区。运行魔法函数。清理。
func run(i int) {
r, w, _ := os.Pipe()
// Capture stderr
stderr := os.Stderr
os.Stderr = w
defer func() {
os.Stderr = stderr
}()
// Copy catured stderr to a buffer.
done := make(chan *bytes.Buffer)
go func() {
defer r.Close()
var buf bytes.Buffer
io.Copy(&buf, r)
done <- &buf
}()
doMagic(i)
// Close write to cause io.Copy to complete.
w.Close()
// Wait for goroutine to complete.
buf := <-done
fmt.Printf("Size: %d, Content: %s", buf.Len(), buf.String())
}