bilibili-backup/library/log/pattern.go
2019-04-22 02:59:20 +00:00

168 lines
3.3 KiB
Go

package log
import (
"bytes"
"fmt"
"io"
"path"
"runtime"
"strings"
"sync"
"time"
)
var patternMap = map[string]func(map[string]interface{}) string{
"T": longTime,
"t": shortTime,
"D": longDate,
"d": shortDate,
"L": keyFactory(_level),
"f": keyFactory(_source),
"i": keyFactory(_instanceID),
"e": keyFactory(_deplyEnv),
"z": keyFactory(_zone),
"S": longSource,
"s": shortSource,
"M": message,
}
// newPatternRender new pattern render
func newPatternRender(format string) Render {
p := &pattern{
bufPool: sync.Pool{New: func() interface{} { return &bytes.Buffer{} }},
}
b := make([]byte, 0, len(format))
for i := 0; i < len(format); i++ {
if format[i] != '%' {
b = append(b, format[i])
continue
}
if i+1 >= len(format) {
b = append(b, format[i])
continue
}
f, ok := patternMap[string(format[i+1])]
if !ok {
b = append(b, format[i])
continue
}
if len(b) != 0 {
p.funcs = append(p.funcs, textFactory(string(b)))
b = b[:0]
}
p.funcs = append(p.funcs, f)
i++
}
if len(b) != 0 {
p.funcs = append(p.funcs, textFactory(string(b)))
}
return p
}
type pattern struct {
funcs []func(map[string]interface{}) string
bufPool sync.Pool
}
// Render implemet Formater
func (p *pattern) Render(w io.Writer, d map[string]interface{}) error {
buf := p.bufPool.Get().(*bytes.Buffer)
defer func() {
buf.Reset()
p.bufPool.Put(buf)
}()
for _, f := range p.funcs {
buf.WriteString(f(d))
}
_, err := buf.WriteTo(w)
return err
}
// Render implemet Formater as string
func (p *pattern) RenderString(d map[string]interface{}) string {
// TODO strings.Builder
buf := p.bufPool.Get().(*bytes.Buffer)
defer func() {
buf.Reset()
p.bufPool.Put(buf)
}()
for _, f := range p.funcs {
buf.WriteString(f(d))
}
return buf.String()
}
func textFactory(text string) func(map[string]interface{}) string {
return func(map[string]interface{}) string {
return text
}
}
func keyFactory(key string) func(map[string]interface{}) string {
return func(d map[string]interface{}) string {
if v, ok := d[key]; ok {
if s, ok := v.(string); ok {
return s
}
return fmt.Sprint(v)
}
return ""
}
}
func longSource(map[string]interface{}) string {
if _, file, lineNo, ok := runtime.Caller(6); ok {
return fmt.Sprintf("%s:%d", file, lineNo)
}
return "unknown:0"
}
func shortSource(map[string]interface{}) string {
if _, file, lineNo, ok := runtime.Caller(6); ok {
return fmt.Sprintf("%s:%d", path.Base(file), lineNo)
}
return "unknown:0"
}
func longTime(map[string]interface{}) string {
return time.Now().Format("15:04:05.000")
}
func shortTime(map[string]interface{}) string {
return time.Now().Format("15:04")
}
func longDate(map[string]interface{}) string {
return time.Now().Format("2006/01/02")
}
func shortDate(map[string]interface{}) string {
return time.Now().Format("01/02")
}
func isInternalKey(k string) bool {
switch k {
case _level, _levelValue, _time, _source, _instanceID, _appID, _deplyEnv, _zone:
return true
}
return false
}
func message(d map[string]interface{}) string {
var m string
var s []string
for k, v := range d {
if k == _log {
m = fmt.Sprint(v)
continue
}
if isInternalKey(k) {
continue
}
s = append(s, fmt.Sprintf("%s=%v", k, v))
}
s = append(s, m)
return strings.Join(s, " ")
}