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  }