83 lines
1.7 KiB
Go
83 lines
1.7 KiB
Go
package log
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type Field func() (k string, v interface{})
|
|
|
|
func String(name string, value string) Field {
|
|
return func() (k string, v interface{}) {
|
|
return name, value
|
|
}
|
|
}
|
|
func Int(name string, value int) Field {
|
|
return func() (k string, v interface{}) {
|
|
return name, value
|
|
}
|
|
}
|
|
func Int64(name string, value int64) Field {
|
|
return func() (k string, v interface{}) {
|
|
return name, value
|
|
}
|
|
}
|
|
func Interface(name string, value interface{}) Field {
|
|
return func() (k string, v interface{}) {
|
|
return name, value
|
|
}
|
|
}
|
|
|
|
func Info(msg string, fields ...Field) {
|
|
std.Write("INFO", msg, fields...)
|
|
}
|
|
|
|
func Warn(msg string, fields ...Field) {
|
|
std.Write("WARN", msg, fields...)
|
|
}
|
|
|
|
func Error(msg string, err error, fields ...Field) {
|
|
if err != nil {
|
|
fields = append(fields, String("error", err.Error()))
|
|
}
|
|
std.Write("ERROR", msg, fields...)
|
|
}
|
|
|
|
type Logger struct {
|
|
stdout sync.Mutex
|
|
stderr sync.Mutex
|
|
enc json.Encoder
|
|
newLine []byte
|
|
}
|
|
|
|
func (s *Logger) Write(level string, msg string, fields ...Field) {
|
|
entry := make(map[string]interface{})
|
|
entry["time"] = time.Now().UTC().Format(time.RFC3339)
|
|
entry["level"] = level
|
|
entry["msg"] = msg
|
|
for i := 0; i < len(fields); i++ {
|
|
k, v := fields[i]()
|
|
entry[k] = v
|
|
}
|
|
j, err := json.Marshal(entry)
|
|
if err != nil {
|
|
j = []byte(fmt.Sprintf("log.Write: failed to marshal entry '%+v': %v", entry, err))
|
|
}
|
|
if level == "ERROR" {
|
|
s.stderr.Lock()
|
|
defer s.stderr.Unlock()
|
|
os.Stderr.Write(j)
|
|
os.Stderr.Write(s.newLine)
|
|
return
|
|
}
|
|
s.stdout.Lock()
|
|
defer s.stdout.Unlock()
|
|
os.Stdout.Write(j)
|
|
os.Stderr.Write(s.newLine)
|
|
}
|
|
|
|
var std = &Logger{newLine: []byte("\n")}
|