176 lines
3.7 KiB
Go
176 lines
3.7 KiB
Go
package log
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"runtime"
|
|
"text/template"
|
|
"time"
|
|
|
|
"github.com/mattn/go-isatty"
|
|
)
|
|
|
|
const (
|
|
Lerror = 1 << iota
|
|
Lwarn
|
|
Linfo
|
|
Ldebug
|
|
)
|
|
|
|
var PROD = true
|
|
var LEVEL = Lerror | Linfo
|
|
|
|
const (
|
|
DEFAULT_ERR = `{{Time}} [{{red}}ERROR{{reset}}]({{cyan}}{{.System}}{{reset}}) {{.Caller}} {{.Message}}{{if .Fields}}{{printf "%v\n" .Fields}}{{end}}{{if .Stack}}{{redl}}{{.Stack}}{{reset}}{{end}}`
|
|
DEFAULT_DEBUG = `{{Time}} [{{magenta}}DEBUG{{reset}}]({{cyan}}{{.System}}{{reset}}) {{.Caller}} {{.Message}}{{if .Fields}}{{printf "%v\n" .Fields}}{{end}}{{if .Stack}}{{.Stack}}{{end}}`
|
|
DEFAULT_WARN = `{{Time}} [{{yellow}}WARN {{reset}}]({{cyan}}{{.System}}{{reset}}) {{.Message}}{{if .Fields}}{{printf "%v\n" .Fields}}{{end}}`
|
|
DEFAULT_INFO = `{{Time}} [{{blue}}INFO {{reset}}]({{cyan}}{{.System}}{{reset}}) {{.Message}}{{if .Fields}}{{printf "%v\n" .Fields}}{{end}}`
|
|
)
|
|
|
|
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
|
|
}
|
|
|
|
type logger struct {
|
|
system string
|
|
color bool
|
|
|
|
err io.Writer
|
|
out io.Writer
|
|
|
|
err_tmpl *template.Template
|
|
warn_tmpl *template.Template
|
|
info_tmpl *template.Template
|
|
debug_tmpl *template.Template
|
|
}
|
|
|
|
func New() *logger {
|
|
l := &logger{
|
|
err: os.Stderr,
|
|
out: os.Stdout,
|
|
color: true,
|
|
}
|
|
l.guessColor()
|
|
l.SetTmpl(NewLogFormater())
|
|
return l
|
|
}
|
|
|
|
func (l *logger) guessColor() {
|
|
if w, ok := l.out.(*os.File); !ok || os.Getenv("TERM") == "dumb" ||
|
|
(!isatty.IsTerminal(w.Fd()) && !isatty.IsCygwinTerminal(w.Fd())) {
|
|
l.color = false
|
|
}
|
|
}
|
|
func (l *logger) SetColor(c bool) {
|
|
l.color = c
|
|
}
|
|
|
|
func NewLogFormater() *LogFormater {
|
|
return &LogFormater{
|
|
ErrTmplStr: DEFAULT_ERR,
|
|
WarnTmplStr: DEFAULT_WARN,
|
|
InfoTmplStr: DEFAULT_INFO,
|
|
DebugTmplStr: DEFAULT_DEBUG,
|
|
}
|
|
}
|
|
|
|
func (l *logger) SetTmpl(tmpl *LogFormater) error {
|
|
funcMap := template.FuncMap{
|
|
"Time": func() string { return time.Now().Format("2006/01/02 15:04:05") },
|
|
// "red": func() string { return "\033[91m" },
|
|
// "redl": func() string { return "\033[31m" },
|
|
// "green": func() string { return "\033[92m" },
|
|
// "yellow": func() string { return "\033[93m" },
|
|
// "blue": func() string { return "\033[94m" },
|
|
// "magenta": func() string { return "\033[95m" },
|
|
// "cyan": func() string { return "\033[96m" },
|
|
// "white": func() string { return "\033[97m" },
|
|
// "reset": func() string { return "\033[0m" },
|
|
}
|
|
if l.color {
|
|
|
|
}
|
|
err_tmpl, err := template.New("err_tmpl").Funcs(funcMap).Parse(tmpl.ErrTmplStr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
l.err_tmpl = err_tmpl
|
|
return nil
|
|
}
|
|
|
|
func (l *logger) error(depth int, stack string, fields H, v ...interface{}) {
|
|
msg := fmt.Sprintln(v...)
|
|
data := Ldata{
|
|
Fields: fields,
|
|
Message: msg,
|
|
System: l.system,
|
|
Caller: caller(depth),
|
|
Color: l.color,
|
|
Stack: stack,
|
|
}
|
|
err := l.err_tmpl.Execute(os.Stdout, data)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
}
|
|
|
|
func (l *logger) ErrorF(fields H, v ...interface{}) {
|
|
stak := ""
|
|
if !PROD {
|
|
stak = stack()
|
|
}
|
|
l.error(3, stak, fields, v...)
|
|
}
|
|
|
|
func (l *logger) Error(v ...interface{}) {
|
|
stak := ""
|
|
if !PROD {
|
|
stak = stack()
|
|
}
|
|
l.error(3, stak, H{}, v...)
|
|
}
|
|
|
|
func caller(depth int) string {
|
|
_, file, line, _ := runtime.Caller(depth)
|
|
short := file
|
|
for i := len(file) - 1; i > 0; i-- {
|
|
if file[i] == '/' {
|
|
short = file[i+1:]
|
|
break
|
|
}
|
|
}
|
|
return fmt.Sprintf("%s:%d", short, line)
|
|
}
|
|
|
|
func stack() string {
|
|
buf := make([]byte, 1024)
|
|
for {
|
|
n := runtime.Stack(buf, false)
|
|
if n < len(buf) {
|
|
return string(buf[:n])
|
|
}
|
|
buf = make([]byte, 2*len(buf))
|
|
}
|
|
}
|