235 lines
5.8 KiB
Go
235 lines
5.8 KiB
Go
package formatters
|
|
|
|
import (
|
|
"fmt"
|
|
_ "reflect"
|
|
"sort"
|
|
"strings"
|
|
|
|
"codeark.it/Bithero-Agency-Go/logfrog-go"
|
|
)
|
|
|
|
const (
|
|
Ldate = 1 << iota
|
|
Ltime
|
|
Lmicroseconds
|
|
Llongfile
|
|
Lshortfile
|
|
Lfuncname
|
|
Lshortfuncname
|
|
LUTC
|
|
Llevelinitial
|
|
Llevel
|
|
|
|
LstdFlags = Ldate | Ltime | Lshortfile | Lshortfuncname | Llevelinitial
|
|
)
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
type TextFormatterStyles struct {
|
|
DateTimeStyle []CliOption
|
|
FileStyle []CliOption
|
|
CallerStyle []CliOption
|
|
LogLevelStyles map[logfrog.LogLevel][]CliOption
|
|
}
|
|
|
|
func (s TextFormatterStyles) GetLogLevelStyle(level logfrog.LogLevel) []CliOption {
|
|
attrs, ok := s.LogLevelStyles[level]
|
|
if ok {
|
|
return attrs
|
|
}
|
|
return ColorForLevel(level)
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
type TextFormatter struct {
|
|
*logfrog.BaseLogFormatter
|
|
|
|
Colorize bool
|
|
Flags int
|
|
Styles *TextFormatterStyles
|
|
}
|
|
|
|
var defaultStyles = &TextFormatterStyles{
|
|
DateTimeStyle: []CliOption{ FgCyan },
|
|
FileStyle: []CliOption{ FgGreen },
|
|
CallerStyle: []CliOption{ FgGreen },
|
|
}
|
|
|
|
func NewTextFormatter(colorize bool, flags int) *TextFormatter {
|
|
b := logfrog.NewBaseLogFormatter()
|
|
t := &TextFormatter{ b, colorize, flags, defaultStyles }
|
|
b.LogFormatter = t
|
|
return t
|
|
}
|
|
|
|
func NewTextFormatterWithStyles(colorize bool, flags int, styles *TextFormatterStyles) *TextFormatter {
|
|
t := &TextFormatter{ nil, colorize, flags, styles }
|
|
t.LogFormatter = t
|
|
return t
|
|
}
|
|
|
|
func (formatter *TextFormatter) formatFields(r *logfrog.LogRecord, buf *[]byte) {
|
|
if r.Fields != nil {
|
|
*buf = append(*buf, (" [")...)
|
|
|
|
keys := make([]string, 0)
|
|
for k := range r.Fields {
|
|
keys = append(keys, k)
|
|
}
|
|
|
|
sort.Strings(keys)
|
|
|
|
for i, k := range keys {
|
|
if (i != 0) {
|
|
*buf = append(*buf, ' ')
|
|
}
|
|
|
|
if formatter.Colorize {
|
|
*buf = AppendColors(*buf, formatter.Styles.GetLogLevelStyle(r.Level)...)
|
|
}
|
|
|
|
*buf = append(*buf, k...)
|
|
|
|
if formatter.Colorize {
|
|
*buf = AppendColors(*buf, Reset)
|
|
}
|
|
|
|
*buf = append(*buf, '=')
|
|
|
|
val := fmt.Sprintf("%v", r.Fields[k])
|
|
*buf = append(*buf, val...)
|
|
}
|
|
|
|
*buf = append(*buf, ']')
|
|
}
|
|
}
|
|
|
|
func (formatter *TextFormatter) Format(r *logfrog.LogRecord) ([]byte, error) {
|
|
var buf []byte
|
|
|
|
if formatter.Flags&(Ldate|Ltime|Lmicroseconds) != 0 {
|
|
if formatter.Colorize {
|
|
buf = AppendColors(buf, formatter.Styles.DateTimeStyle...)
|
|
}
|
|
|
|
t := r.Created
|
|
if formatter.Flags&LUTC != 0 {
|
|
t = t.UTC()
|
|
}
|
|
|
|
if formatter.Flags&Ldate != 0 {
|
|
year, month, day := t.Date()
|
|
itoa(&buf, year, 4)
|
|
buf = append(buf, '/')
|
|
itoa(&buf, int(month), 2)
|
|
buf = append(buf, '/')
|
|
itoa(&buf, day, 2)
|
|
buf = append(buf, ' ')
|
|
}
|
|
if formatter.Flags&(Ltime|Lmicroseconds) != 0 {
|
|
hour, min, sec := t.Clock()
|
|
itoa(&buf, hour, 2)
|
|
buf = append(buf, ':')
|
|
itoa(&buf, int(min), 2)
|
|
buf = append(buf, ':')
|
|
itoa(&buf, sec, 2)
|
|
if formatter.Flags&(Lmicroseconds) != 0 {
|
|
buf = append(buf, '.')
|
|
itoa(&buf, t.Nanosecond() / 1e3, 6)
|
|
}
|
|
buf = append(buf, ' ')
|
|
}
|
|
|
|
if formatter.Colorize {
|
|
buf = AppendColors(buf, Reset)
|
|
}
|
|
}
|
|
|
|
if formatter.Flags&(Lshortfile|Llongfile) != 0 && r.Caller != nil {
|
|
if formatter.Colorize {
|
|
buf = AppendColors(buf, formatter.Styles.FileStyle...)
|
|
}
|
|
|
|
file := r.Caller.File
|
|
if formatter.Flags&Lshortfile != 0 {
|
|
idx := strings.LastIndexByte(file, '/')
|
|
if idx > 0 && idx < len(file) {
|
|
file = file[idx+1:]
|
|
}
|
|
}
|
|
|
|
buf = append(buf, file...)
|
|
buf = append(buf, ':')
|
|
itoa(&buf, r.Caller.Line, -1)
|
|
if formatter.Flags&(Lfuncname|Lshortfuncname) != 0 {
|
|
buf = append(buf, ':')
|
|
} else {
|
|
buf = append(buf, ' ')
|
|
}
|
|
|
|
if formatter.Colorize {
|
|
buf = AppendColors(buf, Reset)
|
|
}
|
|
}
|
|
|
|
if formatter.Flags&(Lfuncname|Lshortfuncname) != 0 {
|
|
if formatter.Colorize {
|
|
buf = AppendColors(buf, formatter.Styles.CallerStyle...)
|
|
}
|
|
|
|
name := r.Caller.Funcname
|
|
if formatter.Flags&Lshortfuncname != 0 {
|
|
idx := strings.LastIndexByte(name, '.')
|
|
if idx > 0 && idx < len(name) {
|
|
name = name[idx+1:]
|
|
}
|
|
}
|
|
|
|
buf = append(buf, name...)
|
|
|
|
if formatter.Colorize {
|
|
buf = AppendColors(buf, Reset)
|
|
}
|
|
|
|
buf = append(buf, ' ')
|
|
}
|
|
|
|
if formatter.Flags&(Llevel|Llevelinitial) != 0 {
|
|
if formatter.Colorize {
|
|
buf = AppendColors(buf, formatter.Styles.GetLogLevelStyle(r.Level)...)
|
|
}
|
|
|
|
buf = append(buf, '[')
|
|
level := strings.ToUpper(r.Level.String())
|
|
if formatter.Flags&Llevelinitial != 0 {
|
|
buf = append(buf, level[0])
|
|
} else {
|
|
buf = append(buf, level...)
|
|
}
|
|
|
|
buf = append(buf, ']')
|
|
|
|
if formatter.Colorize {
|
|
buf = AppendColors(buf, Reset)
|
|
}
|
|
|
|
buf = append(buf, ' ')
|
|
}
|
|
|
|
msg := []byte(r.Message)
|
|
if len(msg) > 0 && msg[len(msg)-1] == '\n' {
|
|
msg = msg[:len(msg)-1]
|
|
}
|
|
|
|
// TODO: remove all escape sequenced from the message!
|
|
buf = append(buf, msg...)
|
|
|
|
formatter.formatFields(r, &buf)
|
|
|
|
// TODO: add stacktrace if needed
|
|
|
|
buf = append(buf, '\n')
|
|
return buf, nil
|
|
} |