forked from LaconicNetwork/kompose
This adds github.com/pkg/errors to glide.yaml followed by glide and glide-vc commands. The github.com/pkg/errors package is currently required mainly for the errors.Wrap() and errors.New() methods, since this lets us to annotate the errors while passing the error message up the call stack.
162 lines
3.5 KiB
Go
162 lines
3.5 KiB
Go
package logrus
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"runtime"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
nocolor = 0
|
|
red = 31
|
|
green = 32
|
|
yellow = 33
|
|
blue = 34
|
|
gray = 37
|
|
)
|
|
|
|
var (
|
|
baseTimestamp time.Time
|
|
isTerminal bool
|
|
)
|
|
|
|
func init() {
|
|
baseTimestamp = time.Now()
|
|
isTerminal = IsTerminal()
|
|
}
|
|
|
|
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
|
|
|
|
// Force disabling colors.
|
|
DisableColors bool
|
|
|
|
// Disable timestamp logging. useful when output is redirected to logging
|
|
// system that already adds timestamps.
|
|
DisableTimestamp bool
|
|
|
|
// Enable logging the full timestamp when a TTY is attached instead of just
|
|
// the time passed since beginning of execution.
|
|
FullTimestamp bool
|
|
|
|
// TimestampFormat to use for display when a full timestamp is printed
|
|
TimestampFormat string
|
|
|
|
// The fields are sorted by default for a consistent output. For applications
|
|
// that log extremely frequently and don't use the JSON formatter this may not
|
|
// be desired.
|
|
DisableSorting bool
|
|
}
|
|
|
|
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
|
var keys []string = make([]string, 0, len(entry.Data))
|
|
for k := range entry.Data {
|
|
keys = append(keys, k)
|
|
}
|
|
|
|
if !f.DisableSorting {
|
|
sort.Strings(keys)
|
|
}
|
|
|
|
b := &bytes.Buffer{}
|
|
|
|
prefixFieldClashes(entry.Data)
|
|
|
|
isColorTerminal := isTerminal && (runtime.GOOS != "windows")
|
|
isColored := (f.ForceColors || isColorTerminal) && !f.DisableColors
|
|
|
|
timestampFormat := f.TimestampFormat
|
|
if timestampFormat == "" {
|
|
timestampFormat = DefaultTimestampFormat
|
|
}
|
|
if isColored {
|
|
f.printColored(b, entry, keys, timestampFormat)
|
|
} else {
|
|
if !f.DisableTimestamp {
|
|
f.appendKeyValue(b, "time", entry.Time.Format(timestampFormat))
|
|
}
|
|
f.appendKeyValue(b, "level", entry.Level.String())
|
|
if entry.Message != "" {
|
|
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 (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, timestampFormat string) {
|
|
var levelColor int
|
|
switch entry.Level {
|
|
case DebugLevel:
|
|
levelColor = gray
|
|
case WarnLevel:
|
|
levelColor = yellow
|
|
case ErrorLevel, FatalLevel, PanicLevel:
|
|
levelColor = red
|
|
default:
|
|
levelColor = blue
|
|
}
|
|
|
|
levelText := strings.ToUpper(entry.Level.String())[0:4]
|
|
|
|
if !f.FullTimestamp {
|
|
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message)
|
|
} else {
|
|
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message)
|
|
}
|
|
for _, k := range keys {
|
|
v := entry.Data[k]
|
|
fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=%+v", levelColor, k, v)
|
|
}
|
|
}
|
|
|
|
func needsQuoting(text string) bool {
|
|
for _, ch := range text {
|
|
if !((ch >= 'a' && ch <= 'z') ||
|
|
(ch >= 'A' && ch <= 'Z') ||
|
|
(ch >= '0' && ch <= '9') ||
|
|
ch == '-' || ch == '.') {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) {
|
|
|
|
b.WriteString(key)
|
|
b.WriteByte('=')
|
|
|
|
switch value := value.(type) {
|
|
case string:
|
|
if needsQuoting(value) {
|
|
b.WriteString(value)
|
|
} else {
|
|
fmt.Fprintf(b, "%q", value)
|
|
}
|
|
case error:
|
|
errmsg := value.Error()
|
|
if needsQuoting(errmsg) {
|
|
b.WriteString(errmsg)
|
|
} else {
|
|
fmt.Fprintf(b, "%q", value)
|
|
}
|
|
default:
|
|
fmt.Fprint(b, value)
|
|
}
|
|
|
|
b.WriteByte(' ')
|
|
}
|