使用go中的goroutine捕获Stderr并将其重定向到服务中的Stdout

问题描述 投票:0回答:1

我需要编写一个调用黑盒函数的服务。该函数可能会产生推送到 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 以及随后关闭其写入通道?

go pipe channel goroutine
1个回答
0
投票

创建一个管道来捕获 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())

}

https://go.dev/play/p/bHwd9X_QWPy

© www.soinside.com 2019 - 2024. All rights reserved.