douxian6008
2018-04-17 06:25
浏览 50
已采纳

关闭io.PipeWriter是否会关闭基础文件?

I am using logrus for logging and have a few custom format loggers. Each is initialized to write to a different file like:

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

Later in the application, I need to change the file the logger is writing to (for a log rotation logic). What I want to achieve is to properly close the current file before changing the logger's output file. But the closest thing to the file handle logrus provides me is a Writer() method that returns a io.PipeWriter pointer. So would calling Close() on the PipeWriter also close the underlying file? If not, what are my options to do this, other than keeping the file pointer stored somewhere.

图片转代码服务由CSDN问答提供 功能建议

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

  fp,_:= os.OpenFile(path,os.O_APPEND | os.O_WRONLY | os.O_CREATE,0755)  
 //为简洁起见,未进行错误处理
log.Out = fp 
   
 
 

稍后在应用程序中,我需要更改记录器正在写入的文件( 对于日志旋转逻辑)。 我要实现的是在更改记录器的输出文件之前正确关闭当前文件。 但是与文件处理Logrus提供的最接近的东西是 Writer( ) 方法,该方法返回 io.PipeWriter 指针。 那么,在PipeWriter上调用 Close()也会关闭基础文件吗? 如果没有,除了将文件指针存储在某处之外,我有什么选择呢?

  • 写回答
  • 好问题 提建议
  • 追加酬金
  • 关注问题
  • 邀请回答

2条回答 默认 最新

  • doulan7166 2018-04-17 07:45
    最佳回答

    For the record, twelve-factor tells us that applications should not concern themselves with log rotation. If and how logs are handled best depends on how the application is deployed. Systemd has its own logging system, for instance. Writing to files when deployed in (Docker) containers is annoying. Rotating files are annoying during development.

    Now, pipes don't have an "underlying file". There's a Reader end and a Writer end, and that's it. From the docs for PipeWriter:

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

    So what happens when you close the writer depends on how Logrus handles EOF on the Reader end. Since Logger.Out is an io.Writer, Logrus cannot possibly call Close on your file.

    Your best bet would be to wrap *os.File, perhaps like so:

    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)
    }
    

    Implementing log file rotation in a robust way is surprisingly tricky. For instance, closing the old file before creating the new one is not a good idea. What if the log directory permissions changed? What if you run out of inodes? If you can't create a new log file you may want to keep writing to the current file. Are you okay with ripping lines apart, or do you only want to rotate after a newline? Do you want to rotate empty files? How do you reliably remove old logs if someone deletes the N-1th file? Will you notice the Nth file or stop looking at the N-2nd?

    The best advice I can give you is to leave log rotation to the pros. I like svlogd (part of runit) as a standalone log rotation tool.

    评论
    解决 无用
    打赏 举报
查看更多回答(1条)

相关推荐 更多相似问题