a3ef049df9
It's not necessary to enclose in quotes every single string value in log2met format; when using basic words, it's possible to not quote it (as heroku does for its own logging). This keeps the logs easier on the human eye.
109 lines
2.2 KiB
Go
109 lines
2.2 KiB
Go
package logrus
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"regexp"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
nocolor = 0
|
|
red = 31
|
|
green = 32
|
|
yellow = 33
|
|
blue = 34
|
|
)
|
|
|
|
var (
|
|
baseTimestamp time.Time
|
|
isTerminal bool
|
|
noQuoteNeeded *regexp.Regexp
|
|
)
|
|
|
|
func init() {
|
|
baseTimestamp = time.Now()
|
|
isTerminal = IsTerminal()
|
|
noQuoteNeeded, _ = regexp.Compile("^[a-zA-Z0-9.-]*$")
|
|
}
|
|
|
|
func miniTS() int {
|
|
return int(time.Since(baseTimestamp) / time.Second)
|
|
}
|
|
|
|
type TextFormatter struct {
|
|
// Set to true to bypass checking for a TTY before outputting colors.
|
|
ForceColors bool
|
|
DisableColors bool
|
|
}
|
|
|
|
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
|
|
|
var keys []string
|
|
for k := range entry.Data {
|
|
keys = append(keys, k)
|
|
}
|
|
sort.Strings(keys)
|
|
|
|
b := &bytes.Buffer{}
|
|
|
|
prefixFieldClashes(entry)
|
|
|
|
isColored := (f.ForceColors || isTerminal) && !f.DisableColors
|
|
|
|
if isColored {
|
|
printColored(b, entry, keys)
|
|
} else {
|
|
f.appendKeyValue(b, "time", entry.Time.Format(time.RFC3339))
|
|
f.appendKeyValue(b, "level", entry.Level.String())
|
|
f.appendKeyValue(b, "msg", entry.Message)
|
|
for _, key := range keys {
|
|
f.appendKeyValue(b, key, entry.Data[key])
|
|
}
|
|
}
|
|
|
|
b.WriteByte('\n')
|
|
return b.Bytes(), nil
|
|
}
|
|
|
|
func printColored(b *bytes.Buffer, entry *Entry, keys []string) {
|
|
var levelColor int
|
|
switch entry.Level {
|
|
case WarnLevel:
|
|
levelColor = yellow
|
|
case ErrorLevel, FatalLevel, PanicLevel:
|
|
levelColor = red
|
|
default:
|
|
levelColor = blue
|
|
}
|
|
|
|
levelText := strings.ToUpper(entry.Level.String())[0:4]
|
|
|
|
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message)
|
|
for _, k := range keys {
|
|
v := entry.Data[k]
|
|
fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=%v", levelColor, k, v)
|
|
}
|
|
}
|
|
|
|
func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key, value interface{}) {
|
|
switch value.(type) {
|
|
case string:
|
|
if noQuoteNeeded.MatchString(value.(string)) {
|
|
fmt.Fprintf(b, "%v=%s ", key, value)
|
|
} else {
|
|
fmt.Fprintf(b, "%v=%q ", key, value)
|
|
}
|
|
case error:
|
|
if noQuoteNeeded.MatchString(value.(error).Error()) {
|
|
fmt.Fprintf(b, "%v=%s ", key, value)
|
|
} else {
|
|
fmt.Fprintf(b, "%v=%q ", key, value)
|
|
}
|
|
default:
|
|
fmt.Fprintf(b, "%v=%v ", key, value)
|
|
}
|
|
}
|