package starlog import ( "fmt" "io" "math/rand" "sync" "time" "b612.me/starlog/colorable" "b612.me/starmap" ) 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", } stacks *starmap.StarChanStack stackStarted bool = false stackStopChan chan int stackMu sync.Mutex stdScreen io.Writer = colorable.NewColorableStdout() errScreen io.Writer = colorable.NewColorableStderr() ) type starlog struct { mu *sync.Mutex output io.Writer errOutputLevel int showFuncName bool showThread bool showLevel bool showDeatilFile bool showColor bool switching bool showStd bool onlyColorLevel bool stopWriter bool id string name string colorList map[int][]Attr colorMe map[int]*Color } type StarLogger struct { thread string handlerFunc func(LogData) logcore *starlog isStd bool } type logTransfer struct { handlerFunc func(LogData) LogData } type LogData struct { Name string Log string Colors []Attr } func newLogCore(out io.Writer) *starlog { return &starlog{ mu: &sync.Mutex{}, output: out, errOutputLevel: LvError, showFuncName: true, showThread: true, showLevel: true, showStd: true, showDeatilFile: true, switching: false, stopWriter: false, showColor: true, id: generateId(), colorList: map[int][]Attr{ LvDebug: []Attr{FgWhite}, LvInfo: []Attr{FgGreen}, LvNotice: []Attr{FgCyan}, LvWarning: []Attr{FgYellow}, LvError: []Attr{FgMagenta}, LvCritical: []Attr{FgRed, Bold}, LvPanic: []Attr{FgRed, Bold}, LvFatal: []Attr{FgRed}, }, colorMe: map[int]*Color{ LvDebug: NewColor([]Attr{FgWhite}...), LvInfo: NewColor([]Attr{FgGreen}...), LvNotice: NewColor([]Attr{FgCyan}...), LvWarning: NewColor([]Attr{FgYellow}...), LvError: NewColor([]Attr{FgMagenta}...), LvCritical: NewColor([]Attr{FgRed, Bold}...), LvPanic: NewColor([]Attr{FgRed, Bold}...), LvFatal: NewColor([]Attr{FgRed}...), }, } } func NewStarlog(out io.Writer) *StarLogger { return &StarLogger{ handlerFunc: nil, thread: "MAN", logcore: newLogCore(out), isStd: false, } } func (logger *StarLogger) StdErrLevel() int { logger.logcore.mu.Lock() defer logger.logcore.mu.Unlock() return logger.logcore.errOutputLevel } func (logger *StarLogger) SetStdErrLevel(level int) { logger.logcore.mu.Lock() defer logger.logcore.mu.Unlock() logger.logcore.errOutputLevel = level } func (logger *StarLogger) NewFlag() *StarLogger { return &StarLogger{ thread: getRandomFlag(false), handlerFunc: logger.handlerFunc, logcore: logger.logcore, isStd: false, } } func (logger *StarLogger) SetNewRandomFlag() { logger.thread = getRandomFlag(false) } func (logger *StarLogger) SetName(name string) { logger.logcore.mu.Lock() defer logger.logcore.mu.Unlock() logger.logcore.name = name } func (logger *StarLogger) GetName() string { return logger.logcore.name } func getRandomFlag(isMain bool) string { rand.Seed(time.Now().UnixNano()) if isMain { return "MAN" } flag := "MAN" for flag == "MAN" { flag = string([]byte{uint8(rand.Intn(26) + 65), uint8(rand.Intn(26) + 65), uint8(rand.Intn(26) + 65)}) } return flag } func generateId() string { rand.Seed(time.Now().UnixNano()) return fmt.Sprintf("%dstar%db612%d", time.Now().UnixNano(), rand.Intn(1000000), rand.Intn(1000000)) } func StartStacks() { stackMu.Lock() if stackStarted { stackMu.Unlock() return } unlock := make(chan struct{}) go func() { stackStarted = true stacks = starmap.NewStarChanStack(1024) stackMu.Unlock() unlock <- struct{}{} defer func() { stackStarted = false }() for { select { case <-stackStopChan: return default: } poped, err := stacks.Pop() if err != nil { return } val := poped.(logTransfer) if val.handlerFunc != nil { val.handlerFunc(val.LogData) } } }() <-unlock } func StopStacks() { if !stackStarted { return } stackStopChan <- 1 } func Stop() { stacks.Close() StopStacks() }