update
commit
0e3a40c587
|
@ -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
|
||||
)
|
|
@ -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
|
||||
)
|
|
@ -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=
|
|
@ -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))
|
||||
}
|
||||
}
|
|
@ -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")
|
||||
}
|
Loading…
Reference in New Issue