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  }