gpt4 book ai didi

golang 代理 io.Writer 在 log.Logger 中使用时表现不同

转载 作者:IT王子 更新时间:2023-10-29 01:40:47 25 4
gpt4 key购买 nike

我正在尝试实现一个满足 io.Writer 要求的代理,这样我就可以将它插入一个记录器中。这个想法是它会像平常一样打印输出,但也会保留一份数据副本供以后读取。

下面代码中的 ProxyIO 结构应该可以做到这一点,而且只要我直接调用它的 Write() 方法,它确实可以做到。但是,当我将它插入 log.Logger 实例时,输出是意外的。

(这是精简代码,我想使用的原始实现是使用映射和循环指针,而不是示例代码中使用的 [][]byte buf。我还删除了所有的锁定。)

package main

import (
"fmt"
"io"
"io/ioutil"
"log"
)

type ProxyIO struct {
out io.Writer // the io we are proxying
buf [][]byte
}

func newProxyIO(out io.Writer) *ProxyIO {
return &ProxyIO{
out: out,
buf: [][]byte{},
}
}

func (r *ProxyIO) Write(s []byte) (int, error) {
r.out.Write(s)
r.buf = append(r.buf, s)
return len(s), nil
}

func main() {
p := newProxyIO(ioutil.Discard)
p.Write([]byte("test1\n"))
p.Write([]byte("test2\n"))
p.Write([]byte("test3\n"))
l := log.New(p, "", 0)
l.Print("test4")
l.Print("test5")
l.Print("test6")
for i, e := range p.buf {
fmt.Printf("%d: %s", i, e)
}
}

(这是 Playground 上的代码 https://play.golang.org/p/UoOq4Nd-rmI )

我希望这段代码的输出如下:

0: test1
1: test2
2: test3
3: test4
4: test5
5: test6

但是,它总是会打印:

0: test1
1: test2
2: test3
3: test6
4: test6
5: test6

我的 map 实现的行为是相同的。我还尝试使用 container/list 中的双向链表作为存储,它总是一样的。所以我一定在这里遗漏了一些重要的东西。

为什么我在缓冲区中看到了三次最后的日志输出,而不是最后三行日志输出?

最佳答案

如果您查看 Logger.Print 的源代码你会看到它调用logger.Output .您会注意到它如何将字符串的值设置为 l.buf,然后调用 Write

如果您阅读 this answer你会看到即使一切都是按值传递

when you pass a slice to a function, a copy will be made from this header, including the pointer, which will point to the same backing array.

所以当你这样做的时候:

l.Print("test4")
l.Print("test5")
l.Print("test6")

Logger 有效地重用同一个 slice ,并且您要附加对同一个 slice 的引用三次,因此在打印时自然会使用最新的值集三次。

要解决此问题,您可以在使用前复制 []byte,如下所示:

func (r *ProxyIO) Write(s []byte) (int, error) {
c := make([]byte, len(s))
copy(c, s)
r.out.Write(c)
r.buf = append(r.buf, c)
return len(c), nil
}

更新 Playground :https://play.golang.org/p/DIWC1Xa6w0R

关于golang 代理 io.Writer 在 log.Logger 中使用时表现不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52787176/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com