diff --git a/tlog/logger.go b/tlog/logger.go index fe1b108..8217ba8 100644 --- a/tlog/logger.go +++ b/tlog/logger.go @@ -1,3 +1,5 @@ +// +build !windows + package tlog import ( diff --git a/tlog/logger_windows.go b/tlog/logger_windows.go new file mode 100644 index 0000000..6ce49ac --- /dev/null +++ b/tlog/logger_windows.go @@ -0,0 +1,216 @@ +//go:build windows +// +build windows + +package tlog + +import ( + "bufio" + "bytes" + "fmt" + "os" + "path/filepath" + "runtime" + "strings" + "sync" + "time" +) + +var l *Logger +var mu sync.Mutex + +type Logger struct { + fileSize int64 + fileNum int + fileName string + host string + debug bool + tag string + level LEVEL + dir string + ch chan *Atom + f *os.File + w *bufio.Writer + bytePool *sync.Pool +} + +type Atom struct { + line int + file string + format string + level LEVEL + args []interface{} + data map[string]interface{} +} + +func newLogger(config Config) *Logger { + logger := &Logger{ + dir: config.Dir, + fileSize: int64(config.FileSize * 1024 * 1024), + fileNum: config.FileNum, + fileName: filepath.Join(config.Dir, config.FileName+".log"), + tag: config.Tag, + debug: config.Debug, + level: getLevel(config.Level), + ch: make(chan *Atom, 102400), + bytePool: &sync.Pool{New: func() interface{} { return new(bytes.Buffer) }}, + } + + host, _ := os.Hostname() + ss := strings.Split(host, "-") + if len(ss) < 2 { + logger.host = host + } else { + logger.host = ss[len(ss)-2] + ss[len(ss)-1] + } + + if logger.debug { + return logger + } + + os.MkdirAll(logger.dir, 0755) + logger.f, _ = os.OpenFile(logger.fileName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + logger.w = bufio.NewWriterSize(logger.f, 1024*1024) + + return logger +} + +func (l *Logger) run() { + if l.debug { + return + } + go l.flush() + go l.start() +} + +func (l *Logger) start() { + for { + a := <-l.ch + if a == nil { + l.flushNow() + continue + } + b := l.bytes(a) + l.w.Write(b) + } +} + +func (l *Logger) flushNow() { + l.w.Flush() + info, err := os.Stat(l.fileName) + if err == nil && info.Size() > l.fileSize { + l.rotate() + } +} + +func (l *Logger) rotate() { + l.f.Close() + newName := l.logname() + os.Rename(l.fileName, newName) + l.f, _ = os.OpenFile(l.fileName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + l.w.Reset(l.f) + + // 简化版本,不做保留 N 个旧日志处理 +} + +func (l *Logger) flush() { + for range time.NewTicker(time.Second).C { + l.ch <- nil + } +} + +func (l *Logger) stop() { + if l != nil && l.w != nil { + l.w.Flush() + } +} + +func (l *Logger) getTag() string { + if l != nil { + return l.tag + } + return "" +} + +func (l *Logger) bytes(a *Atom) []byte { + w := l.bytePool.Get().(*bytes.Buffer) + defer func() { + w.Reset() + l.bytePool.Put(w) + }() + + w.Write(l.genTime()) + fmt.Fprintf(w, "%s %s %s %s:%d ", l.host, l.tag, levelText[a.level], a.file, a.line) + if a.format == "" { + for _, arg := range a.args { + w.WriteByte(' ') + fmt.Fprint(w, arg) + } + } else { + fmt.Fprintf(w, a.format, a.args...) + } + w.WriteByte('\n') + b := make([]byte, w.Len()) + copy(b, w.Bytes()) + return b +} + +func (l *Logger) logname() string { + now := time.Now().Format("20060102_150405") + return fmt.Sprintf("%s.%s", l.fileName, now) +} + +func (l *Logger) getFileNameAndLine() (string, int) { + _, file, line, ok := runtime.Caller(3) + if !ok { + return "???", 1 + } + dirs := strings.Split(file, string(os.PathSeparator)) + if len(dirs) >= 2 { + return dirs[len(dirs)-2] + "/" + dirs[len(dirs)-1], line + } + return file, line +} + +func (l *Logger) p(level LEVEL, args ...interface{}) { + file, line := l.getFileNameAndLine() + if l == nil || l.debug { + mu.Lock() + defer mu.Unlock() + fmt.Printf("%s%s %s %s:%d ", l.genTime(), l.getTag(), levelText[level], file, line) + fmt.Println(args...) + return + } + if level >= l.level { + select { + case l.ch <- &Atom{file: file, line: line, level: level, args: args}: + default: + } + } +} + +func (l *Logger) pf(level LEVEL, format string, args ...interface{}) { + file, line := l.getFileNameAndLine() + if l == nil || l.debug { + mu.Lock() + defer mu.Unlock() + fmt.Printf("%s%s %s %s:%d ", l.genTime(), l.getTag(), levelText[level], file, line) + fmt.Printf(format, args...) + fmt.Println() + return + } + if level >= l.level { + select { + case l.ch <- &Atom{file: file, line: line, format: format, level: level, args: args}: + default: + } + } +} + +func (l *Logger) genTime() []byte { + now := time.Now() + return []byte(now.Format("01-02 15:04:05 ")) +} + +func (l *Logger) pj(level LEVEL, m map[string]interface{}) { + return +}