github.com/ssgreg/logf@v1.4.1/appender.go (about) 1 package logf 2 3 import ( 4 "io" 5 "os" 6 "syscall" 7 ) 8 9 // Appender is the interface for your own strategies for outputting log 10 // entries. 11 type Appender interface { 12 // Append logs the Entry in Appender specific way. 13 Append(Entry) error 14 15 // Flush writes uncommitted changes to the underlying buffer of Writer. 16 Flush() error 17 18 // Sync writes uncommitted changes to the stable storage. For files this 19 // means flushing the file system's in-memory copy of recently written 20 // data to disk. 21 Sync() error 22 } 23 24 // NewDiscardAppender returns a new Appender that does nothing. 25 func NewDiscardAppender() Appender { 26 return &discardAppender{} 27 } 28 29 type discardAppender struct { 30 } 31 32 func (a *discardAppender) Append(Entry) error { 33 return nil 34 } 35 36 func (a *discardAppender) Sync() (err error) { 37 return nil 38 } 39 40 func (a *discardAppender) Flush() error { 41 return nil 42 } 43 44 // NewWriteAppender returns a new Appender with the given Writer and Encoder. 45 func NewWriteAppender(w io.Writer, enc Encoder) Appender { 46 s, _ := w.(syncer) 47 48 if s != nil { 49 err := s.Sync() 50 // Check for EINVAL and ENOTSUP - known errors if Writer is bound to 51 // a special File (e.g., a pipe or socket) which does not support 52 // synchronization. 53 if pathErr, ok := err.(*os.PathError); ok { 54 if errno, ok := pathErr.Err.(syscall.Errno); ok { 55 if errno == syscall.EINVAL || errno == syscall.ENOTSUP { 56 // Disable future syncs. 57 s = nil 58 } 59 } 60 } 61 } 62 63 return &writeAppender{ 64 w: w, 65 s: s, 66 enc: enc, 67 buf: NewBufferWithCapacity(PageSize * 2), 68 } 69 } 70 71 // syncer provides access the the Sync function of a Writer. 72 type syncer interface { 73 Sync() error 74 } 75 76 type writeAppender struct { 77 w io.Writer 78 s syncer 79 enc Encoder 80 buf *Buffer 81 } 82 83 func (a *writeAppender) Append(entry Entry) error { 84 err := a.enc.Encode(a.buf, entry) 85 if err != nil { 86 return err 87 } 88 if a.buf.Len() > PageSize { 89 a.Flush() 90 } 91 92 return nil 93 } 94 95 func (a *writeAppender) Sync() error { 96 if a.s == nil { 97 return nil 98 } 99 100 return a.s.Sync() 101 } 102 103 func (a *writeAppender) Flush() error { 104 if a.buf.Len() != 0 { 105 defer a.buf.Reset() 106 _, err := a.w.Write(a.buf.Bytes()) 107 108 return err 109 } 110 111 return nil 112 }