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.

  • 写回答

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

报告相同问题?

悬赏问题

  • ¥15 乌班图ip地址配置及远程SSH
  • ¥15 怎么让点阵屏显示静态爱心,用keiluVision5写出让点阵屏显示静态爱心的代码,越快越好
  • ¥15 PSPICE制作一个加法器
  • ¥15 javaweb项目无法正常跳转
  • ¥15 VMBox虚拟机无法访问
  • ¥15 skd显示找不到头文件
  • ¥15 机器视觉中图片中长度与真实长度的关系
  • ¥15 fastreport table 怎么只让每页的最下面和最顶部有横线
  • ¥15 java 的protected权限 ,问题在注释里
  • ¥15 这个是哪里有问题啊?