package slog import ( "fmt" "os" "sync" ) type FileLogger struct { w *os.File l sync.Mutex buffer chan []byte buffered bool } func (f *FileLogger) flush() { f.l.Lock() defer func() { f.w.Sync() f.l.Unlock() }() if !f.buffered { return } for { select { case msg := <-f.buffer: f.w.Write(msg) default: return } } } func (f *FileLogger) write(p []byte) (n int, err error) { if f.w == nil { return 0, fmt.Errorf("No file handle available") } if f.buffered { if len(f.buffer)+len(p) >= cap(f.buffer) { f.flush() } f.l.Lock() defer f.l.Unlock() f.buffer <- p return len(p), nil } f.l.Lock() defer func() { f.w.Sync() f.l.Unlock() }() return f.w.Write(p) } func (f *FileLogger) Write(p []byte) (n int, err error) { return f.write(p) } func (f *FileLogger) WriteE(p []byte) (n int, err error) { return f.write(p) } func (f *FileLogger) Close() error { if f.w == nil { return nil } f.flush() return f.w.Close() } func newFileLogger(file string, buffer int) (ret SLogLogI, err error) { rret := &FileLogger{} rret.buffered = false if rret.w, err = os.OpenFile(file, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644); err != nil { return nil, err } if buffer > 0 { rret.buffer = make(chan []byte, buffer) rret.buffered = true } return rret, nil } func NewFileLogger(file string) (ret SLogLogI, err error) { return newFileLogger(file, 0) } func NewBufferedFileLogger(file string, buffer int) (ret SLogLogI, err error) { return newFileLogger(file, buffer) }