package log import ( "fmt" "os" "strconv" "sync" "time" ) type File struct { Filename string `json:"filename"` MaxSize int64 `json:"max_size"` MaxLogFiles int `json:"max_log_files"` Format string `json:"format"` Level int `json:"level"` mutex sync.RWMutex buf []byte fp *os.File prefix string size int64 } func itoa(buf *[]byte, i int, wid int) { // Assemble decimal in reverse order. var b [20]byte bp := len(b) - 1 for i >= 10 || wid > 1 { wid-- q := i / 10 b[bp] = byte('0' + i - q*10) bp-- i = q } // i < 10 b[bp] = byte('0' + i) *buf = append(*buf, b[bp:]...) } func (lg *File) SetLevel(lv int) { lg.Level = lv } func (lg *File) Prefix(s string) { lg.prefix = s } func (lg *File) Print(i ...interface{}) { lg.write(TraceLevel, fmt.Sprint(i...)) } func (lg *File) Printf(format string, args ...interface{}) { lg.write(TraceLevel, fmt.Sprintf(format, args...)) } func (lg *File) Debug(i ...interface{}) { lg.write(DebugLevel, fmt.Sprint(i...)) } func (lg *File) Debugf(format string, args ...interface{}) { lg.write(DebugLevel, fmt.Sprintf(format, args...)) } func (lg *File) Info(i ...interface{}) { lg.write(InfoLevel, fmt.Sprint(i...)) } func (lg *File) Infof(format string, args ...interface{}) { lg.write(InfoLevel, fmt.Sprintf(format, args...)) } func (lg *File) Warn(i ...interface{}) { lg.write(WarnLevel, fmt.Sprint(i...)) } func (lg *File) Warnf(format string, args ...interface{}) { lg.write(WarnLevel, fmt.Sprintf(format, args...)) } func (lg *File) Error(i ...interface{}) { lg.write(ErrorLevel, fmt.Sprint(i...)) } func (lg *File) Errorf(format string, args ...interface{}) { lg.write(ErrorLevel, fmt.Sprintf(format, args...)) } func (lg *File) Fatal(i ...interface{}) { lg.write(FatalLevel, fmt.Sprint(i...)) } func (lg *File) Fatalf(format string, args ...interface{}) { lg.write(FatalLevel, fmt.Sprintf(format, args...)) } func (lg *File) Panic(i ...interface{}) { lg.write(PanicLevel, fmt.Sprint(i...)) } func (lg *File) Panicf(format string, args ...interface{}) { lg.write(PanicLevel, fmt.Sprintf(format, args...)) } func (lg *File) format(buf *[]byte, level int, s string) (err error) { t := time.Now() year, month, day := t.Date() itoa(buf, year, 4) *buf = append(*buf, '-') itoa(buf, int(month), 2) *buf = append(*buf, '-') itoa(buf, day, 2) *buf = append(*buf, ' ') hour, min, sec := t.Clock() itoa(buf, hour, 2) *buf = append(*buf, ':') itoa(buf, min, 2) *buf = append(*buf, ':') itoa(buf, sec, 2) *buf = append(*buf, ' ') *buf = append(*buf, '[') *buf = append(*buf, getLevelText(level)...) *buf = append(*buf, ']') *buf = append(*buf, ' ') *buf = append(*buf, s...) return } // Write 实现标准的写入行数 func (lg *File) Write(p []byte) (n int, err error) { lg.mutex.Lock() defer lg.mutex.Unlock() if n, err = lg.fp.Write(p); err != nil { return } lg.size += int64(n) if lg.MaxSize > 0 && lg.size >= lg.MaxSize { if err = lg.rotate(); err != nil { return } lg.size = 0 } return } func (lg *File) write(level int, s string) { var ( n int err error ) if lg.Level > level { return } lg.mutex.Lock() defer lg.mutex.Unlock() lg.buf = lg.buf[:0] if err = lg.format(&lg.buf, level, s); err != nil { return } lg.buf = append(lg.buf, '\n') if n, err = lg.fp.Write(lg.buf); err != nil { return } lg.size += int64(n) if lg.MaxSize > 0 && lg.size >= lg.MaxSize { if err = lg.rotate(); err != nil { return } lg.size = 0 } } func (lg *File) isExists(filename string) bool { if _, err := os.Stat(filename); err == nil { return true } else { return false } } // rotate 实现日志滚动处理 func (lg *File) rotate() (err error) { if err = lg.close(); err != nil { return } for i := lg.MaxLogFiles; i >= 0; i-- { filename := lg.Filename if i > 0 { filename += "." + strconv.Itoa(i) } if i == lg.MaxLogFiles { if lg.isExists(filename) { if err = os.Remove(filename); err != nil { return } } } else { if lg.isExists(filename) { if err = os.Rename(filename, lg.Filename+"."+strconv.Itoa(i+1)); err != nil { return } } } } err = lg.open() return } func (lg *File) Reload() (err error) { lg.mutex.Lock() defer lg.mutex.Unlock() _ = lg.close() err = lg.open() return } func (lg *File) open() (err error) { if lg.fp, err = os.OpenFile(lg.Filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600); err != nil { return } return } func (lg *File) Open() (err error) { var ( info os.FileInfo ) if err = lg.open(); err != nil { return } if info, err = os.Stat(lg.Filename); err == nil { lg.size = info.Size() } return } func (lg *File) close() (err error) { if lg.fp != nil { err = lg.fp.Close() } return } func (lg *File) Close() (err error) { err = lg.close() return } func NewFileLogger(filename string) *File { lg := &File{Filename: filename, buf: make([]byte, 1024)} return lg }