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