如何等到特定行打印到 os.Stderr?
How to wait until a specific line is printed to os.Stderr?
我正在 运行 设置一个 Goroutine,在延迟一段时间后,它会将特定行记录到 os.Stderr
。我想等到记录该行。到目前为止,我尝试过的是
package main
import (
"bufio"
"log"
"os"
"strings"
"time"
)
func main() {
go func() {
time.Sleep(time.Second)
log.Println("Hello, world!")
}()
scanner := bufio.NewScanner(os.Stderr)
for scanner.Scan() {
if strings.Contains(scanner.Text(), "Hello, world!") {
break
}
}
}
但是,如果我 运行 这个,它只会阻塞:
> go run main.go
2022/04/17 00:31:43 Hello, world!
这个扫描器不应该捕获标准错误输出并命中 break
语句吗?
似乎如果 io.Reader
是 os.Stderr
,scanner.Scan()
会无限期地阻塞,而如果我将它设置为自定义 reader 就像 *bytes.Buffer
,它 returns 在 Goroutine 有机会写入它之前。
由于这个逻辑的上下文是一个单元测试,我通过使用 assert.Eventually
:
解决了这个问题
func TestScan(t *testing.T) {
buf := bytes.NewBuffer([]byte{})
log.SetOutput(buf)
go func() {
time.Sleep(time.Second)
log.Println("Hello, world!")
}()
assert.Eventually(t, func() bool {
scanner := bufio.NewScanner(buf)
for scanner.Scan() {
if strings.Contains(scanner.Text(), "Hello, world!") {
return true
}
}
return false
}, 10*time.Second, 100*time.Millisecond)
}
此测试按预期在 1.1 秒内通过:
> go test ./... -v
=== RUN TestScan
--- PASS: TestScan (1.10s)
PASS
(当然,这不是最有效的解决方案,因为它可能每次都读取整个输出,但它应该完成这项工作)。
如果你想拦截输出,你可以使用管道,像这样:
r, w, _ := os.Pipe()
log.SetOutput(w)
go func() {
time.Sleep(time.Second)
log.Println("Hello, world!")
}()
scanner := bufio.NewScanner(r)
我正在 运行 设置一个 Goroutine,在延迟一段时间后,它会将特定行记录到 os.Stderr
。我想等到记录该行。到目前为止,我尝试过的是
package main
import (
"bufio"
"log"
"os"
"strings"
"time"
)
func main() {
go func() {
time.Sleep(time.Second)
log.Println("Hello, world!")
}()
scanner := bufio.NewScanner(os.Stderr)
for scanner.Scan() {
if strings.Contains(scanner.Text(), "Hello, world!") {
break
}
}
}
但是,如果我 运行 这个,它只会阻塞:
> go run main.go
2022/04/17 00:31:43 Hello, world!
这个扫描器不应该捕获标准错误输出并命中 break
语句吗?
似乎如果 io.Reader
是 os.Stderr
,scanner.Scan()
会无限期地阻塞,而如果我将它设置为自定义 reader 就像 *bytes.Buffer
,它 returns 在 Goroutine 有机会写入它之前。
由于这个逻辑的上下文是一个单元测试,我通过使用 assert.Eventually
:
func TestScan(t *testing.T) {
buf := bytes.NewBuffer([]byte{})
log.SetOutput(buf)
go func() {
time.Sleep(time.Second)
log.Println("Hello, world!")
}()
assert.Eventually(t, func() bool {
scanner := bufio.NewScanner(buf)
for scanner.Scan() {
if strings.Contains(scanner.Text(), "Hello, world!") {
return true
}
}
return false
}, 10*time.Second, 100*time.Millisecond)
}
此测试按预期在 1.1 秒内通过:
> go test ./... -v
=== RUN TestScan
--- PASS: TestScan (1.10s)
PASS
(当然,这不是最有效的解决方案,因为它可能每次都读取整个输出,但它应该完成这项工作)。
如果你想拦截输出,你可以使用管道,像这样:
r, w, _ := os.Pipe()
log.SetOutput(w)
go func() {
time.Sleep(time.Second)
log.Println("Hello, world!")
}()
scanner := bufio.NewScanner(r)