1
0
Fork 0

Colored logs on windows.

This commit is contained in:
Ludovic Fernandez 2018-10-02 16:28:04 +02:00 committed by Traefiker Bot
parent f04813fa02
commit 4cb1ae4626
17 changed files with 427 additions and 121 deletions

View file

@ -41,14 +41,14 @@ type Entry struct {
// Message passed to Debug, Info, Warn, Error, Fatal or Panic
Message string
// When formatter is called in entry.log(), an Buffer may be set to entry
// When formatter is called in entry.log(), a Buffer may be set to entry
Buffer *bytes.Buffer
}
func NewEntry(logger *Logger) *Entry {
return &Entry{
Logger: logger,
// Default is three fields, give a little extra room
// Default is five fields, give a little extra room
Data: make(Fields, 5),
}
}
@ -83,43 +83,41 @@ func (entry *Entry) WithFields(fields Fields) *Entry {
for k, v := range fields {
data[k] = v
}
return &Entry{Logger: entry.Logger, Data: data}
return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time}
}
// Overrides the time of the Entry.
func (entry *Entry) WithTime(t time.Time) *Entry {
return &Entry{Logger: entry.Logger, Data: entry.Data, Time: t}
}
// This function is not declared with a pointer value because otherwise
// race conditions will occur when using multiple goroutines
func (entry Entry) log(level Level, msg string) {
var buffer *bytes.Buffer
entry.Time = time.Now()
// Default to now, but allow users to override if they want.
//
// We don't have to worry about polluting future calls to Entry#log()
// with this assignment because this function is declared with a
// non-pointer receiver.
if entry.Time.IsZero() {
entry.Time = time.Now()
}
entry.Level = level
entry.Message = msg
entry.Logger.mu.Lock()
err := entry.Logger.Hooks.Fire(level, &entry)
entry.Logger.mu.Unlock()
if err != nil {
entry.Logger.mu.Lock()
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
entry.Logger.mu.Unlock()
}
entry.fireHooks()
buffer = bufferPool.Get().(*bytes.Buffer)
buffer.Reset()
defer bufferPool.Put(buffer)
entry.Buffer = buffer
serialized, err := entry.Logger.Formatter.Format(&entry)
entry.write()
entry.Buffer = nil
if err != nil {
entry.Logger.mu.Lock()
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
entry.Logger.mu.Unlock()
} else {
entry.Logger.mu.Lock()
_, err = entry.Logger.Out.Write(serialized)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
}
entry.Logger.mu.Unlock()
}
// To avoid Entry#log() returning a value that only would make sense for
// panic() to use in Entry#Panic(), we avoid the allocation by checking
@ -129,8 +127,31 @@ func (entry Entry) log(level Level, msg string) {
}
}
func (entry *Entry) fireHooks() {
entry.Logger.mu.Lock()
defer entry.Logger.mu.Unlock()
err := entry.Logger.Hooks.Fire(entry.Level, entry)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
}
}
func (entry *Entry) write() {
entry.Logger.mu.Lock()
defer entry.Logger.mu.Unlock()
serialized, err := entry.Logger.Formatter.Format(entry)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
} else {
_, err = entry.Logger.Out.Write(serialized)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
}
}
}
func (entry *Entry) Debug(args ...interface{}) {
if entry.Logger.level() >= DebugLevel {
if entry.Logger.IsLevelEnabled(DebugLevel) {
entry.log(DebugLevel, fmt.Sprint(args...))
}
}
@ -140,13 +161,13 @@ func (entry *Entry) Print(args ...interface{}) {
}
func (entry *Entry) Info(args ...interface{}) {
if entry.Logger.level() >= InfoLevel {
if entry.Logger.IsLevelEnabled(InfoLevel) {
entry.log(InfoLevel, fmt.Sprint(args...))
}
}
func (entry *Entry) Warn(args ...interface{}) {
if entry.Logger.level() >= WarnLevel {
if entry.Logger.IsLevelEnabled(WarnLevel) {
entry.log(WarnLevel, fmt.Sprint(args...))
}
}
@ -156,20 +177,20 @@ func (entry *Entry) Warning(args ...interface{}) {
}
func (entry *Entry) Error(args ...interface{}) {
if entry.Logger.level() >= ErrorLevel {
if entry.Logger.IsLevelEnabled(ErrorLevel) {
entry.log(ErrorLevel, fmt.Sprint(args...))
}
}
func (entry *Entry) Fatal(args ...interface{}) {
if entry.Logger.level() >= FatalLevel {
if entry.Logger.IsLevelEnabled(FatalLevel) {
entry.log(FatalLevel, fmt.Sprint(args...))
}
Exit(1)
}
func (entry *Entry) Panic(args ...interface{}) {
if entry.Logger.level() >= PanicLevel {
if entry.Logger.IsLevelEnabled(PanicLevel) {
entry.log(PanicLevel, fmt.Sprint(args...))
}
panic(fmt.Sprint(args...))
@ -178,13 +199,13 @@ func (entry *Entry) Panic(args ...interface{}) {
// Entry Printf family functions
func (entry *Entry) Debugf(format string, args ...interface{}) {
if entry.Logger.level() >= DebugLevel {
if entry.Logger.IsLevelEnabled(DebugLevel) {
entry.Debug(fmt.Sprintf(format, args...))
}
}
func (entry *Entry) Infof(format string, args ...interface{}) {
if entry.Logger.level() >= InfoLevel {
if entry.Logger.IsLevelEnabled(InfoLevel) {
entry.Info(fmt.Sprintf(format, args...))
}
}
@ -194,7 +215,7 @@ func (entry *Entry) Printf(format string, args ...interface{}) {
}
func (entry *Entry) Warnf(format string, args ...interface{}) {
if entry.Logger.level() >= WarnLevel {
if entry.Logger.IsLevelEnabled(WarnLevel) {
entry.Warn(fmt.Sprintf(format, args...))
}
}
@ -204,20 +225,20 @@ func (entry *Entry) Warningf(format string, args ...interface{}) {
}
func (entry *Entry) Errorf(format string, args ...interface{}) {
if entry.Logger.level() >= ErrorLevel {
if entry.Logger.IsLevelEnabled(ErrorLevel) {
entry.Error(fmt.Sprintf(format, args...))
}
}
func (entry *Entry) Fatalf(format string, args ...interface{}) {
if entry.Logger.level() >= FatalLevel {
if entry.Logger.IsLevelEnabled(FatalLevel) {
entry.Fatal(fmt.Sprintf(format, args...))
}
Exit(1)
}
func (entry *Entry) Panicf(format string, args ...interface{}) {
if entry.Logger.level() >= PanicLevel {
if entry.Logger.IsLevelEnabled(PanicLevel) {
entry.Panic(fmt.Sprintf(format, args...))
}
}
@ -225,13 +246,13 @@ func (entry *Entry) Panicf(format string, args ...interface{}) {
// Entry Println family functions
func (entry *Entry) Debugln(args ...interface{}) {
if entry.Logger.level() >= DebugLevel {
if entry.Logger.IsLevelEnabled(DebugLevel) {
entry.Debug(entry.sprintlnn(args...))
}
}
func (entry *Entry) Infoln(args ...interface{}) {
if entry.Logger.level() >= InfoLevel {
if entry.Logger.IsLevelEnabled(InfoLevel) {
entry.Info(entry.sprintlnn(args...))
}
}
@ -241,7 +262,7 @@ func (entry *Entry) Println(args ...interface{}) {
}
func (entry *Entry) Warnln(args ...interface{}) {
if entry.Logger.level() >= WarnLevel {
if entry.Logger.IsLevelEnabled(WarnLevel) {
entry.Warn(entry.sprintlnn(args...))
}
}
@ -251,20 +272,20 @@ func (entry *Entry) Warningln(args ...interface{}) {
}
func (entry *Entry) Errorln(args ...interface{}) {
if entry.Logger.level() >= ErrorLevel {
if entry.Logger.IsLevelEnabled(ErrorLevel) {
entry.Error(entry.sprintlnn(args...))
}
}
func (entry *Entry) Fatalln(args ...interface{}) {
if entry.Logger.level() >= FatalLevel {
if entry.Logger.IsLevelEnabled(FatalLevel) {
entry.Fatal(entry.sprintlnn(args...))
}
Exit(1)
}
func (entry *Entry) Panicln(args ...interface{}) {
if entry.Logger.level() >= PanicLevel {
if entry.Logger.IsLevelEnabled(PanicLevel) {
entry.Panic(entry.sprintlnn(args...))
}
}

View file

@ -2,6 +2,7 @@ package logrus
import (
"io"
"time"
)
var (
@ -15,37 +16,32 @@ func StandardLogger() *Logger {
// SetOutput sets the standard logger output.
func SetOutput(out io.Writer) {
std.mu.Lock()
defer std.mu.Unlock()
std.Out = out
std.SetOutput(out)
}
// SetFormatter sets the standard logger formatter.
func SetFormatter(formatter Formatter) {
std.mu.Lock()
defer std.mu.Unlock()
std.Formatter = formatter
std.SetFormatter(formatter)
}
// SetLevel sets the standard logger level.
func SetLevel(level Level) {
std.mu.Lock()
defer std.mu.Unlock()
std.SetLevel(level)
}
// GetLevel returns the standard logger level.
func GetLevel() Level {
std.mu.Lock()
defer std.mu.Unlock()
return std.level()
return std.GetLevel()
}
// IsLevelEnabled checks if the log level of the standard logger is greater than the level param
func IsLevelEnabled(level Level) bool {
return std.IsLevelEnabled(level)
}
// AddHook adds a hook to the standard logger hooks.
func AddHook(hook Hook) {
std.mu.Lock()
defer std.mu.Unlock()
std.Hooks.Add(hook)
std.AddHook(hook)
}
// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key.
@ -72,6 +68,15 @@ func WithFields(fields Fields) *Entry {
return std.WithFields(fields)
}
// WithTime creats an entry from the standard logger and overrides the time of
// logs generated with it.
//
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
// or Panic on the Entry it returns.
func WithTime(t time.Time) *Entry {
return std.WithTime(t)
}
// Debug logs a message at level Debug on the standard logger.
func Debug(args ...interface{}) {
std.Debug(args...)
@ -107,7 +112,7 @@ func Panic(args ...interface{}) {
std.Panic(args...)
}
// Fatal logs a message at level Fatal on the standard logger.
// Fatal logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
func Fatal(args ...interface{}) {
std.Fatal(args...)
}
@ -147,7 +152,7 @@ func Panicf(format string, args ...interface{}) {
std.Panicf(format, args...)
}
// Fatalf logs a message at level Fatal on the standard logger.
// Fatalf logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
func Fatalf(format string, args ...interface{}) {
std.Fatalf(format, args...)
}
@ -187,7 +192,7 @@ func Panicln(args ...interface{}) {
std.Panicln(args...)
}
// Fatalln logs a message at level Fatal on the standard logger.
// Fatalln logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
func Fatalln(args ...interface{}) {
std.Fatalln(args...)
}

View file

@ -30,16 +30,22 @@ type Formatter interface {
//
// It's not exported because it's still using Data in an opinionated way. It's to
// avoid code duplication between the two default formatters.
func prefixFieldClashes(data Fields) {
if t, ok := data["time"]; ok {
data["fields.time"] = t
func prefixFieldClashes(data Fields, fieldMap FieldMap) {
timeKey := fieldMap.resolve(FieldKeyTime)
if t, ok := data[timeKey]; ok {
data["fields."+timeKey] = t
delete(data, timeKey)
}
if m, ok := data["msg"]; ok {
data["fields.msg"] = m
msgKey := fieldMap.resolve(FieldKeyMsg)
if m, ok := data[msgKey]; ok {
data["fields."+msgKey] = m
delete(data, msgKey)
}
if l, ok := data["level"]; ok {
data["fields.level"] = l
levelKey := fieldMap.resolve(FieldKeyLevel)
if l, ok := data[levelKey]; ok {
data["fields."+levelKey] = l
delete(data, levelKey)
}
}

View file

@ -1,6 +1,7 @@
package logrus
import (
"bytes"
"encoding/json"
"fmt"
)
@ -33,6 +34,9 @@ type JSONFormatter struct {
// DisableTimestamp allows disabling automatic timestamps in output
DisableTimestamp bool
// DataKey allows users to put all the log entry parameters into a nested dictionary at a given key.
DataKey string
// FieldMap allows users to customize the names of keys for default fields.
// As an example:
// formatter := &JSONFormatter{
@ -43,6 +47,9 @@ type JSONFormatter struct {
// },
// }
FieldMap FieldMap
// PrettyPrint will indent all json logs
PrettyPrint bool
}
// Format renders a single log entry
@ -58,7 +65,14 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
data[k] = v
}
}
prefixFieldClashes(data)
if f.DataKey != "" {
newData := make(Fields, 4)
newData[f.DataKey] = data
data = newData
}
prefixFieldClashes(data, f.FieldMap)
timestampFormat := f.TimestampFormat
if timestampFormat == "" {
@ -71,9 +85,20 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message
data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String()
serialized, err := json.Marshal(data)
if err != nil {
var b *bytes.Buffer
if entry.Buffer != nil {
b = entry.Buffer
} else {
b = &bytes.Buffer{}
}
encoder := json.NewEncoder(b)
if f.PrettyPrint {
encoder.SetIndent("", " ")
}
if err := encoder.Encode(data); err != nil {
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
}
return append(serialized, '\n'), nil
return b.Bytes(), nil
}

View file

@ -5,12 +5,13 @@ import (
"os"
"sync"
"sync/atomic"
"time"
)
type Logger struct {
// The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
// file, or leave it default which is `os.Stderr`. You can also set this to
// something more adventorous, such as logging to Kafka.
// something more adventurous, such as logging to Kafka.
Out io.Writer
// Hooks for the logger instance. These allow firing events based on logging
// levels and log entries. For example, to send errors to an error tracking
@ -84,11 +85,12 @@ func (logger *Logger) newEntry() *Entry {
}
func (logger *Logger) releaseEntry(entry *Entry) {
entry.Data = map[string]interface{}{}
logger.entryPool.Put(entry)
}
// Adds a field to the log entry, note that it doesn't log until you call
// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry.
// Debug, Print, Info, Warn, Error, Fatal or Panic. It only creates a log entry.
// If you want multiple fields, use `WithFields`.
func (logger *Logger) WithField(key string, value interface{}) *Entry {
entry := logger.newEntry()
@ -112,8 +114,15 @@ func (logger *Logger) WithError(err error) *Entry {
return entry.WithError(err)
}
// Overrides the time of the log entry.
func (logger *Logger) WithTime(t time.Time) *Entry {
entry := logger.newEntry()
defer logger.releaseEntry(entry)
return entry.WithTime(t)
}
func (logger *Logger) Debugf(format string, args ...interface{}) {
if logger.level() >= DebugLevel {
if logger.IsLevelEnabled(DebugLevel) {
entry := logger.newEntry()
entry.Debugf(format, args...)
logger.releaseEntry(entry)
@ -121,7 +130,7 @@ func (logger *Logger) Debugf(format string, args ...interface{}) {
}
func (logger *Logger) Infof(format string, args ...interface{}) {
if logger.level() >= InfoLevel {
if logger.IsLevelEnabled(InfoLevel) {
entry := logger.newEntry()
entry.Infof(format, args...)
logger.releaseEntry(entry)
@ -135,7 +144,7 @@ func (logger *Logger) Printf(format string, args ...interface{}) {
}
func (logger *Logger) Warnf(format string, args ...interface{}) {
if logger.level() >= WarnLevel {
if logger.IsLevelEnabled(WarnLevel) {
entry := logger.newEntry()
entry.Warnf(format, args...)
logger.releaseEntry(entry)
@ -143,7 +152,7 @@ func (logger *Logger) Warnf(format string, args ...interface{}) {
}
func (logger *Logger) Warningf(format string, args ...interface{}) {
if logger.level() >= WarnLevel {
if logger.IsLevelEnabled(WarnLevel) {
entry := logger.newEntry()
entry.Warnf(format, args...)
logger.releaseEntry(entry)
@ -151,7 +160,7 @@ func (logger *Logger) Warningf(format string, args ...interface{}) {
}
func (logger *Logger) Errorf(format string, args ...interface{}) {
if logger.level() >= ErrorLevel {
if logger.IsLevelEnabled(ErrorLevel) {
entry := logger.newEntry()
entry.Errorf(format, args...)
logger.releaseEntry(entry)
@ -159,7 +168,7 @@ func (logger *Logger) Errorf(format string, args ...interface{}) {
}
func (logger *Logger) Fatalf(format string, args ...interface{}) {
if logger.level() >= FatalLevel {
if logger.IsLevelEnabled(FatalLevel) {
entry := logger.newEntry()
entry.Fatalf(format, args...)
logger.releaseEntry(entry)
@ -168,7 +177,7 @@ func (logger *Logger) Fatalf(format string, args ...interface{}) {
}
func (logger *Logger) Panicf(format string, args ...interface{}) {
if logger.level() >= PanicLevel {
if logger.IsLevelEnabled(PanicLevel) {
entry := logger.newEntry()
entry.Panicf(format, args...)
logger.releaseEntry(entry)
@ -176,7 +185,7 @@ func (logger *Logger) Panicf(format string, args ...interface{}) {
}
func (logger *Logger) Debug(args ...interface{}) {
if logger.level() >= DebugLevel {
if logger.IsLevelEnabled(DebugLevel) {
entry := logger.newEntry()
entry.Debug(args...)
logger.releaseEntry(entry)
@ -184,7 +193,7 @@ func (logger *Logger) Debug(args ...interface{}) {
}
func (logger *Logger) Info(args ...interface{}) {
if logger.level() >= InfoLevel {
if logger.IsLevelEnabled(InfoLevel) {
entry := logger.newEntry()
entry.Info(args...)
logger.releaseEntry(entry)
@ -198,7 +207,7 @@ func (logger *Logger) Print(args ...interface{}) {
}
func (logger *Logger) Warn(args ...interface{}) {
if logger.level() >= WarnLevel {
if logger.IsLevelEnabled(WarnLevel) {
entry := logger.newEntry()
entry.Warn(args...)
logger.releaseEntry(entry)
@ -206,7 +215,7 @@ func (logger *Logger) Warn(args ...interface{}) {
}
func (logger *Logger) Warning(args ...interface{}) {
if logger.level() >= WarnLevel {
if logger.IsLevelEnabled(WarnLevel) {
entry := logger.newEntry()
entry.Warn(args...)
logger.releaseEntry(entry)
@ -214,7 +223,7 @@ func (logger *Logger) Warning(args ...interface{}) {
}
func (logger *Logger) Error(args ...interface{}) {
if logger.level() >= ErrorLevel {
if logger.IsLevelEnabled(ErrorLevel) {
entry := logger.newEntry()
entry.Error(args...)
logger.releaseEntry(entry)
@ -222,7 +231,7 @@ func (logger *Logger) Error(args ...interface{}) {
}
func (logger *Logger) Fatal(args ...interface{}) {
if logger.level() >= FatalLevel {
if logger.IsLevelEnabled(FatalLevel) {
entry := logger.newEntry()
entry.Fatal(args...)
logger.releaseEntry(entry)
@ -231,7 +240,7 @@ func (logger *Logger) Fatal(args ...interface{}) {
}
func (logger *Logger) Panic(args ...interface{}) {
if logger.level() >= PanicLevel {
if logger.IsLevelEnabled(PanicLevel) {
entry := logger.newEntry()
entry.Panic(args...)
logger.releaseEntry(entry)
@ -239,7 +248,7 @@ func (logger *Logger) Panic(args ...interface{}) {
}
func (logger *Logger) Debugln(args ...interface{}) {
if logger.level() >= DebugLevel {
if logger.IsLevelEnabled(DebugLevel) {
entry := logger.newEntry()
entry.Debugln(args...)
logger.releaseEntry(entry)
@ -247,7 +256,7 @@ func (logger *Logger) Debugln(args ...interface{}) {
}
func (logger *Logger) Infoln(args ...interface{}) {
if logger.level() >= InfoLevel {
if logger.IsLevelEnabled(InfoLevel) {
entry := logger.newEntry()
entry.Infoln(args...)
logger.releaseEntry(entry)
@ -261,7 +270,7 @@ func (logger *Logger) Println(args ...interface{}) {
}
func (logger *Logger) Warnln(args ...interface{}) {
if logger.level() >= WarnLevel {
if logger.IsLevelEnabled(WarnLevel) {
entry := logger.newEntry()
entry.Warnln(args...)
logger.releaseEntry(entry)
@ -269,7 +278,7 @@ func (logger *Logger) Warnln(args ...interface{}) {
}
func (logger *Logger) Warningln(args ...interface{}) {
if logger.level() >= WarnLevel {
if logger.IsLevelEnabled(WarnLevel) {
entry := logger.newEntry()
entry.Warnln(args...)
logger.releaseEntry(entry)
@ -277,7 +286,7 @@ func (logger *Logger) Warningln(args ...interface{}) {
}
func (logger *Logger) Errorln(args ...interface{}) {
if logger.level() >= ErrorLevel {
if logger.IsLevelEnabled(ErrorLevel) {
entry := logger.newEntry()
entry.Errorln(args...)
logger.releaseEntry(entry)
@ -285,7 +294,7 @@ func (logger *Logger) Errorln(args ...interface{}) {
}
func (logger *Logger) Fatalln(args ...interface{}) {
if logger.level() >= FatalLevel {
if logger.IsLevelEnabled(FatalLevel) {
entry := logger.newEntry()
entry.Fatalln(args...)
logger.releaseEntry(entry)
@ -294,7 +303,7 @@ func (logger *Logger) Fatalln(args ...interface{}) {
}
func (logger *Logger) Panicln(args ...interface{}) {
if logger.level() >= PanicLevel {
if logger.IsLevelEnabled(PanicLevel) {
entry := logger.newEntry()
entry.Panicln(args...)
logger.releaseEntry(entry)
@ -312,12 +321,47 @@ func (logger *Logger) level() Level {
return Level(atomic.LoadUint32((*uint32)(&logger.Level)))
}
// SetLevel sets the logger level.
func (logger *Logger) SetLevel(level Level) {
atomic.StoreUint32((*uint32)(&logger.Level), uint32(level))
}
// GetLevel returns the logger level.
func (logger *Logger) GetLevel() Level {
return logger.level()
}
// AddHook adds a hook to the logger hooks.
func (logger *Logger) AddHook(hook Hook) {
logger.mu.Lock()
defer logger.mu.Unlock()
logger.Hooks.Add(hook)
}
// IsLevelEnabled checks if the log level of the logger is greater than the level param
func (logger *Logger) IsLevelEnabled(level Level) bool {
return logger.level() >= level
}
// SetFormatter sets the logger formatter.
func (logger *Logger) SetFormatter(formatter Formatter) {
logger.mu.Lock()
defer logger.mu.Unlock()
logger.Formatter = formatter
}
// SetOutput sets the logger output.
func (logger *Logger) SetOutput(output io.Writer) {
logger.mu.Lock()
defer logger.mu.Unlock()
logger.Out = output
}
// ReplaceHooks replaces the logger hooks and returns the old ones
func (logger *Logger) ReplaceHooks(hooks LevelHooks) LevelHooks {
logger.mu.Lock()
oldHooks := logger.Hooks
logger.Hooks = hooks
logger.mu.Unlock()
return oldHooks
}

View file

@ -140,4 +140,11 @@ type FieldLogger interface {
Errorln(args ...interface{})
Fatalln(args ...interface{})
Panicln(args ...interface{})
// IsDebugEnabled() bool
// IsInfoEnabled() bool
// IsWarnEnabled() bool
// IsErrorEnabled() bool
// IsFatalEnabled() bool
// IsPanicEnabled() bool
}

View file

@ -0,0 +1,13 @@
// Based on ssh/terminal:
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build appengine
package logrus
import "io"
func initTerminal(w io.Writer) {
}

View file

@ -1,10 +1,17 @@
// +build darwin freebsd openbsd netbsd dragonfly
// +build !appengine
// +build !appengine,!js
package logrus
import "golang.org/x/sys/unix"
import (
"io"
"golang.org/x/sys/unix"
)
const ioctlReadTermios = unix.TIOCGETA
type Termios unix.Termios
func initTerminal(w io.Writer) {
}

11
vendor/github.com/sirupsen/logrus/terminal_check_js.go generated vendored Normal file
View file

@ -0,0 +1,11 @@
// +build js
package logrus
import (
"io"
)
func checkIfTerminal(w io.Writer) bool {
return false
}

View file

@ -1,4 +1,4 @@
// +build !appengine
// +build !appengine,!js,!windows
package logrus

View file

@ -0,0 +1,20 @@
// +build !appengine,!js,windows
package logrus
import (
"io"
"os"
"syscall"
)
func checkIfTerminal(w io.Writer) bool {
switch v := w.(type) {
case *os.File:
var mode uint32
err := syscall.GetConsoleMode(syscall.Handle(v.Fd()), &mode)
return err == nil
default:
return false
}
}

View file

@ -3,12 +3,19 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !appengine
// +build !appengine,!js
package logrus
import "golang.org/x/sys/unix"
import (
"io"
"golang.org/x/sys/unix"
)
const ioctlReadTermios = unix.TCGETS
type Termios unix.Termios
func initTerminal(w io.Writer) {
}

18
vendor/github.com/sirupsen/logrus/terminal_windows.go generated vendored Normal file
View file

@ -0,0 +1,18 @@
// +build !appengine,!js,windows
package logrus
import (
"io"
"os"
"syscall"
sequences "github.com/konsorten/go-windows-terminal-sequences"
)
func initTerminal(w io.Writer) {
switch v := w.(type) {
case *os.File:
sequences.EnableVirtualTerminalProcessing(syscall.Handle(v.Fd()), true)
}
}

View file

@ -3,6 +3,7 @@ package logrus
import (
"bytes"
"fmt"
"os"
"sort"
"strings"
"sync"
@ -20,6 +21,7 @@ const (
var (
baseTimestamp time.Time
emptyFieldMap FieldMap
)
func init() {
@ -34,6 +36,9 @@ type TextFormatter struct {
// Force disabling colors.
DisableColors bool
// Override coloring based on CLICOLOR and CLICOLOR_FORCE. - https://bixense.com/clicolors/
EnvironmentOverrideColors bool
// Disable timestamp logging. useful when output is redirected to logging
// system that already adds timestamps.
DisableTimestamp bool
@ -50,60 +55,119 @@ type TextFormatter struct {
// be desired.
DisableSorting bool
// The keys sorting function, when uninitialized it uses sort.Strings.
SortingFunc func([]string)
// Disables the truncation of the level text to 4 characters.
DisableLevelTruncation bool
// QuoteEmptyFields will wrap empty fields in quotes if true
QuoteEmptyFields bool
// Whether the logger's out is to a terminal
isTerminal bool
sync.Once
// FieldMap allows users to customize the names of keys for default fields.
// As an example:
// formatter := &TextFormatter{
// FieldMap: FieldMap{
// FieldKeyTime: "@timestamp",
// FieldKeyLevel: "@level",
// FieldKeyMsg: "@message"}}
FieldMap FieldMap
terminalInitOnce sync.Once
}
func (f *TextFormatter) init(entry *Entry) {
if entry.Logger != nil {
f.isTerminal = checkIfTerminal(entry.Logger.Out)
if f.isTerminal {
initTerminal(entry.Logger.Out)
}
}
}
func (f *TextFormatter) isColored() bool {
isColored := f.ForceColors || f.isTerminal
if f.EnvironmentOverrideColors {
if force, ok := os.LookupEnv("CLICOLOR_FORCE"); ok && force != "0" {
isColored = true
} else if ok && force == "0" {
isColored = false
} else if os.Getenv("CLICOLOR") == "0" {
isColored = false
}
}
return isColored && !f.DisableColors
}
// Format renders a single log entry
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
var b *bytes.Buffer
prefixFieldClashes(entry.Data, f.FieldMap)
keys := make([]string, 0, len(entry.Data))
for k := range entry.Data {
keys = append(keys, k)
}
if !f.DisableSorting {
sort.Strings(keys)
fixedKeys := make([]string, 0, 3+len(entry.Data))
if !f.DisableTimestamp {
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyTime))
}
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLevel))
if entry.Message != "" {
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyMsg))
}
if !f.DisableSorting {
if f.SortingFunc == nil {
sort.Strings(keys)
fixedKeys = append(fixedKeys, keys...)
} else {
if !f.isColored() {
fixedKeys = append(fixedKeys, keys...)
f.SortingFunc(fixedKeys)
} else {
f.SortingFunc(keys)
}
}
} else {
fixedKeys = append(fixedKeys, keys...)
}
var b *bytes.Buffer
if entry.Buffer != nil {
b = entry.Buffer
} else {
b = &bytes.Buffer{}
}
prefixFieldClashes(entry.Data)
f.Do(func() { f.init(entry) })
isColored := (f.ForceColors || f.isTerminal) && !f.DisableColors
f.terminalInitOnce.Do(func() { f.init(entry) })
timestampFormat := f.TimestampFormat
if timestampFormat == "" {
timestampFormat = defaultTimestampFormat
}
if isColored {
if f.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])
for _, key := range fixedKeys {
var value interface{}
switch key {
case f.FieldMap.resolve(FieldKeyTime):
value = entry.Time.Format(timestampFormat)
case f.FieldMap.resolve(FieldKeyLevel):
value = entry.Level.String()
case f.FieldMap.resolve(FieldKeyMsg):
value = entry.Message
default:
value = entry.Data[key]
}
f.appendKeyValue(b, key, value)
}
}
@ -124,7 +188,14 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin
levelColor = blue
}
levelText := strings.ToUpper(entry.Level.String())[0:4]
levelText := strings.ToUpper(entry.Level.String())
if !f.DisableLevelTruncation {
levelText = levelText[0:4]
}
// Remove a single newline if it already exists in the message to keep
// the behavior of logrus text_formatter the same as the stdlib log package
entry.Message = strings.TrimSuffix(entry.Message, "\n")
if f.DisableTimestamp {
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m %-44s ", levelColor, levelText, entry.Message)