kubekey/pkg/core/logger/formatter.go
24sama f4b7fd4605 dev-v2.0.0: add copyright
Signed-off-by: 24sama <leo@kubesphere.io>
2021-11-15 11:31:28 +08:00

205 lines
4.5 KiB
Go

/*
Copyright 2021 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package logger
import (
"bytes"
"fmt"
"github.com/sirupsen/logrus"
"runtime"
"sort"
"strings"
"time"
)
type Formatter struct {
// TimestampFormat - default: time.StampMilli = "Jan _2 15:04:05.000"
TimestampFormat string
// NoColors - disable colors
NoColors bool
// ShowLevel - when the level < this field, it won't be show. default: TRACE
ShowLevel logrus.Level
// ShowFullLevel - show a full level [WARNING] instead of [WARN]
ShowFullLevel bool
// NoUppercaseLevel - no upper case for level value
NoUppercaseLevel bool
// HideKeys - show [fieldValue] instead of [fieldKey:fieldValue]
HideKeys bool
// FieldsDisplayWithOrder - default: all fields display and sorted alphabetically
FieldsDisplayWithOrder []string
// CallerFirst - print caller info first
CallerFirst bool
// CustomCallerFormatter - set custom formatter for caller info
CustomCallerFormatter func(*runtime.Frame) string
}
func (f *Formatter) Format(entry *logrus.Entry) ([]byte, error) {
levelColor := getColorByLevel(entry.Level)
timestampFormat := f.TimestampFormat
if timestampFormat == "" {
timestampFormat = time.StampMilli
}
// output buffer
b := &bytes.Buffer{}
// write time
b.WriteString(entry.Time.Format(timestampFormat))
if f.CallerFirst {
f.writeCaller(b, entry)
}
if !f.NoColors {
fmt.Fprintf(b, "\x1b[%dm", levelColor)
}
level := entry.Level
if f.ShowLevel >= level {
var levelStr string
if f.NoUppercaseLevel {
levelStr = entry.Level.String()
} else {
levelStr = strings.ToUpper(entry.Level.String())
}
b.WriteString(" [")
if f.ShowFullLevel {
b.WriteString(levelStr)
} else {
b.WriteString(levelStr[:4])
}
b.WriteString("]")
}
b.WriteString(" ")
// write fields
if f.FieldsDisplayWithOrder == nil {
f.writeFields(b, entry)
} else {
f.writeOrderedFields(b, entry)
}
b.WriteString(entry.Message)
if !f.CallerFirst {
f.writeCaller(b, entry)
}
b.WriteByte('\n')
return b.Bytes(), nil
}
const (
colorRed = 31
colorYellow = 33
colorBlue = 36
colorGray = 37
)
func getColorByLevel(level logrus.Level) int {
switch level {
case logrus.DebugLevel, logrus.TraceLevel:
return colorGray
case logrus.WarnLevel:
return colorYellow
case logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel:
return colorRed
default:
return colorBlue
}
}
func (f *Formatter) writeFields(b *bytes.Buffer, entry *logrus.Entry) {
if len(entry.Data) != 0 {
fields := make([]string, 0, len(entry.Data))
for field := range entry.Data {
fields = append(fields, field)
}
sort.Strings(fields)
b.WriteString("[")
for i, field := range fields {
f.writeField(b, entry, field, i)
}
b.WriteString("]")
}
}
func (f *Formatter) writeOrderedFields(b *bytes.Buffer, entry *logrus.Entry) {
if len(entry.Data) != 0 {
b.WriteString("[")
length := len(entry.Data)
foundFieldsMap := map[string]bool{}
for i, field := range f.FieldsDisplayWithOrder {
if _, ok := entry.Data[field]; ok {
foundFieldsMap[field] = true
length--
f.writeField(b, entry, field, i)
}
}
if length > 0 {
notFoundFields := make([]string, 0, length)
for field := range entry.Data {
if foundFieldsMap[field] == false {
notFoundFields = append(notFoundFields, field)
}
}
sort.Strings(notFoundFields)
for i, field := range notFoundFields {
f.writeField(b, entry, field, i)
}
}
b.WriteString("]")
}
}
func (f *Formatter) writeField(b *bytes.Buffer, entry *logrus.Entry, field string, i int) {
if f.HideKeys {
fmt.Fprintf(b, "%v", entry.Data[field])
} else {
fmt.Fprintf(b, "%s:%v", field, entry.Data[field])
}
if i != len(entry.Data) && len(entry.Data) != 1 {
b.WriteString(" | ")
}
}
func (f *Formatter) writeCaller(b *bytes.Buffer, entry *logrus.Entry) {
if entry.HasCaller() {
if f.CustomCallerFormatter != nil {
fmt.Fprintf(b, f.CustomCallerFormatter(entry.Caller))
} else {
fmt.Fprintf(
b,
" (%s:%d %s)",
entry.Caller.File,
entry.Caller.Line,
entry.Caller.Function,
)
}
}
}