master
Evan Chen 2021-11-01 22:38:30 +08:00
commit 0e3a40c587
6 changed files with 270 additions and 0 deletions

0
README.md Normal file
View File

65
color.go Normal file
View File

@ -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
)

8
go.mod Normal file
View File

@ -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
)

4
go.sum Normal file
View File

@ -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=

172
log.go Normal file
View File

@ -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))
}
}

21
log_test.go Normal file
View File

@ -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")
}