duanlu4371 2016-07-17 11:16
浏览 70
已采纳

如何在io.MultiWriter中添加/删除按需编写器?

I am writing logs to a file and to the standard input of a program using something like:

type myLogger {
    log  *log.Logger
}

cmd := exec.Command("logger", "-t", "test")
w, _ = cmd.StdinPipe()

multi := io.MultiWriter(file, w)

myLog := myLogger{log.New(multi, "", log.Ldate|log.Ltime)}

But if the command exits, is killed or if I just want to add another Writer, how could I append it to the existing logger?

Currently for every change I create a new multi and overwrite the existing logger:

multi := io.MultiWriter(file, w)
myLog.log = log.New(multi, "", log.Ldate|log.Ltime)

But wondering if there is a better way of doing this and if by creating a new log.New, should I close the previous ones or they are just sharing references of the Writers that I pass to the multi var?

  • 写回答

1条回答 默认 最新

  • drbe16008 2016-07-18 10:40
    关注

    you may write your own package and add these two Removeand Append method like this working test sample code(not concurrent):

    package main
    
    import (
        "io"
        "os"
    )
    
    func main() {
        w1, e := os.Create("file1.txt")
        if e != nil {
            panic(e)
        }
        w2, e := os.Create("file2.txt")
        if e != nil {
            panic(e)
        }
        mw := MultiWriter(w1, w2)
        data := []byte("Hello ")
        _, e = mw.Write(data)
        if e != nil {
            panic(e)
        }
    
        var m *multiWriter = mw.(*multiWriter)
        m.Remove(w2)
        w2.Close()
        w3, e := os.Create("file3.txt")
        if e != nil {
            panic(e)
        }
        m.Append(w3)
        data = []byte("World ")
        _, e = mw.Write(data)
        if e != nil {
            panic(e)
        }
        w3.Close()
        w1.Close()
    }
    func (t *multiWriter) Remove(writers ...io.Writer) {
        for i := len(t.writers) - 1; i > 0; i-- {
            for _, v := range writers {
                if t.writers[i] == v {
                    t.writers = append(t.writers[:i], t.writers[i+1:]...)
                    break
                }
            }
        }
    }
    func (t *multiWriter) Append(writers ...io.Writer) {
        t.writers = append(t.writers, writers...)
    }
    
    type multiWriter struct {
        writers []io.Writer
    }
    
    func (t *multiWriter) Write(p []byte) (n int, err error) {
        for _, w := range t.writers {
            n, err = w.Write(p)
            if err != nil {
                return
            }
            if n != len(p) {
                err = io.ErrShortWrite
                return
            }
        }
        return len(p), nil
    }
    
    var _ stringWriter = (*multiWriter)(nil)
    
    func (t *multiWriter) WriteString(s string) (n int, err error) {
        var p []byte // lazily initialized if/when needed
        for _, w := range t.writers {
            if sw, ok := w.(stringWriter); ok {
                n, err = sw.WriteString(s)
            } else {
                if p == nil {
                    p = []byte(s)
                }
                n, err = w.Write(p)
            }
            if err != nil {
                return
            }
            if n != len(s) {
                err = io.ErrShortWrite
                return
            }
        }
        return len(s), nil
    }
    
    // MultiWriter creates a writer that duplicates its writes to all the
    // provided writers, similar to the Unix tee(1) command.
    func MultiWriter(writers ...io.Writer) io.Writer {
        w := make([]io.Writer, len(writers))
        copy(w, writers)
        return &multiWriter{w}
    }
    
    // stringWriter is the interface that wraps the WriteString method.
    type stringWriter interface {
        WriteString(s string) (n int, err error)
    }
    

    concurrent safe:

    package main
    
    import (
        "io"
        "os"
        "sync"
    )
    
    func main() {
        w1, e := os.Create("file1.txt")
        if e != nil {
            panic(e)
        }
        w2, e := os.Create("file2.txt")
        if e != nil {
            panic(e)
        }
        mw := MultiWriter(w1, w2)
        data := []byte("Hello ")
        _, e = mw.Write(data)
        if e != nil {
            panic(e)
        }
    
        var m *multiWriter = mw.(*multiWriter)
        m.Remove(w2)
        w2.Close()
        w3, e := os.Create("file3.txt")
        if e != nil {
            panic(e)
        }
        m.Append(w3)
        data = []byte("World ")
        _, e = mw.Write(data)
        if e != nil {
            panic(e)
        }
        w3.Close()
        w1.Close()
    }
    func (t *multiWriter) Remove(writers ...io.Writer) {
        t.mu.Lock()
        defer t.mu.Unlock()
        for i := len(t.writers) - 1; i > 0; i-- {
            for _, v := range writers {
                if t.writers[i] == v {
                    t.writers = append(t.writers[:i], t.writers[i+1:]...)
                    break
                }
            }
        }
    }
    func (t *multiWriter) Append(writers ...io.Writer) {
        t.mu.Lock()
        defer t.mu.Unlock()
        t.writers = append(t.writers, writers...)
    }
    
    type multiWriter struct {
        writers []io.Writer
        mu      sync.Mutex
    }
    
    func (t *multiWriter) Write(p []byte) (n int, err error) {
        t.mu.Lock()
        defer t.mu.Unlock()
        for _, w := range t.writers {
            n, err = w.Write(p)
            if err != nil {
                return
            }
            if n != len(p) {
                err = io.ErrShortWrite
                return
            }
        }
        return len(p), nil
    }
    
    var _ stringWriter = (*multiWriter)(nil)
    
    func (t *multiWriter) WriteString(s string) (n int, err error) {
        t.mu.Lock()
        defer t.mu.Unlock()
        var p []byte // lazily initialized if/when needed
        for _, w := range t.writers {
            if sw, ok := w.(stringWriter); ok {
                n, err = sw.WriteString(s)
            } else {
                if p == nil {
                    p = []byte(s)
                }
                n, err = w.Write(p)
            }
            if err != nil {
                return
            }
            if n != len(s) {
                err = io.ErrShortWrite
                return
            }
        }
        return len(s), nil
    }
    
    // MultiWriter creates a writer that duplicates its writes to all the
    // provided writers, similar to the Unix tee(1) command.
    func MultiWriter(writers ...io.Writer) io.Writer {
        w := make([]io.Writer, len(writers))
        copy(w, writers)
        return &multiWriter{writers: w}
    }
    
    // stringWriter is the interface that wraps the WriteString method.
    type stringWriter interface {
        WriteString(s string) (n int, err error)
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 C++ yoloV5改写遇到的问题
  • ¥20 win11修改中文用户名路径
  • ¥15 win2012磁盘空间不足,c盘正常,d盘无法写入
  • ¥15 用土力学知识进行土坡稳定性分析与挡土墙设计
  • ¥70 PlayWright在Java上连接CDP关联本地Chrome启动失败,貌似是Windows端口转发问题
  • ¥15 帮我写一个c++工程
  • ¥30 Eclipse官网打不开,官网首页进不去,显示无法访问此页面,求解决方法
  • ¥15 关于smbclient 库的使用
  • ¥15 微信小程序协议怎么写
  • ¥15 c语言怎么用printf(“\b \b”)与getch()实现黑框里写入与删除?