252 lines
4.9 KiB
Go
252 lines
4.9 KiB
Go
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
|
|
}
|