package starlog import ( "errors" "fmt" "io" "math/rand" "os" "path/filepath" "runtime" "strconv" "strings" "sync" "time" "b612.me/starmap" "github.com/mattn/go-colorable" ) const ( LvDebug = iota LvInfo LvNotice LvWarning LvError LvCritical LvPanic LvFatal ) var ( levels = map[int]string{ LvDebug: "DEBUG", LvInfo: "INFO", LvNotice: "NOTICE", LvWarning: "WARNING", LvError: "ERROR", LvCritical: "CRITICAL", LvPanic: "PANIC", LvFatal: "FATAL", } Colors = map[int][]Attr{ LvDebug: []Attr{FgWhite}, LvInfo: []Attr{FgGreen}, LvNotice: []Attr{FgBlue}, LvWarning: []Attr{FgYellow}, LvError: []Attr{FgMagenta}, LvCritical: []Attr{FgRed, Bold}, LvPanic: []Attr{FgRed, Bold}, LvFatal: []Attr{FgRed}, } stdLock sync.Mutex logmaps sync.Map ) type StarLogger struct { mu *sync.Mutex lock *sync.Mutex Flag string out io.Writer ShowLine bool ShowLevel bool ShowFunc bool ShowThread bool DoWrite bool DoShow bool switching bool isStd bool //handleFunc stopChan chan int setChan chan int outshow io.Writer LogLevel int handleFunc func([]Attr, string) StdFuncColor bool logbuf string BufSize int stacks starmap.StarStack } type logTran struct { color []Attr log string } var Std = New(nil) var StdFile *os.File func init() { Std.DoShow = true Std.Flag = "MAN" Std.isStd = true logmaps.Store("std", Std) } func Close() error { if StdFile == nil { return errors.New("File not Open") } if err := Std.Flush(); err != nil { return err } return StdFile.Close() } func New(out io.Writer) *StarLogger { rand.Seed(time.Now().UnixNano()) logger := new(StarLogger) logger.DoShow = false logger.mu = new(sync.Mutex) logger.lock = new(sync.Mutex) logger.ShowLevel = true logger.ShowLine = true logger.DoWrite = true logger.ShowThread = true logger.ShowFunc = false logger.out = out logger.outshow = colorable.NewColorableStdout() logger.StdFuncColor = true logger.BufSize = 0 logger.Flag = "MAN" logger.stopChan, logger.setChan = make(chan int), make(chan int) go logger.runTransfer() logmaps.Store(fmt.Sprint(time.Now().UnixNano()), logger) return logger } func (logger *StarLogger) SetHandleFunc(funcs func([]Attr, string)) { if logger.handleFunc == nil { logger.setChan <- 1 } logger.handleFunc = funcs } func (logger *StarLogger) GetHandleFunc() func([]Attr, string) { return logger.handleFunc } func (logger *StarLogger) Flush() error { logger.mu.Lock() defer logger.mu.Unlock() logger.write(logger.logbuf) logger.logbuf = "" return nil } func (logger *StarLogger) Close() error { logger.stopChan <- 1 logmaps.Range(func(k, v interface{}) bool { if v.(*StarLogger) == logger { logmaps.Delete(k) return false } return true }) logger = nil return nil } func (logger *StarLogger) runTransfer() { if logger.handleFunc == nil { select { case <-logger.stopChan: return case <-logger.setChan: } } for { select { case <-logger.stopChan: return default: } if logger.handleFunc == nil { time.Sleep(time.Millisecond * 100) continue } poped := logger.stacks.MustPop() if poped == nil { time.Sleep(time.Millisecond * 20) continue } val := poped.(logTran) logger.handleFunc(val.color, val.log) } } func NewFlag() *StarLogger { return Std.NewFlag() } func (logger *StarLogger) NewFlag() *StarLogger { logger2 := new(StarLogger) logger2.out = logger.out logger2.ShowThread = logger.ShowThread logger2.ShowFunc = logger.ShowFunc logger2.DoShow = logger.DoShow logger2.ShowLevel = logger.ShowLevel logger2.ShowLine = logger.ShowLine logger2.DoWrite = logger.DoWrite logger2.outshow = logger.outshow logger2.mu = logger.mu logger2.lock = logger.lock logger2.Flag = string([]byte{uint8(rand.Intn(26) + 65), uint8(rand.Intn(26) + 65), uint8(rand.Intn(26) + 65)}) logger2.stopChan, logger2.setChan = make(chan int), make(chan int) logger2.handleFunc = logger.handleFunc go logger2.runTransfer() if logger2.Flag == "MAN" { logger2.Flag = "RYZ" } logmaps.Store(fmt.Sprint(time.Now().UnixNano()), logger2) return logger2 } func (logger *StarLogger) write(logstr string) { if (!logger.DoWrite) || (logger.out == nil) { return } i := 0 for logger.switching { time.Sleep(time.Millisecond * 100) i++ if i > 20 { return } } if &(logger.out) == nil { return } logger.out.Write([]byte(logstr)) } func (logger *StarLogger) OutPut(logstr string) { logger.out.Write([]byte(logstr)) } func (logger *StarLogger) output(level int, logstr string) { var logs string var skip int = 2 logger.mu.Lock() defer logger.mu.Unlock() if level < logger.LogLevel { return } if logger.isStd { skip++ } logger.isStd = false pc, fname, line, ok := runtime.Caller(skip) if !ok { return } funcname := runtime.FuncForPC(pc).Name() funcname = filepath.Ext(funcname) funcname = strings.TrimPrefix(funcname, ".") fname = filepath.Base(fname) date := time.Now().Format("2006-01-02 15:04:05.000 Mon") logs = date if logger.ShowLine { logs += " " + fname + ":" + strconv.Itoa(line) } if logger.ShowFunc { logs += " <" + funcname + ">" } if logger.ShowThread { logs += " |" + logger.Flag + "|" } if logger.ShowLevel { logs += " " + `[` + levels[level] + `]` } logs += " " + logstr if logger.DoShow { logcolor := NewColor(Colors[level]...) logcolor.Fprint(logger.outshow, logs) } if logger.handleFunc != nil { //logger.handleFunc(Colors[level], logs) logger.stacks.Push(logTran{Colors[level], logs}) } if logger.DoWrite { if logger.BufSize == 0 { logger.write(logs) } else { logger.logbuf += logs if len(logger.logbuf) >= logger.BufSize { logger.write(logs) } } } } func (logger *StarLogger) Debug(str ...interface{}) { strs := fmt.Sprint(str...) logger.output(LvDebug, strs) } func Debug(str ...interface{}) { stdLock.Lock() defer stdLock.Unlock() Std.isStd = true Std.Debug(str...) } func (logger *StarLogger) Debugf(format string, str ...interface{}) { strs := fmt.Sprintf(format, str...) logger.output(LvDebug, strs) } func Debugf(format string, str ...interface{}) { stdLock.Lock() defer stdLock.Unlock() Std.isStd = true Std.Debugf(format, str...) } func (logger *StarLogger) Debugln(str ...interface{}) { strs := fmt.Sprintln(str...) logger.output(LvDebug, strs) } func Debugln(str ...interface{}) { stdLock.Lock() defer stdLock.Unlock() Std.isStd = true Std.Debugln(str...) } func (logger *StarLogger) Info(str ...interface{}) { strs := fmt.Sprint(str...) logger.output(LvInfo, strs) } func Info(str ...interface{}) { stdLock.Lock() defer stdLock.Unlock() Std.isStd = true Std.Info(str...) } func (logger *StarLogger) Infof(format string, str ...interface{}) { strs := fmt.Sprintf(format, str...) logger.output(LvInfo, strs) } func Infof(format string, str ...interface{}) { stdLock.Lock() defer stdLock.Unlock() Std.isStd = true Std.Infof(format, str...) } func (logger *StarLogger) Infoln(str ...interface{}) { strs := fmt.Sprintln(str...) logger.output(LvInfo, strs) } func Infoln(str ...interface{}) { stdLock.Lock() defer stdLock.Unlock() Std.isStd = true Std.Infoln(str...) } func (logger *StarLogger) Notice(str ...interface{}) { strs := fmt.Sprint(str...) logger.output(LvNotice, strs) } func Notice(str ...interface{}) { stdLock.Lock() defer stdLock.Unlock() Std.isStd = true Std.Notice(str...) } func (logger *StarLogger) Noticef(format string, str ...interface{}) { strs := fmt.Sprintf(format, str...) logger.output(LvNotice, strs) } func Noticef(format string, str ...interface{}) { stdLock.Lock() defer stdLock.Unlock() Std.isStd = true Std.Noticef(format, str...) } func (logger *StarLogger) Noticeln(str ...interface{}) { strs := fmt.Sprintln(str...) logger.output(LvNotice, strs) } func Noticeln(str ...interface{}) { stdLock.Lock() defer stdLock.Unlock() Std.isStd = true Std.Noticeln(str...) } func (logger *StarLogger) Warning(str ...interface{}) { strs := fmt.Sprint(str...) logger.output(LvWarning, strs) } func Warning(str ...interface{}) { stdLock.Lock() defer stdLock.Unlock() Std.isStd = true Std.Warning(str...) } func (logger *StarLogger) Warningf(format string, str ...interface{}) { strs := fmt.Sprintf(format, str...) logger.output(LvWarning, strs) } func Warningf(format string, str ...interface{}) { stdLock.Lock() defer stdLock.Unlock() Std.isStd = true Std.Warningf(format, str...) } func (logger *StarLogger) Warningln(str ...interface{}) { strs := fmt.Sprintln(str...) logger.output(LvWarning, strs) } func Warningln(str ...interface{}) { stdLock.Lock() defer stdLock.Unlock() Std.isStd = true Std.Warningln(str...) } func (logger *StarLogger) Error(str ...interface{}) { strs := fmt.Sprint(str...) logger.output(LvError, strs) } func Error(str ...interface{}) { stdLock.Lock() defer stdLock.Unlock() Std.isStd = true Std.Error(str...) } func (logger *StarLogger) Errorf(format string, str ...interface{}) { strs := fmt.Sprintf(format, str...) logger.output(LvError, strs) } func Errorf(format string, str ...interface{}) { stdLock.Lock() defer stdLock.Unlock() Std.isStd = true Std.Errorf(format, str...) } func (logger *StarLogger) Errorln(str ...interface{}) { strs := fmt.Sprintln(str...) logger.output(LvError, strs) } func Errorln(str ...interface{}) { stdLock.Lock() defer stdLock.Unlock() Std.isStd = true Std.Errorln(str...) } func (logger *StarLogger) Critical(str ...interface{}) { strs := fmt.Sprint(str...) logger.output(LvCritical, strs) } func Critical(str ...interface{}) { stdLock.Lock() defer stdLock.Unlock() Std.isStd = true Std.Critical(str...) } func (logger *StarLogger) Criticalf(format string, str ...interface{}) { strs := fmt.Sprintf(format, str...) logger.output(LvCritical, strs) } func Criticalf(format string, str ...interface{}) { stdLock.Lock() defer stdLock.Unlock() Std.isStd = true Std.Criticalf(format, str...) } func (logger *StarLogger) Criticalln(str ...interface{}) { strs := fmt.Sprintln(str...) logger.output(LvCritical, strs) } func Criticalln(str ...interface{}) { stdLock.Lock() defer stdLock.Unlock() Std.isStd = true Std.Criticalln(str...) } func (logger *StarLogger) Fatal(str ...interface{}) { strs := fmt.Sprint(str...) logger.output(LvFatal, strs) os.Exit(9) } func Fatal(str ...interface{}) { stdLock.Lock() defer stdLock.Unlock() Std.isStd = true Std.Fatal(str...) } func (logger *StarLogger) Fatalf(format string, str ...interface{}) { strs := fmt.Sprintf(format, str...) logger.output(LvFatal, strs) os.Exit(9) } func Fatalf(format string, str ...interface{}) { stdLock.Lock() defer stdLock.Unlock() Std.isStd = true Std.Fatalf(format, str...) } func (logger *StarLogger) Fatalln(str ...interface{}) { strs := fmt.Sprintln(str...) logger.output(LvFatal, strs) os.Exit(9) } func Fatalln(str ...interface{}) { stdLock.Lock() defer stdLock.Unlock() Std.isStd = true Std.Fatalln(str...) } func (logger *StarLogger) Panic(str ...interface{}) { strs := fmt.Sprint(str...) logger.output(LvPanic, strs) panic(str) } func Panic(str ...interface{}) { stdLock.Lock() defer stdLock.Unlock() Std.isStd = true Std.Panic(str...) } func (logger *StarLogger) Panicf(format string, str ...interface{}) { strs := fmt.Sprintf(format, str...) logger.output(LvPanic, strs) panic(fmt.Sprintf(format, str...)) } func Panicf(format string, str ...interface{}) { stdLock.Lock() defer stdLock.Unlock() Std.isStd = true Std.Panicf(format, str...) } func (logger *StarLogger) Panicln(str ...interface{}) { strs := fmt.Sprintln(str...) logger.output(LvPanic, strs) panic(fmt.Sprintln(str...)) } func Panicln(str ...interface{}) { stdLock.Lock() defer stdLock.Unlock() Std.isStd = true Std.Panicln(str...) } func (logger *StarLogger) Print(str ...interface{}) { logger.lock.Lock() defer logger.lock.Unlock() strs := fmt.Sprint(str...) logger.OutPut(strs) } func Print(str ...interface{}) { stdLock.Lock() defer stdLock.Unlock() Std.isStd = true Std.Print(str...) } func (logger *StarLogger) Printf(format string, str ...interface{}) { logger.lock.Lock() defer logger.lock.Unlock() strs := fmt.Sprintf(format, str...) logger.OutPut(strs) } func Printf(format string, str ...interface{}) { stdLock.Lock() defer stdLock.Unlock() Std.isStd = true Std.Printf(format, str...) } func (logger *StarLogger) Println(str ...interface{}) { logger.lock.Lock() defer logger.lock.Unlock() strs := fmt.Sprintln(str...) logger.OutPut(strs) } func Println(str ...interface{}) { stdLock.Lock() defer stdLock.Unlock() Std.isStd = true Std.Println(str...) } func StdPrint(c []Attr, str ...interface{}) { Std.lock.Lock() defer Std.lock.Unlock() colorstr := NewColor(c...) colorstr.Print(str...) if Std.StdFuncColor && Std.handleFunc != nil { go Std.handleFunc(c, fmt.Sprint(str...)) } } func StdPrintf(c []Attr, format string, str ...interface{}) { Std.lock.Lock() defer Std.lock.Unlock() colorstr := NewColor(c...) colorstr.Printf(format, str...) if Std.StdFuncColor && Std.handleFunc != nil { go Std.handleFunc(c, fmt.Sprintf(format, str...)) } } func StdPrintln(c []Attr, str ...interface{}) { Std.lock.Lock() defer Std.lock.Unlock() colorstr := NewColor(c...) colorstr.Println(str...) if Std.StdFuncColor && Std.handleFunc != nil { go Std.handleFunc(c, fmt.Sprintln(str...)) } } func (logger *StarLogger) SwitchOut(out io.Writer) { logger.lock.Lock() defer logger.lock.Unlock() logger.switching = true logger.out = out logger.switching = false } func (logger *StarLogger) SetSwitching(out bool) { logger.lock.Lock() defer logger.lock.Unlock() logger.switching = out } func SetSwitchingAll(out bool) { logmaps.Range(func(k, v interface{}) bool { v.(*StarLogger).SetSwitching(out) return true }) } func SwitchOutAll(out io.Writer) { logmaps.Range(func(k, v interface{}) bool { v.(*StarLogger).SwitchOut(out) return true }) } func SethandleFuncAll(fn func([]Attr, string)) { logmaps.Range(func(k, v interface{}) bool { v.(*StarLogger).handleFunc = fn return true }) } func SetLogFile(path string) error { var err error StdFile, err = os.Create(path) Std.out = StdFile Std.switching = false return err } func SwitchFile(path string) error { Std.switching = true return SetLogFile(path) }