From 0e3a40c587234630b2adba701ec7b7bc3b2b5047 Mon Sep 17 00:00:00 2001 From: Evan Chen Date: Mon, 1 Nov 2021 22:38:30 +0800 Subject: [PATCH] update --- README.md | 0 color.go | 65 ++++++++++++++++++++ go.mod | 8 +++ go.sum | 4 ++ log.go | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++++ log_test.go | 21 +++++++ 6 files changed, 270 insertions(+) create mode 100644 README.md create mode 100644 color.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 log.go create mode 100644 log_test.go diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/color.go b/color.go new file mode 100644 index 0000000..ce515b3 --- /dev/null +++ b/color.go @@ -0,0 +1,65 @@ +package log + +type Attribute int + +// Base attributes +const ( + Reset Attribute = iota + Bold + Faint + Italic + Underline + BlinkSlow + BlinkRapid + ReverseVideo + Concealed + CrossedOut +) + +// Foreground text colors +const ( + FgBlack Attribute = iota + 30 + FgRed + FgGreen + FgYellow + FgBlue + FgMagenta + FgCyan + FgWhite +) + +// Foreground Hi-Intensity text colors +const ( + FgHiBlack Attribute = iota + 90 + FgHiRed + FgHiGreen + FgHiYellow + FgHiBlue + FgHiMagenta + FgHiCyan + FgHiWhite +) + +// Background text colors +const ( + BgBlack Attribute = iota + 40 + BgRed + BgGreen + BgYellow + BgBlue + BgMagenta + BgCyan + BgWhite +) + +// Background Hi-Intensity text colors +const ( + BgHiBlack Attribute = iota + 100 + BgHiRed + BgHiGreen + BgHiYellow + BgHiBlue + BgHiMagenta + BgHiCyan + BgHiWhite +) diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..4d6c830 --- /dev/null +++ b/go.mod @@ -0,0 +1,8 @@ +module kumoly.io/core/log + +go 1.17 + +require ( + github.com/mattn/go-isatty v0.0.14 // indirect + golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..cb37ebd --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/log.go b/log.go new file mode 100644 index 0000000..47ea0a9 --- /dev/null +++ b/log.go @@ -0,0 +1,172 @@ +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" }, + } + 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)) + } +} diff --git a/log_test.go b/log_test.go new file mode 100644 index 0000000..8e85ffa --- /dev/null +++ b/log_test.go @@ -0,0 +1,21 @@ +package log + +import "testing" + +func TestError(t *testing.T) { + PROD = false + log := New() + log.system = "test" + log.Error("d", "sdf", "sdfsdf") + + log.ErrorF(H{"Test": "set"}, "d", "sdf", "sdfsdf") +} + +func TestErrorProd(t *testing.T) { + PROD = true + log := New() + log.system = "test" + log.Error("d", "sdf", "sdfsdf") + + log.ErrorF(H{"Test": "set"}, "d", "sdf", "sdfsdf") +}