github.com/weedge/lib@v0.0.0-20230424045628-a36dcc1d90e4/log/logger.go (about) 1 package log 2 3 import ( 4 "fmt" 5 "io" 6 "os" 7 "path/filepath" 8 "sync" 9 ) 10 11 var _ io.WriteCloser = (*Logger)(nil) 12 13 var ( 14 // os_Stat exists so it can be mocked out by tests. 15 os_Stat = os.Stat 16 ) 17 18 type Logger struct { 19 Filename string 20 file *os.File 21 mu sync.Mutex 22 } 23 24 // dir returns the directory for the current filename. 25 func (l *Logger) dir() string { 26 return filepath.Dir(l.Filename) 27 } 28 29 // openNew opens a new log file for writing, moving any old log file out of the 30 // way. This methods assumes the file has already been closed. 31 func (l *Logger) openNew() error { 32 err := os.MkdirAll(l.dir(), 0755) 33 if err != nil { 34 return fmt.Errorf("can't make directories for new logfile: %s", err) 35 } 36 f, err := os.OpenFile(l.Filename, os.O_CREATE|os.O_WRONLY, 0655) 37 if err != nil { 38 return fmt.Errorf("can't open new logfile: %s", err) 39 } 40 l.file = f 41 return nil 42 } 43 44 func (l *Logger) openExistingOrNew() error { 45 filename := l.Filename 46 if _, err := os_Stat(filename); os.IsNotExist(err) { 47 return l.openNew() 48 } 49 50 file, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY, 0655) 51 l.file = file 52 if err != nil { 53 return l.openNew() 54 } 55 return nil 56 } 57 58 func (l *Logger) Write(p []byte) (n int, err error) { 59 l.mu.Lock() 60 defer l.mu.Unlock() 61 62 if l.file == nil { 63 if err = l.openExistingOrNew(); err != nil { 64 return 0, err 65 } 66 } 67 68 n, err = l.file.Write(p) 69 70 return n, err 71 } 72 73 // Close implements io.Closer, and closes the current logfile. 74 func (l *Logger) Close() error { 75 l.mu.Lock() 76 defer l.mu.Unlock() 77 return l.close() 78 } 79 80 // close closes the file if it is open. 81 func (l *Logger) close() error { 82 if l.file == nil { 83 return nil 84 } 85 err := l.file.Close() 86 l.file = nil 87 return err 88 }