logfrog-go/formatters/text.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
}