123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415 |
- package log
- import (
- "bytes"
- "encoding/json"
- "fmt"
- "io"
- "os"
- "path"
- "runtime"
- "strconv"
- "sync"
- "time"
- "github.com/mattn/go-isatty"
- "github.com/valyala/fasttemplate"
- "github.com/labstack/gommon/color"
- )
- type (
- Logger struct {
- prefix string
- level Lvl
- skip int
- output io.Writer
- template *fasttemplate.Template
- levels []string
- color *color.Color
- bufferPool sync.Pool
- mutex sync.Mutex
- }
- Lvl uint8
- JSON map[string]interface{}
- )
- const (
- DEBUG Lvl = iota + 1
- INFO
- WARN
- ERROR
- OFF
- panicLevel
- fatalLevel
- )
- var (
- global = New("-")
- defaultHeader = `{"time":"${time_rfc3339_nano}","level":"${level}","prefix":"${prefix}",` +
- `"file":"${short_file}","line":"${line}"}`
- )
- func init() {
- global.skip = 3
- }
- func New(prefix string) (l *Logger) {
- l = &Logger{
- level: INFO,
- skip: 2,
- prefix: prefix,
- template: l.newTemplate(defaultHeader),
- color: color.New(),
- bufferPool: sync.Pool{
- New: func() interface{} {
- return bytes.NewBuffer(make([]byte, 256))
- },
- },
- }
- l.initLevels()
- l.SetOutput(output())
- return
- }
- func (l *Logger) initLevels() {
- l.levels = []string{
- "-",
- l.color.Blue("DEBUG"),
- l.color.Green("INFO"),
- l.color.Yellow("WARN"),
- l.color.Red("ERROR"),
- "",
- l.color.Yellow("PANIC", color.U),
- l.color.Red("FATAL", color.U),
- }
- }
- func (l *Logger) newTemplate(format string) *fasttemplate.Template {
- return fasttemplate.New(format, "${", "}")
- }
- func (l *Logger) DisableColor() {
- l.color.Disable()
- l.initLevels()
- }
- func (l *Logger) EnableColor() {
- l.color.Enable()
- l.initLevels()
- }
- func (l *Logger) Prefix() string {
- return l.prefix
- }
- func (l *Logger) SetPrefix(p string) {
- l.prefix = p
- }
- func (l *Logger) Level() Lvl {
- return l.level
- }
- func (l *Logger) SetLevel(v Lvl) {
- l.level = v
- }
- func (l *Logger) Output() io.Writer {
- return l.output
- }
- func (l *Logger) SetOutput(w io.Writer) {
- l.output = w
- if w, ok := w.(*os.File); !ok || !isatty.IsTerminal(w.Fd()) {
- l.DisableColor()
- }
- }
- func (l *Logger) Color() *color.Color {
- return l.color
- }
- func (l *Logger) SetHeader(h string) {
- l.template = l.newTemplate(h)
- }
- func (l *Logger) Print(i ...interface{}) {
- l.log(0, "", i...)
- // fmt.Fprintln(l.output, i...)
- }
- func (l *Logger) Printf(format string, args ...interface{}) {
- l.log(0, format, args...)
- }
- func (l *Logger) Printj(j JSON) {
- l.log(0, "json", j)
- }
- func (l *Logger) Debug(i ...interface{}) {
- l.log(DEBUG, "", i...)
- }
- func (l *Logger) Debugf(format string, args ...interface{}) {
- l.log(DEBUG, format, args...)
- }
- func (l *Logger) Debugj(j JSON) {
- l.log(DEBUG, "json", j)
- }
- func (l *Logger) Info(i ...interface{}) {
- l.log(INFO, "", i...)
- }
- func (l *Logger) Infof(format string, args ...interface{}) {
- l.log(INFO, format, args...)
- }
- func (l *Logger) Infoj(j JSON) {
- l.log(INFO, "json", j)
- }
- func (l *Logger) Warn(i ...interface{}) {
- l.log(WARN, "", i...)
- }
- func (l *Logger) Warnf(format string, args ...interface{}) {
- l.log(WARN, format, args...)
- }
- func (l *Logger) Warnj(j JSON) {
- l.log(WARN, "json", j)
- }
- func (l *Logger) Error(i ...interface{}) {
- l.log(ERROR, "", i...)
- }
- func (l *Logger) Errorf(format string, args ...interface{}) {
- l.log(ERROR, format, args...)
- }
- func (l *Logger) Errorj(j JSON) {
- l.log(ERROR, "json", j)
- }
- func (l *Logger) Fatal(i ...interface{}) {
- l.log(fatalLevel, "", i...)
- os.Exit(1)
- }
- func (l *Logger) Fatalf(format string, args ...interface{}) {
- l.log(fatalLevel, format, args...)
- os.Exit(1)
- }
- func (l *Logger) Fatalj(j JSON) {
- l.log(fatalLevel, "json", j)
- os.Exit(1)
- }
- func (l *Logger) Panic(i ...interface{}) {
- l.log(panicLevel, "", i...)
- panic(fmt.Sprint(i...))
- }
- func (l *Logger) Panicf(format string, args ...interface{}) {
- l.log(panicLevel, format, args...)
- panic(fmt.Sprintf(format, args))
- }
- func (l *Logger) Panicj(j JSON) {
- l.log(panicLevel, "json", j)
- panic(j)
- }
- func DisableColor() {
- global.DisableColor()
- }
- func EnableColor() {
- global.EnableColor()
- }
- func Prefix() string {
- return global.Prefix()
- }
- func SetPrefix(p string) {
- global.SetPrefix(p)
- }
- func Level() Lvl {
- return global.Level()
- }
- func SetLevel(v Lvl) {
- global.SetLevel(v)
- }
- func Output() io.Writer {
- return global.Output()
- }
- func SetOutput(w io.Writer) {
- global.SetOutput(w)
- }
- func SetHeader(h string) {
- global.SetHeader(h)
- }
- func Print(i ...interface{}) {
- global.Print(i...)
- }
- func Printf(format string, args ...interface{}) {
- global.Printf(format, args...)
- }
- func Printj(j JSON) {
- global.Printj(j)
- }
- func Debug(i ...interface{}) {
- global.Debug(i...)
- }
- func Debugf(format string, args ...interface{}) {
- global.Debugf(format, args...)
- }
- func Debugj(j JSON) {
- global.Debugj(j)
- }
- func Info(i ...interface{}) {
- global.Info(i...)
- }
- func Infof(format string, args ...interface{}) {
- global.Infof(format, args...)
- }
- func Infoj(j JSON) {
- global.Infoj(j)
- }
- func Warn(i ...interface{}) {
- global.Warn(i...)
- }
- func Warnf(format string, args ...interface{}) {
- global.Warnf(format, args...)
- }
- func Warnj(j JSON) {
- global.Warnj(j)
- }
- func Error(i ...interface{}) {
- global.Error(i...)
- }
- func Errorf(format string, args ...interface{}) {
- global.Errorf(format, args...)
- }
- func Errorj(j JSON) {
- global.Errorj(j)
- }
- func Fatal(i ...interface{}) {
- global.Fatal(i...)
- }
- func Fatalf(format string, args ...interface{}) {
- global.Fatalf(format, args...)
- }
- func Fatalj(j JSON) {
- global.Fatalj(j)
- }
- func Panic(i ...interface{}) {
- global.Panic(i...)
- }
- func Panicf(format string, args ...interface{}) {
- global.Panicf(format, args...)
- }
- func Panicj(j JSON) {
- global.Panicj(j)
- }
- func (l *Logger) log(v Lvl, format string, args ...interface{}) {
- l.mutex.Lock()
- defer l.mutex.Unlock()
- buf := l.bufferPool.Get().(*bytes.Buffer)
- buf.Reset()
- defer l.bufferPool.Put(buf)
- _, file, line, _ := runtime.Caller(l.skip)
- if v >= l.level || v == 0 {
- message := ""
- if format == "" {
- message = fmt.Sprint(args...)
- } else if format == "json" {
- b, err := json.Marshal(args[0])
- if err != nil {
- panic(err)
- }
- message = string(b)
- } else {
- message = fmt.Sprintf(format, args...)
- }
- _, err := l.template.ExecuteFunc(buf, func(w io.Writer, tag string) (int, error) {
- switch tag {
- case "time_rfc3339":
- return w.Write([]byte(time.Now().Format(time.RFC3339)))
- case "time_rfc3339_nano":
- return w.Write([]byte(time.Now().Format(time.RFC3339Nano)))
- case "level":
- return w.Write([]byte(l.levels[v]))
- case "prefix":
- return w.Write([]byte(l.prefix))
- case "long_file":
- return w.Write([]byte(file))
- case "short_file":
- return w.Write([]byte(path.Base(file)))
- case "line":
- return w.Write([]byte(strconv.Itoa(line)))
- }
- return 0, nil
- })
- if err == nil {
- s := buf.String()
- i := buf.Len() - 1
- if s[i] == '}' {
- // JSON header
- buf.Truncate(i)
- buf.WriteByte(',')
- if format == "json" {
- buf.WriteString(message[1:])
- } else {
- buf.WriteString(`"message":`)
- buf.WriteString(strconv.Quote(message))
- buf.WriteString(`}`)
- }
- } else {
- // Text header
- buf.WriteByte(' ')
- buf.WriteString(message)
- }
- buf.WriteByte('\n')
- l.output.Write(buf.Bytes())
- }
- }
- }
|