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 求差集那个函数有问题,有无佬可以解决
  • ¥15 【提问】基于Invest的水源涵养
  • ¥20 微信网友居然可以通过vx号找到我绑的手机号
  • ¥15 寻一个支付宝扫码远程授权登录的软件助手app
  • ¥15 解riccati方程组
  • ¥15 display:none;样式在嵌套结构中的已设置了display样式的元素上不起作用?
  • ¥15 使用rabbitMQ 消息队列作为url源进行多线程爬取时,总有几个url没有处理的问题。
  • ¥15 Ubuntu在安装序列比对软件STAR时出现报错如何解决
  • ¥50 树莓派安卓APK系统签名
  • ¥65 汇编语言除法溢出问题