os.Pipe在与log包一起使用时无法按预期工作

huangapple go评论83阅读模式
英文:

os.Pipe not working as expected with log package

问题

我有一段代码,用于设置os.Pipe来捕获标准输出和标准错误:

https://github.com/sevagh/stdcap/blob/master/stdcap.go

// Capture执行f()并返回捕获的数据
func (s *stdcap) Capture(f func()) string {
    s.mu.Lock()
    defer s.mu.Unlock()

    var old, r, w *os.File

    if s.out {
        old = os.Stdout
        r, w, _ = os.Pipe()
        os.Stdout = w
    } else {
        old = os.Stderr
        r, w, _ = os.Pipe()
        os.Stderr = w
    }

    f()

    outC := make(chan string)
    defer close(outC)

    go func() {
        var buf bytes.Buffer
        io.Copy(&buf, r)
        outC <- buf.String()
    }()

    w.Close()

    if s.out {
        os.Stdout = old
    } else {
        os.Stderr = old
    }

    return <-outC
}

今天我尝试将这段代码与log包一起使用,但不起作用。

以下代码是有效的:

func TestOutCapture(t *testing.T) {
    sc := StdoutCapture()
    out := sc.Capture(func() {
        fmt.Printf("Hello world!")
    })

    if out != "Hello world!" {
        t.Errorf("Expected \"Hello world!\", got: %s\n", out)
    }
}

func TestErrCapture(t *testing.T) {
    sc := StderrCapture()
    err := sc.Capture(func() {
        fmt.Fprintf(os.Stderr, "Hello world!")
    })

    if err != "Hello world!" {
        t.Errorf("Expected \"Hello world!\", got: %s\n", err)
    }
}

以下代码不起作用:

func TestLogOutCapture(t *testing.T) {
    sc := StdoutCapture()

    log.SetOutput(os.Stdout)
    out := sc.Capture(func() {
        log.Printf("Hello world!")
    })

    if out != "Hello world!" {
        t.Errorf("Expected \"Hello world!\", got: %s\n", out)
    }
}

func TestLogErrCapture(t *testing.T) {
    sc := StderrCapture()
    log.SetOutput(os.Stderr)

    err := sc.Capture(func() {
        log.Printf("Hello world!")
    })

    if err != "Hello world!" {
        t.Errorf("Expected \"Hello world!\", got: %s\n", err)
    }
}

你有什么想法可以帮助我调试这个问题吗?Golang的log包是否不使用os.Stdout/os.Stderr

英文:

I have a piece of code which sets up an os.Pipe to capture Stdout/Stderr:

https://github.com/sevagh/stdcap/blob/master/stdcap.go

// Capture executes f() and returns the captured data
func (s *stdcap) Capture(f func()) string {
	s.mu.Lock()
	defer s.mu.Unlock()

	var old, r, w *os.File

	if s.out {
		old = os.Stdout
		r, w, _ = os.Pipe()
		os.Stdout = w
	} else {
		old = os.Stderr
		r, w, _ = os.Pipe()
		os.Stderr = w
	}

	f()

	outC := make(chan string)
	defer close(outC)

	go func() {
		var buf bytes.Buffer
		io.Copy(&amp;buf, r)
		outC &lt;- buf.String()
	}()

	w.Close()

	if s.out {
		os.Stdout = old
	} else {
		os.Stderr = old
	}

	return &lt;-outC
}

Today I tried using this code with the log package and it doesn't work.

This works:

func TestOutCapture(t *testing.T) {
	sc := StdoutCapture()
	out := sc.Capture(func() {
		fmt.Printf(&quot;Hello world!&quot;)
	})

	if out != &quot;Hello world!&quot; {
		t.Errorf(&quot;Expected \&quot;Hello world!\&quot;, got: %s\n&quot;, out)
	}
}

func TestErrCapture(t *testing.T) {
	sc := StderrCapture()
	err := sc.Capture(func() {
		fmt.Fprintf(os.Stderr, &quot;Hello world!&quot;)
	})

	if err != &quot;Hello world!&quot; {
		t.Errorf(&quot;Expected \&quot;Hello world!\&quot;, got: %s\n&quot;, err)
	}
}

These don't work:

func TestLogOutCapture(t *testing.T) {
	sc := StdoutCapture()

	log.SetOutput(os.Stdout)
	out := sc.Capture(func() {
		log.Printf(&quot;Hello world!&quot;)
	})

	if out != &quot;Hello world!&quot; {
		t.Errorf(&quot;Expected \&quot;Hello world!\&quot;, got: %s\n&quot;, out)
	}
}

func TestLogErrCapture(t *testing.T) {
	sc := StderrCapture()
	log.SetOutput(os.Stderr)

	err := sc.Capture(func() {
		log.Printf(&quot;Hello world!&quot;)
	})

	if err != &quot;Hello world!&quot; {
		t.Errorf(&quot;Expected \&quot;Hello world!\&quot;, got: %s\n&quot;, err)
	}
}

Any ideas on where I can debug this? Does the Golang log package not use os.Stdout/os.Stderr?

答案1

得分: 3

日志记录包在初始化时使用os.Stderr的值初始化标准记录器。对os.Stderr变量的修改不会改变记录器字段中的值。

调用log.SetOutput来从你的捕获函数更改标准记录器的输出位置。不幸的是,没有办法获取标准记录器的输出,以便在捕获函数中保存和恢复它。

英文:

The logging package initializes the standard logger with the value os.Stderr at initialization time. Modifications to the variable os.Stderr do not change the value in the logger field.

Call log.SetOutput to change the output location for the standard logger from your capture function. Unfortunately, there's not a way to get standard logger's output so you can save and restore it in your capture function.

huangapple
  • 本文由 发表于 2017年5月25日 00:39:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/44164122.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定