klog/log.go

330 lines
6.5 KiB
Go
Raw Normal View History

2021-11-01 14:38:30 +00:00
package log
import (
2021-11-03 05:51:59 +00:00
"encoding/json"
2021-11-01 14:38:30 +00:00
"fmt"
"io"
"os"
2021-11-02 07:26:10 +00:00
"sync"
2021-11-01 14:38:30 +00:00
"text/template"
"time"
"github.com/mattn/go-isatty"
)
const (
Lerror = 1 << iota
2021-11-01 14:41:11 +00:00
Ldebug
2021-11-01 14:38:30 +00:00
Lwarn
Linfo
2021-11-01 14:41:11 +00:00
)
type tout int
const (
terror tout = iota
tdebug
tinfo
twarn
2021-11-01 14:38:30 +00:00
)
2021-11-02 07:26:10 +00:00
var lock sync.Mutex
2021-11-01 14:38:30 +00:00
var PROD = true
var LEVEL = Lerror | Linfo
const (
2021-11-03 05:51:59 +00:00
DEFAULT_ERR = `{{Time}} [{{"ERROR"|red}}]` +
`{{if .System}}({{.System|cyan}}){{end}} ` +
`{{.Caller}} {{.Message}}` +
`{{if .Fields}} {{.Fields|json|green}}{{end}}{{"\n"}}` +
`{{if .Stack}}{{.Stack|redl}}{{end}}`
DEFAULT_DEBUG = `{{Time}} [{{"DEBUG"|magenta}}]` +
`{{if .System}}({{.System|cyan}}){{end}} ` +
`{{.Caller}} {{.Message}}` +
`{{if .Fields}} {{.Fields|json|green}}{{end}}{{"\n"}}` +
`{{if .Stack}}{{.Stack|redl}}{{end}}`
DEFAULT_WARN = `{{Time}} [{{"WARN"|yellow}} ]` +
`{{if .System}}({{.System|cyan}}){{end}} ` +
`{{.Message}}` +
`{{if .Fields}} {{.Fields|json|green}}{{end}}{{"\n"}}`
DEFAULT_INFO = `{{Time}} [{{"INFO"|blue}} ]` +
`{{if .System}}({{.System|cyan}}){{end}} ` +
`{{.Message}}` +
`{{if .Fields}} {{.Fields|json|green}}{{end}}{{"\n"}}`
2021-11-01 14:38:30 +00:00
)
type LogFormater struct {
ErrTmplStr string
WarnTmplStr string
InfoTmplStr string
DebugTmplStr string
}
type H map[string]interface{}
type Ldata struct {
Message string
System string
// Caller only evaluates in DEBUG, and ERROR calls
Caller string
// Stack only eval when !PROD and {DEBUG, ERROR}
Stack string
Fields H
Color bool
}
2021-11-01 18:07:05 +00:00
type Logger struct {
2021-11-01 14:38:30 +00:00
system string
color bool
2021-11-02 07:26:10 +00:00
explicit bool
2021-11-01 14:38:30 +00:00
err io.Writer
out io.Writer
2021-11-01 14:41:11 +00:00
formatter *LogFormater
2021-11-01 16:50:15 +00:00
funcMap template.FuncMap
2021-11-01 14:38:30 +00:00
err_tmpl *template.Template
2021-11-01 14:41:11 +00:00
debug_tmpl *template.Template
2021-11-01 14:38:30 +00:00
warn_tmpl *template.Template
info_tmpl *template.Template
2021-11-02 03:08:23 +00:00
subs []*Logger
2021-11-01 14:38:30 +00:00
}
2021-11-02 03:08:23 +00:00
func New(name string) *Logger {
2021-11-01 18:07:05 +00:00
l := &Logger{
2021-11-02 03:08:23 +00:00
system: name,
2021-11-01 14:41:11 +00:00
err: os.Stderr,
out: os.Stdout,
color: true,
formatter: NewLogFormater(),
2021-11-01 14:38:30 +00:00
}
2021-11-01 16:50:49 +00:00
l.Reload()
2021-11-01 14:38:30 +00:00
return l
}
2021-11-01 18:07:05 +00:00
func (l *Logger) Sub(sys string) *Logger {
ret := &Logger{
2021-11-01 14:41:11 +00:00
system: sys,
err: l.err,
out: l.out,
color: l.color,
formatter: l.formatter,
err_tmpl: l.err_tmpl,
debug_tmpl: l.debug_tmpl,
warn_tmpl: l.warn_tmpl,
info_tmpl: l.info_tmpl,
}
2021-11-02 03:08:23 +00:00
if l.subs == nil {
l.subs = make([]*Logger, 0)
}
l.subs = append(l.subs, ret)
2021-11-01 14:41:11 +00:00
return ret
}
2021-11-01 18:07:05 +00:00
func (l *Logger) guessColor() {
2021-11-01 16:50:15 +00:00
l.color = true
2021-11-01 14:38:30 +00:00
if w, ok := l.out.(*os.File); !ok || os.Getenv("TERM") == "dumb" ||
(!isatty.IsTerminal(w.Fd()) && !isatty.IsCygwinTerminal(w.Fd())) {
l.color = false
}
2021-11-01 16:50:15 +00:00
if w, ok := l.err.(*os.File); !ok || os.Getenv("TERM") == "dumb" ||
(!isatty.IsTerminal(w.Fd()) && !isatty.IsCygwinTerminal(w.Fd())) {
l.color = false
}
2021-11-01 14:38:30 +00:00
}
2021-11-01 18:07:05 +00:00
func (l *Logger) SetColor(c bool) {
2021-11-02 07:26:10 +00:00
l.explicit = true
2021-11-01 14:38:30 +00:00
l.color = c
}
2021-11-02 07:26:10 +00:00
func (l *Logger) SetColorAll(c bool) {
for _, v := range getAllOffsprings(l) {
v.SetColor(c)
}
}
2021-11-01 18:07:05 +00:00
func (l *Logger) SetErrOutput(err io.Writer) {
2021-11-01 16:50:15 +00:00
l.err = err
}
2021-11-02 03:08:23 +00:00
func (l *Logger) SetErrOutputAll(err io.Writer) {
for _, v := range getAllOffsprings(l) {
v.err = err
}
}
2021-11-01 18:07:05 +00:00
func (l *Logger) SetOutput(out io.Writer) {
2021-11-01 16:50:15 +00:00
l.out = out
}
2021-11-02 03:08:23 +00:00
func (l *Logger) SetOutputAll(out io.Writer) {
for _, v := range getAllOffsprings(l) {
v.out = out
}
}
2021-11-01 18:07:05 +00:00
func (l *Logger) Reload() error {
2021-11-02 07:26:10 +00:00
if !l.explicit {
l.guessColor()
}
2021-11-01 16:50:15 +00:00
return l.ParseTmpl()
}
2021-11-02 03:08:23 +00:00
func (l *Logger) ReloadAll() error {
for _, v := range getAllOffsprings(l) {
if err := v.Reload(); err != nil {
return err
}
}
return nil
}
2021-11-01 14:38:30 +00:00
func NewLogFormater() *LogFormater {
return &LogFormater{
ErrTmplStr: DEFAULT_ERR,
WarnTmplStr: DEFAULT_WARN,
InfoTmplStr: DEFAULT_INFO,
DebugTmplStr: DEFAULT_DEBUG,
}
}
2021-11-01 18:07:05 +00:00
func (l *Logger) DefaultFuncMap() template.FuncMap {
2021-11-01 14:38:30 +00:00
funcMap := template.FuncMap{
2021-11-01 14:41:11 +00:00
"Time": func() string { return time.Now().Format("2006/01/02 15:04:05") },
2021-11-03 05:51:59 +00:00
"json": func(i interface{}) (string, error) { r, err := json.Marshal(i); return string(r), err },
2021-11-01 14:41:11 +00:00
}
return funcMap
}
2021-11-01 18:07:05 +00:00
func (l *Logger) ParseTmpl() error {
2021-11-01 16:50:15 +00:00
if l.funcMap == nil {
l.funcMap = l.DefaultFuncMap()
}
2021-11-02 03:08:23 +00:00
funcMap := copyFuncMap(l.funcMap)
2021-11-03 05:51:59 +00:00
l.setColorMap(funcMap)
2021-11-02 03:08:23 +00:00
err_tmpl, err := template.New("err_tmpl").Funcs(funcMap).Parse(l.formatter.ErrTmplStr)
2021-11-01 14:38:30 +00:00
if err != nil {
return err
}
l.err_tmpl = err_tmpl
2021-11-02 03:08:23 +00:00
warn_tmpl, err := template.New("warn_tmpl").Funcs(funcMap).Parse(l.formatter.WarnTmplStr)
2021-11-01 14:41:11 +00:00
if err != nil {
return err
}
l.warn_tmpl = warn_tmpl
2021-11-02 03:08:23 +00:00
info_tmpl, err := template.New("info_tmpl").Funcs(funcMap).Parse(l.formatter.InfoTmplStr)
2021-11-01 14:41:11 +00:00
if err != nil {
return err
}
l.info_tmpl = info_tmpl
2021-11-02 03:08:23 +00:00
debug_tmpl, err := template.New("debug_tmpl").Funcs(funcMap).Parse(l.formatter.DebugTmplStr)
2021-11-01 14:41:11 +00:00
if err != nil {
return err
}
l.debug_tmpl = debug_tmpl
2021-11-01 14:38:30 +00:00
return nil
}
2021-11-01 18:07:05 +00:00
func (l *Logger) SetTmpl(formatter *LogFormater, funcMap template.FuncMap) {
2021-11-01 14:41:11 +00:00
l.formatter = formatter
2021-11-01 16:50:15 +00:00
if funcMap != nil {
l.funcMap = funcMap
}
2021-11-01 14:41:11 +00:00
}
2021-11-01 18:07:05 +00:00
func (l *Logger) output(t tout, depth int, stack string, fields H, v ...interface{}) {
2021-11-01 14:41:11 +00:00
msg := fmt.Sprint(v...)
2021-11-01 14:38:30 +00:00
data := Ldata{
Fields: fields,
Message: msg,
System: l.system,
Caller: caller(depth),
Color: l.color,
Stack: stack,
}
2021-11-02 07:26:10 +00:00
lock.Lock()
defer lock.Unlock()
2021-11-01 14:41:11 +00:00
var err error
switch t {
case terror:
2021-11-01 16:18:20 +00:00
if LEVEL&Lerror == 0 {
return
}
2021-11-01 14:41:11 +00:00
err = l.err_tmpl.Execute(l.err, data)
case tdebug:
2021-11-01 16:18:20 +00:00
if LEVEL&Ldebug == 0 {
return
}
2021-11-01 14:41:11 +00:00
err = l.debug_tmpl.Execute(l.err, data)
case twarn:
2021-11-01 16:18:20 +00:00
if LEVEL&Lwarn == 0 {
return
}
2021-11-01 14:41:11 +00:00
err = l.warn_tmpl.Execute(l.out, data)
case tinfo:
2021-11-01 16:18:20 +00:00
if LEVEL&Linfo == 0 {
return
}
2021-11-01 14:41:11 +00:00
err = l.info_tmpl.Execute(l.out, data)
}
2021-11-01 14:38:30 +00:00
if err != nil {
2021-11-01 18:07:05 +00:00
fmt.Fprintln(l.err, "[FATAL] Logger error:", err)
2021-11-01 14:38:30 +00:00
panic(err)
}
}
2021-11-01 18:07:05 +00:00
func (l *Logger) ErrorF(fields H, v ...interface{}) {
2021-11-01 14:41:11 +00:00
if PROD {
l.output(terror, 3, "", fields, v...)
} else {
l.output(terror, 3, stack(), fields, v...)
2021-11-01 14:38:30 +00:00
}
}
2021-11-01 18:07:05 +00:00
func (l *Logger) Error(v ...interface{}) {
2021-11-01 14:41:11 +00:00
if PROD {
l.output(terror, 3, "", H{}, v...)
} else {
l.output(terror, 3, stack(), H{}, v...)
2021-11-01 14:38:30 +00:00
}
}
2021-11-01 18:07:05 +00:00
func (l *Logger) DebugF(fields H, v ...interface{}) {
2021-11-01 14:41:11 +00:00
if PROD {
l.output(tdebug, 3, "", fields, v...)
} else {
l.output(tdebug, 3, stack(), fields, v...)
2021-11-01 14:38:30 +00:00
}
}
2021-11-01 18:07:05 +00:00
func (l *Logger) Debug(v ...interface{}) {
2021-11-01 14:41:11 +00:00
if PROD {
l.output(tdebug, 3, "", H{}, v...)
} else {
l.output(tdebug, 3, stack(), H{}, v...)
2021-11-01 14:38:30 +00:00
}
}
2021-11-01 14:41:11 +00:00
2021-11-01 18:07:05 +00:00
func (l *Logger) WarnF(fields H, v ...interface{}) {
2021-11-01 14:41:11 +00:00
l.output(twarn, 3, "", fields, v...)
}
2021-11-01 18:07:05 +00:00
func (l *Logger) Warn(v ...interface{}) {
2021-11-01 14:41:11 +00:00
l.output(twarn, 3, "", H{}, v...)
}
2021-11-01 18:07:05 +00:00
func (l *Logger) InfoF(fields H, v ...interface{}) {
2021-11-01 14:41:11 +00:00
l.output(tinfo, 3, "", fields, v...)
}
2021-11-01 18:07:05 +00:00
func (l *Logger) Info(v ...interface{}) {
2021-11-01 14:41:11 +00:00
l.output(tinfo, 3, "", H{}, v...)
}