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"` locker 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 (log *File) SetLevel(lv int) { log.Level = lv } func (log *File) Prefix(s string) { log.prefix = s } func (log *File) Print(i ...interface{}) { log.write(TraceLevel, fmt.Sprint(i...)) } func (log *File) Printf(format string, args ...interface{}) { log.write(TraceLevel, fmt.Sprintf(format, args...)) } func (log *File) Debug(i ...interface{}) { log.write(DebugLevel, fmt.Sprint(i...)) } func (log *File) Debugf(format string, args ...interface{}) { log.write(DebugLevel, fmt.Sprintf(format, args...)) } func (log *File) Info(i ...interface{}) { log.write(InfoLevel, fmt.Sprint(i...)) } func (log *File) Infof(format string, args ...interface{}) { log.write(InfoLevel, fmt.Sprintf(format, args...)) } func (log *File) Warn(i ...interface{}) { log.write(WarnLevel, fmt.Sprint(i...)) } func (log *File) Warnf(format string, args ...interface{}) { log.write(WarnLevel, fmt.Sprintf(format, args...)) } func (log *File) Error(i ...interface{}) { log.write(ErrorLevel, fmt.Sprint(i...)) } func (log *File) Errorf(format string, args ...interface{}) { log.write(ErrorLevel, fmt.Sprintf(format, args...)) } func (log *File) Fatal(i ...interface{}) { log.write(FatalLevel, fmt.Sprint(i...)) } func (log *File) Fatalf(format string, args ...interface{}) { log.write(FatalLevel, fmt.Sprintf(format, args...)) } func (log *File) Panic(i ...interface{}) { log.write(PanicLevel, fmt.Sprint(i...)) } func (log *File) Panicf(format string, args ...interface{}) { log.write(PanicLevel, fmt.Sprintf(format, args...)) } func (log *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 } func (log *File) write(level int, s string) { var ( n int err error ) if log.Level > level { return } log.locker.Lock() log.buf = log.buf[:0] if err = log.format(&log.buf, level, s); err != nil { log.locker.Unlock() return } log.buf = append(log.buf, '\n') if n, err = log.fp.Write(log.buf); err != nil { log.locker.Unlock() return } log.locker.Unlock() //write br log.size += int64(n) if log.MaxSize > 0 && log.size >= log.MaxSize { if err = log.rotate(); err != nil { return } log.size = 0 } } func (log *File) isExists(filename string) bool { if _, err := os.Stat(filename); err == nil { return true } else { return false } } func (log *File) rotate() (err error) { log.locker.Lock() defer log.locker.Unlock() if err = log.close(); err != nil { return } for i := log.MaxLogFiles; i >= 0; i-- { filename := log.Filename if i > 0 { filename += "." + strconv.Itoa(i) } if i == log.MaxLogFiles { if log.isExists(filename) { if err = os.Remove(filename); err != nil { return } } } else { if log.isExists(filename) { if err = os.Rename(filename, log.Filename+"."+strconv.Itoa(i+1)); err != nil { return } } } } err = log.open() return } func (log *File) Reload() (err error) { log.locker.Lock() _ = log.close() err = log.open() log.locker.Unlock() return } func (log *File) open() (err error) { if log.fp, err = os.OpenFile(log.Filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600); err != nil { return } return } func (log *File) Open() (err error) { if err = log.open(); err != nil { return } if info, err := os.Stat(log.Filename); err == nil { log.size = info.Size() } return } func (log *File) close() (err error) { if log.fp != nil { err = log.fp.Close() } return } func (log *File) Close() (err error) { err = log.close() return } func NewFileLogger(filename string) *File { lg := &File{Filename: filename, buf: make([]byte, 1024)} return lg }