package log import ( "bytes" "fmt" "io" "os" "path/filepath" "sync" ) type baseWriter struct { logw *os.File stdw *os.File errw *os.File logFilename string logPreBackupTag string } type cacheWriter struct { cache bytes.Buffer cacheing bool cacheLock *sync.Mutex baseWriter io.Writer } func NewBaseWriter(logw, stdw, errw *os.File) *baseWriter { return &baseWriter{ logw: logw, stdw: stdw, errw: errw, } } // OpenLogFile func (w *baseWriter) OpenLogFile(logDir, logName string, optLogDirs []string) { // Step 1. try get available log dir if _, err := os.Stat(logDir); err == nil { logDir = logDir } else if dir, err := tryOptLogDirs(optLogDirs); err == nil { logDir = dir } else if err := os.Mkdir(logDir, 0755); err == nil { logDir = logDir } else { errstr := fmt.Sprintf("all path not exist:\n "+ "a.[%s]\n b.[%s]\n c.[%s]\n", logDir, "./log/", "./logs/") panic("failed initlog:" + errstr) } // Step 2. open base writer logfile filename := filepath.Join(logDir, logName+".log") w.logFilename = filename w.logPreBackupTag = "" w.ReopenLogFile() } // ReopenLogFile func (w *baseWriter) ReopenLogFile() { var fil, err = os.OpenFile(w.logFilename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, os.ModePerm) if err != nil { panic("open log file failed:" + err.Error()) } w.logw.Close() w.logw = fil } // BackupLogFile func (w *baseWriter) TryBackupLogFile(tag string) bool { if w.logPreBackupTag == "" { w.logPreBackupTag = tag return false } else if w.logPreBackupTag == tag { return false } w.logPreBackupTag = tag newname := w.logFilename + "." + tag if err := os.Rename(w.logFilename, newname); err != nil { return false } w.ReopenLogFile() return true } func NewCacheWriter(basewriter io.Writer) *cacheWriter { return &cacheWriter{ cache: bytes.Buffer{}, cacheing: false, cacheLock: new(sync.Mutex), baseWriter: basewriter, } } func (w *baseWriter) Write(p []byte) (n int, err error) { if w.errw != nil { n, err = w.errw.Write(p) } if w.stdw != nil { n, err = w.stdw.Write(p) } if w.logw != nil { n, err = w.logw.Write(p) } return n, err } func (w *cacheWriter) Write(p []byte) (n int, err error) { if w.cacheing { w.cache.Write(p) } return w.baseWriter.Write(p) } func (w *cacheWriter) GetCacheLog() string { if w.cacheing != true { panic("GetCacheLog MUST call after StartCacheLog called") } return w.cache.String() } func (w *cacheWriter) StartCacheLog() { w.cacheLock.Lock() w.cacheing = true w.cache.Reset() } func (w *cacheWriter) StopCacheLog() { w.cacheLock.Unlock() w.cacheing = true }