1
0
mirror of https://github.com/imgproxy/imgproxy.git synced 2024-11-24 08:12:38 +02:00
imgproxy/log_formatter.go

156 lines
3.1 KiB
Go

package main
import (
"bytes"
"fmt"
"regexp"
"sort"
"strings"
"time"
"unicode/utf8"
logrus "github.com/sirupsen/logrus"
)
var (
logKeysPriorities = map[string]int{
"request_id": 3,
"method": 2,
"status": 1,
"error": -1,
"stack": -2,
}
logQuotingRe = regexp.MustCompile(`^[a-zA-Z0-9\-._/@^+]+$`)
)
type logKeys []string
func (p logKeys) Len() int { return len(p) }
func (p logKeys) Less(i, j int) bool { return logKeysPriorities[p[i]] > logKeysPriorities[p[j]] }
func (p logKeys) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
type logPrettyFormatter struct {
levelFormat string
}
func newLogPrettyFormatter() *logPrettyFormatter {
f := new(logPrettyFormatter)
levelLenMax := 0
for _, level := range logrus.AllLevels {
levelLen := utf8.RuneCount([]byte(level.String()))
if levelLen > levelLenMax {
levelLenMax = levelLen
}
}
f.levelFormat = fmt.Sprintf("%%-%ds", levelLenMax)
return f
}
func (f *logPrettyFormatter) Format(entry *logrus.Entry) ([]byte, error) {
keys := make([]string, 0, len(entry.Data))
for k := range entry.Data {
if k != "stack" {
keys = append(keys, k)
}
}
sort.Sort(logKeys(keys))
levelColor := 36
switch entry.Level {
case logrus.DebugLevel, logrus.TraceLevel:
levelColor = 37
case logrus.WarnLevel:
levelColor = 33
case logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel:
levelColor = 31
}
levelText := fmt.Sprintf(f.levelFormat, strings.ToUpper(entry.Level.String()))
msg := strings.TrimSuffix(entry.Message, "\n")
var b *bytes.Buffer
if entry.Buffer != nil {
b = entry.Buffer
} else {
b = new(bytes.Buffer)
}
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m [%s] %s ", levelColor, levelText, entry.Time.Format(time.RFC3339), msg)
for _, k := range keys {
v := entry.Data[k]
fmt.Fprintf(b, " \x1b[1m%s\x1b[0m=", k)
f.appendValue(b, v)
}
b.WriteByte('\n')
if stack, ok := entry.Data["stack"]; ok {
fmt.Fprintln(b, stack)
}
return b.Bytes(), nil
}
func (f *logPrettyFormatter) appendValue(b *bytes.Buffer, value interface{}) {
strValue, ok := value.(string)
if !ok {
strValue = fmt.Sprint(value)
}
if logQuotingRe.MatchString(strValue) {
b.WriteString(strValue)
} else {
fmt.Fprintf(b, "%q", strValue)
}
}
type logStructuredFormatter struct{}
func (f *logStructuredFormatter) Format(entry *logrus.Entry) ([]byte, error) {
keys := make([]string, 0, len(entry.Data))
for k := range entry.Data {
keys = append(keys, k)
}
sort.Sort(logKeys(keys))
msg := strings.TrimSuffix(entry.Message, "\n")
var b *bytes.Buffer
if entry.Buffer != nil {
b = entry.Buffer
} else {
b = new(bytes.Buffer)
}
f.appendKeyValue(b, "time", entry.Time.Format(time.RFC3339))
f.appendKeyValue(b, "level", entry.Level.String())
f.appendKeyValue(b, "message", msg)
for _, k := range keys {
f.appendKeyValue(b, k, entry.Data[k])
}
b.WriteByte('\n')
return b.Bytes(), nil
}
func (f *logStructuredFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) {
if b.Len() != 0 {
b.WriteByte(' ')
}
strValue, ok := value.(string)
if !ok {
strValue = fmt.Sprint(value)
}
fmt.Fprintf(b, "%s=%q", key, strValue)
}