github.com/Aestek/consul@v1.2.4-0.20190309222502-b2c31e33971a/logger/logfile.go (about) 1 package logger 2 3 import ( 4 "os" 5 "path/filepath" 6 "strconv" 7 "strings" 8 "sync" 9 "time" 10 ) 11 12 var ( 13 now = time.Now 14 ) 15 16 //LogFile is used to setup a file based logger that also performs log rotation 17 type LogFile struct { 18 //Name of the log file 19 fileName string 20 21 //Path to the log file 22 logPath string 23 24 //Duration between each file rotation operation 25 duration time.Duration 26 27 //LastCreated represents the creation time of the latest log 28 LastCreated time.Time 29 30 //FileInfo is the pointer to the current file being written to 31 FileInfo *os.File 32 33 //MaxBytes is the maximum number of desired bytes for a log file 34 MaxBytes int 35 36 //BytesWritten is the number of bytes written in the current log file 37 BytesWritten int64 38 39 //acquire is the mutex utilized to ensure we have no concurrency issues 40 acquire sync.Mutex 41 } 42 43 func (l *LogFile) openNew() error { 44 // Extract the file extension 45 fileExt := filepath.Ext(l.fileName) 46 // If we have no file extension we append .log 47 if fileExt == "" { 48 fileExt = ".log" 49 } 50 // Remove the file extension from the filename 51 fileName := strings.TrimSuffix(l.fileName, fileExt) 52 // New file name has the format : filename-timestamp.extension 53 createTime := now() 54 newfileName := fileName + "-" + strconv.FormatInt(createTime.UnixNano(), 10) + fileExt 55 newfilePath := filepath.Join(l.logPath, newfileName) 56 // Try creating a file. We truncate the file because we are the only authority to write the logs 57 filePointer, err := os.OpenFile(newfilePath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0640) 58 if err != nil { 59 return err 60 } 61 l.FileInfo = filePointer 62 // New file, new bytes tracker, new creation time :) 63 l.LastCreated = createTime 64 l.BytesWritten = 0 65 return nil 66 } 67 68 func (l *LogFile) rotate() error { 69 // Get the time from the last point of contact 70 timeElapsed := time.Since(l.LastCreated) 71 // Rotate if we hit the byte file limit or the time limit 72 if (l.BytesWritten >= int64(l.MaxBytes) && (l.MaxBytes > 0)) || timeElapsed >= l.duration { 73 l.FileInfo.Close() 74 return l.openNew() 75 } 76 return nil 77 } 78 79 func (l *LogFile) Write(b []byte) (n int, err error) { 80 l.acquire.Lock() 81 defer l.acquire.Unlock() 82 //Create a new file if we have no file to write to 83 if l.FileInfo == nil { 84 if err := l.openNew(); err != nil { 85 return 0, err 86 } 87 } 88 // Check for the last contact and rotate if necessary 89 if err := l.rotate(); err != nil { 90 return 0, err 91 } 92 l.BytesWritten += int64(len(b)) 93 return l.FileInfo.Write(b) 94 }