go - Go sdk 记录器如何以及何时刷新?
问题描述
我正在尝试确定默认/sdk 记录器 log.PrintYYY() 函数是否在某个时间点、退出、恐慌等被刷新。我不确定是否需要找到一种方法来刷新写入器记录器已连接,尤其是在使用 SetOutput(...) 设置输出写入器时。当然,writer 接口没有 flush() 方法,所以不确定如何完成。
Go sdk 记录器如何以及何时刷新?
解决方案
包log
不负责刷新底层io.Writer
。包可能会log
执行类型断言以查看当前io.Writer
是否有Flush()
方法,如果有则调用它,但不能保证如果多个io.Writer
s 被“链接”,数据最终会被刷新到最底层。
log
在我看来,包装不刷新的主要原因是性能。我们使用缓冲写入器,因此我们不必在每次写入单个字节(或字节片)时都到达底层,但我们可以缓存最近写入的数据,并且当我们达到某个大小(或某个time),我们可以一次高效地编写“批处理”。
如果log
包在每个日志语句之后刷新,那将使缓冲的 IO 无用。在小型应用程序的情况下这可能无关紧要,但如果您有一个高流量的 Web 服务器,在每个日志语句之后发出一个刷新(每个请求处理中可能有很多)会导致严重的性能缺陷。
那么是的,如果应用程序被终止,最后的日志语句可能不会到达底层。正确的解决方案是优雅地关闭:实现信号处理,当您的应用程序即将终止时,正确刷新并关闭io.Writer
您使用的记录器的底层。有关详细信息,请参阅:
是否可以以“延迟”方式捕获 Ctrl+C 信号并运行清理功能?
Go 中的 finally() 是否与 init() 正好相反?
如果——为了简单起见——你仍然需要一个在每个日志语句之后刷新的记录器,你可以轻松实现。这是因为该log.Logger
类型保证io.Writer
通过一次Writer.Write()
调用将每个日志消息传递到目标:
每个日志记录操作都会调用 Writer 的 Write 方法。一个 Logger 可以同时从多个 goroutine 中使用;它保证序列化对 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()
method 和os.File
'sSync()
方法,并在它们“存在”时调用。
这就是如何使用它,以便日志语句始终刷新:
f, err := os.Create("log.txt")
if err != nil {
panic(err)
}
defer f.Close()
log.SetOutput(&myWriter{Writer: f})
log.Println("hi")
查看相关问题:
推荐阅读
- javascript - Javascript 函数 - 破译有关基本函数的文档
- haproxy - HAProxy Maps 基于路径,如果主机匹配
- bluetooth-lowenergy - 为什么在使用低功耗蓝牙时必须停止蓝牙?
- python - 如何修改 CheckButtons 中的填充?
- javascript - 如何将输入值获取到 GET API 响应?
- recursion - J语言中的递归
- sql - 如何提取一个表中存在的不同 ID 而不是另一个表
- c - 如何访问映射到 swift 结构的内存缓冲区?
- javascript - 如何实例化已转译为 es5 的 es6 类
- file-upload - 如何上传超过 2MB 的文件(yii2)