gpt4 book ai didi

go - 关闭 io.PipeWriter 是否关闭底层文件?

转载 作者:数据小太阳 更新时间:2023-10-29 03:23:04 24 4
gpt4 key购买 nike

我正在使用 logrus用于记录并有一些自定义格式记录器。每个都被初始化为写入不同的文件,例如:

fp, _ := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0755)
// error handling left out for brevity
log.Out = fp

稍后在应用程序中,我需要更改记录器正在写入的文件(用于日志轮换逻辑)。我想要实现的是在更改记录器的输出文件之前正确关闭当前文件。但是 logrus 提供给我的最接近文件句柄的是 Writer()返回 io.PipeWriter 指针的方法。那么在 PipeWriter 上调用 Close() 是否也会关闭底层文件?如果不是,除了将文件指针存储在某处之外,我还有什么选择可以做到这一点。

最佳答案

为了记录,twelve-factor 告诉我们应用程序不应该关心日志轮换。是否以及如何最好地处理日志取决于应用程序的部署方式。例如,Systemd 有自己的日志系统。在(Docker)容器中部署时写入文件很烦人。在开发过程中旋转文件很烦人。

现在,管道没有“底层文件”。有一个 Reader 端和一个 Writer 端,仅此而已。来自 the docs for PipeWriter :

Close closes the writer; subsequent reads from the read half of the pipe will return no bytes and EOF.

那么当你关闭 writer 时会发生什么取决于 Logrus 在 Reader 端如何处理 EOF。自 Logger.Out是一个 io.Writer,Logrus 不可能对您的文件调用 Close。

最好的办法是包装 *os.File,也许像这样:

package main

import "os"

type RotatingFile struct {
*os.File
rotate chan struct{}
}

func NewRotatingFile(f *os.File) RotatingFile {
return RotatingFile{
File: f,
rotate: make(chan struct{}, 1),
}
}

func (r RotatingFile) Rotate() {
r.rotate <- struct{}{}
}

func (r RotatingFile) doRotate() error {
// file rotation logic here
return nil
}

func (r RotatingFile) Write(b []byte) (int, error) {
select {
case <-r.rotate:
if err := r.doRotate(); err != nil {
return 0, err
}
default:
}

return r.File.Write(b)
}

以稳健的方式实现日志文件轮换非常棘手。例如,在创建新文件之前关闭旧文件不是一个好主意。如果日志目录权限发生变化怎么办?如果 inode 用完了怎么办?如果您无法创建新的日志文件,您可能希望继续写入当前文件。您可以将行分开,还是只想在换行后旋转?你想旋转空文件吗?如果有人删除了第 N-1 个文件,您如何可靠地删除旧日志?你会注意到第 N 个文件还是停止查看第 N-2 个文件?

我能给你的最好建议是将日志轮换留给专业人士。我喜欢svlogd (runit 的一部分)作为独立的日志轮换工具。

关于go - 关闭 io.PipeWriter 是否关闭底层文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49871231/

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