Go sdk记录器如何以及何时刷新?

时间:2018-10-22 18:44:30

标签: go logging flush

我正在尝试确定默认/ sdk记录器日志。PrintYYY()函数是否在某个时间点,退出,紧急情况等时被刷新。我不确定是否需要找到一种刷新方法记录器连接到的编写器,尤其是在使用SetOutput(...)设置输出编写器时。当然,writer接口没有flush()方法,因此不确定是否可以完成此操作。

Go sdk记录器如何以及何时刷新?

2 个答案:

答案 0 :(得分:1)

log程序包不负责刷新基础的io.Writerlog程序包可能会执行类型声明,以查看当前的io.Writer是否具有Flush()方法,如果可以,则进行调用,但不能保证如果多个“ io.Writer”被“链接”,则数据最终将被刷新到最底层。

在我看来,log软件包没有刷新的主要原因是 performance 。我们使用缓冲的写入器,因此不必每次写入单个字节(或字节片)时都到达底层,但是我们可以缓存最近写入的数据,并在达到特定大小(或特定大小)时进行缓存时间),我们可以立即高效地编写“批处理”。

如果log软件包将在每个日志语句后刷新,则将使缓冲的IO失效。对于小型应用程序来说,这可能无关紧要,但是,如果您的网络服务器流量很高,则在每个日志语句(每个请求处理中可能有很多日志语句)之后发出刷新操作会严重影响性能。

然后是的,如果应用程序终止,则会出现问题,最后的日志语句可能无法进入基础层。正确的解决方案是执行正常关机:实施信号处理,并在您的应用即将终止时,正确刷新并关闭您使用的记录器的基础io.Writer。有关详细信息,请参见:

Is it possible to capture a Ctrl+C signal and run a cleanup function, in a "defer" fashion?

Is there something like finally() in Go just opposite to what init()?

Are deferred functions called when SIGINT is received in Go?

如果(仅出于简化目的)您仍然需要一个在每个日志语句后刷新的记录器,则可以轻松实现。这是因为log.Logger类型可确保通过单个io.Writer调用将每条日志消息传递到目标Writer.Write()

  

每个日志记录操作都会调用Writer的Write方法。一个Logger可以同时从多个goroutines中使用。它保证序列化对Writer的访问。

因此,基本上,您所需要做的就是创建一个“包装器” io.Writer,其“ Write()”方法在将“ Write()”调用“转发”给其底层编写器之后进行刷新。

它是这样的:

type myWriter struct {
    io.Writer
}

func (m *myWriter) Write(p []byte) (n int, err error) {
    n, err = m.Writer.Write(p)

    if flusher, ok := m.Writer.(interface{ Flush() }); ok {
        flusher.Flush()
    } else if syncer := m.Writer.(interface{ Sync() error }); ok {
        // Preserve original error
        if err2 := syncer.Sync(); err2 != nil && err == nil {
            err = err2
        }
    }
    return
}

此实现会同时检查Flush()方法和os.FileSync()方法,并调用它们是否“存在”。

这是可以使用的方式,以便日志记录语句始终刷新:

f, err := os.Create("log.txt")
if err != nil {
    panic(err)
}
defer f.Close()

log.SetOutput(&myWriter{Writer: f})

log.Println("hi")

查看相关问题:

Go: Create io.Writer inteface for logging to mongodb database

net/http set custom logger

答案 1 :(得分:0)

记录器不应该知道如何刷新数据。您必须刷新在记录器创建时指定的输出记录器(如果具有此功能)。

请参阅github discussion

中的示例
package main

import (
    "bufio"
    "flag"
    "log"
    "os"
    "strings"
)

func main() {
    var flush bool
    flag.BoolVar(&flush, "flush", false, "if set, will flush the buffered io before exiting")
    flag.Parse()

    br := bufio.NewWriter(os.Stdout)
    logger := log.New(br, "", log.Ldate)
    logger.Printf("%s\n", strings.Repeat("This is a test\n", 5))
    if flush {
        br.Flush()
    }
    logger.Fatalf("exiting now!")
}

您可以阅读与您的问题on github相关的整个讨论

或者,您可以查看具有flush的第三方记录器。检出具有方法logger.Sync()

zap logger
相关问题