bump docker/docker, sirupsen/logrus v1.4.1

Full diff: https://github.com/sirupsen/logrus/compare/v1.3.0...v1.4.1

Fixes:

- Remove dependency on golang.org/x/crypto
- Fix wrong method calls Logger.Print and Logger.Warningln
- Update Entry.Logf to not do string formatting unless the log level is enabled
- Fix infinite recursion on unknown Level.String()
- Fix race condition in getCaller
- Fix Entry.WithContext method to return a copy of the initial entry

New:

- Add DeferExitHandler, similar to RegisterExitHandler but prepending the handler to the list of handlers (semantically like defer)
- Add CallerPrettyfier to JSONFormatter and `TextFormatter`
- Add Entry.WithContext() and Entry.Context, to set a context on entries to be used e.g. in hooks
- Enhance TextFormatter to not print caller information when they are empty

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn 2019-04-04 17:46:51 +02:00
parent c500b534e7
commit dfc81eda9c
No known key found for this signature in database
GPG Key ID: 76698F39D527CE8C
14 changed files with 153 additions and 55 deletions

View File

@ -13,7 +13,7 @@ github.com/cpuguy83/go-md2man v1.0.8
github.com/davecgh/go-spew 346938d642f2ec3594ed81d874461961cd0faa76 # v1.1.0
github.com/dgrijalva/jwt-go a2c85815a77d0f951e33ba4db5ae93629a1530af
github.com/docker/distribution 0d3efadf0154c2b8a4e7b6621fff9809655cc580
github.com/docker/docker bcaa613d823afa461957e7ad17faade03d82656f
github.com/docker/docker dbe4a30928d418e0570891a09703bcbc0e4997a1
github.com/docker/compose-on-kubernetes v0.4.21
github.com/docker/docker-credential-helpers 5241b46610f2491efdf9d1c85f1ddf5b02f6d962
# the docker/go package contains a customized version of canonical/json
@ -67,7 +67,7 @@ github.com/prometheus/common 7600349dcfe1abd18d72d3a1770870d9800a7801
github.com/prometheus/procfs 7d6f385de8bea29190f15ba9931442a0eaef9af7
github.com/russross/blackfriday 1d6b8e9301e720b08a8938b8c25c018285885438
github.com/shurcooL/sanitized_anchor_name 10ef21a441db47d8b13ebcc5fd2310f636973c77
github.com/sirupsen/logrus v1.3.0
github.com/sirupsen/logrus 8bdbc7bcc01dcbb8ec23dc8a28e332258d25251f # v1.4.1
github.com/spf13/cobra v0.0.3
# temporary fork with https://github.com/spf13/pflag/pull/170 applied, which isn't merged yet upstream
github.com/spf13/pflag 4cb166e4f25ac4e8016a3595bbf7ea2e9aa85a2c https://github.com/thaJeztah/pflag.git

View File

@ -11,7 +11,7 @@ github.com/Microsoft/opengcs a10967154e143a36014584a6f664344e3bb0aa64
github.com/konsorten/go-windows-terminal-sequences v1.0.1
github.com/kr/pty 5cf931ef8f
github.com/mattn/go-shellwords v1.0.3
github.com/sirupsen/logrus v1.3.0
github.com/sirupsen/logrus 8bdbc7bcc01dcbb8ec23dc8a28e332258d25251f # v1.4.1
github.com/tchap/go-patricia v2.2.6
github.com/vdemeester/shakers 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3
golang.org/x/net a680a1efc54dd51c040b3b5ce4939ea3cf2ea0d1
@ -161,4 +161,4 @@ github.com/morikuni/aec 39771216ff4c63d11f5e604076f9c45e8be1067b
# metrics
github.com/docker/go-metrics d466d4f6fd960e01820085bd7e1a24426ee7ef18
github.com/opencontainers/selinux 9e2c5215628a2567782777efb2049f385484f918 # v1.2
github.com/opencontainers/selinux 0bb7b9fa9ba5c1120e9d22caed4961fca4228408 # v1.2.1

View File

@ -365,6 +365,7 @@ Third party logging formatters:
* [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events.
* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout.
* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
* [`nested-logrus-formatter`](https://github.com/antonfisher/nested-logrus-formatter). Converts logrus fields to a nested structure.
You can define your formatter by implementing the `Formatter` interface,
requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a

View File

@ -51,9 +51,9 @@ func Exit(code int) {
os.Exit(code)
}
// RegisterExitHandler adds a Logrus Exit handler, call logrus.Exit to invoke
// all handlers. The handlers will also be invoked when any Fatal log entry is
// made.
// RegisterExitHandler appends a Logrus Exit handler to the list of handlers,
// call logrus.Exit to invoke all handlers. The handlers will also be invoked when
// any Fatal log entry is made.
//
// This method is useful when a caller wishes to use logrus to log a fatal
// message but also needs to gracefully shutdown. An example usecase could be
@ -62,3 +62,15 @@ func Exit(code int) {
func RegisterExitHandler(handler func()) {
handlers = append(handlers, handler)
}
// DeferExitHandler prepends a Logrus Exit handler to the list of handlers,
// call logrus.Exit to invoke all handlers. The handlers will also be invoked when
// any Fatal log entry is made.
//
// This method is useful when a caller wishes to use logrus to log a fatal
// message but also needs to gracefully shutdown. An example usecase could be
// closing database connections, or sending a alert that the application is
// closing.
func DeferExitHandler(handler func()) {
handlers = append([]func(){handler}, handlers...)
}

View File

@ -2,6 +2,7 @@ package logrus
import (
"bytes"
"context"
"fmt"
"os"
"reflect"
@ -69,6 +70,9 @@ type Entry struct {
// When formatter is called in entry.log(), a Buffer may be set to entry
Buffer *bytes.Buffer
// Contains the context set by the user. Useful for hook processing etc.
Context context.Context
// err may contain a field formatting error
err string
}
@ -97,6 +101,11 @@ func (entry *Entry) WithError(err error) *Entry {
return entry.WithField(ErrorKey, err)
}
// Add a context to the Entry.
func (entry *Entry) WithContext(ctx context.Context) *Entry {
return &Entry{Logger: entry.Logger, Data: entry.Data, Time: entry.Time, err: entry.err, Context: ctx}
}
// Add a single field to the Entry.
func (entry *Entry) WithField(key string, value interface{}) *Entry {
return entry.WithFields(Fields{key: value})
@ -130,12 +139,12 @@ func (entry *Entry) WithFields(fields Fields) *Entry {
data[k] = v
}
}
return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, err: fieldErr}
return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, err: fieldErr, Context: entry.Context}
}
// Overrides the time of the Entry.
func (entry *Entry) WithTime(t time.Time) *Entry {
return &Entry{Logger: entry.Logger, Data: entry.Data, Time: t, err: entry.err}
return &Entry{Logger: entry.Logger, Data: entry.Data, Time: t, err: entry.err, Context: entry.Context}
}
// getPackageName reduces a fully qualified function name to the package name
@ -156,20 +165,23 @@ func getPackageName(f string) string {
// getCaller retrieves the name of the first non-logrus calling function
func getCaller() *runtime.Frame {
// cache this package's fully-qualified name
callerInitOnce.Do(func() {
pcs := make([]uintptr, 2)
_ = runtime.Callers(0, pcs)
logrusPackage = getPackageName(runtime.FuncForPC(pcs[1]).Name())
// now that we have the cache, we can skip a minimum count of known-logrus functions
// XXX this is dubious, the number of frames may vary
minimumCallerDepth = knownLogrusFrames
})
// Restrict the lookback frames to avoid runaway lookups
pcs := make([]uintptr, maximumCallerDepth)
depth := runtime.Callers(minimumCallerDepth, pcs)
frames := runtime.CallersFrames(pcs[:depth])
// cache this package's fully-qualified name
callerInitOnce.Do(func() {
logrusPackage = getPackageName(runtime.FuncForPC(pcs[0]).Name())
// now that we have the cache, we can skip a minimum count of known-logrus functions
// XXX this is dubious, the number of frames may vary store an entry in a logger interface
minimumCallerDepth = knownLogrusFrames
})
for f, again := frames.Next(); again; f, again = frames.Next() {
pkg := getPackageName(f.Function)
@ -298,7 +310,9 @@ func (entry *Entry) Panic(args ...interface{}) {
// Entry Printf family functions
func (entry *Entry) Logf(level Level, format string, args ...interface{}) {
entry.Log(level, fmt.Sprintf(format, args...))
if entry.Logger.IsLevelEnabled(level) {
entry.Log(level, fmt.Sprintf(format, args...))
}
}
func (entry *Entry) Tracef(format string, args ...interface{}) {

View File

@ -1,6 +1,7 @@
package logrus
import (
"context"
"io"
"time"
)
@ -55,6 +56,11 @@ func WithError(err error) *Entry {
return std.WithField(ErrorKey, err)
}
// WithContext creates an entry from the standard logger and adds a context to it.
func WithContext(ctx context.Context) *Entry {
return std.WithContext(ctx)
}
// WithField creates an entry from the standard logger and adds a field to
// it. If you want multiple fields, use `WithFields`.
//

View File

@ -4,6 +4,7 @@ import (
"bytes"
"encoding/json"
"fmt"
"runtime"
)
type fieldKey string
@ -42,6 +43,12 @@ type JSONFormatter struct {
// }
FieldMap FieldMap
// CallerPrettyfier can be set by the user to modify the content
// of the function and file keys in the json data when ReportCaller is
// activated. If any of the returned value is the empty string the
// corresponding key will be removed from json fields.
CallerPrettyfier func(*runtime.Frame) (function string, file string)
// PrettyPrint will indent all json logs
PrettyPrint bool
}
@ -82,8 +89,17 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message
data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String()
if entry.HasCaller() {
data[f.FieldMap.resolve(FieldKeyFunc)] = entry.Caller.Function
data[f.FieldMap.resolve(FieldKeyFile)] = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
funcVal := entry.Caller.Function
fileVal := fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
if f.CallerPrettyfier != nil {
funcVal, fileVal = f.CallerPrettyfier(entry.Caller)
}
if funcVal != "" {
data[f.FieldMap.resolve(FieldKeyFunc)] = funcVal
}
if fileVal != "" {
data[f.FieldMap.resolve(FieldKeyFile)] = fileVal
}
}
var b *bytes.Buffer
@ -98,7 +114,7 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
encoder.SetIndent("", " ")
}
if err := encoder.Encode(data); err != nil {
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
return nil, fmt.Errorf("failed to marshal fields to JSON, %v", err)
}
return b.Bytes(), nil

View File

@ -1,6 +1,7 @@
package logrus
import (
"context"
"io"
"os"
"sync"
@ -124,6 +125,13 @@ func (logger *Logger) WithError(err error) *Entry {
return entry.WithError(err)
}
// Add a context to the log entry.
func (logger *Logger) WithContext(ctx context.Context) *Entry {
entry := logger.newEntry()
defer logger.releaseEntry(entry)
return entry.WithContext(ctx)
}
// Overrides the time of the log entry.
func (logger *Logger) WithTime(t time.Time) *Entry {
entry := logger.newEntry()
@ -200,7 +208,7 @@ func (logger *Logger) Info(args ...interface{}) {
func (logger *Logger) Print(args ...interface{}) {
entry := logger.newEntry()
entry.Info(args...)
entry.Print(args...)
logger.releaseEntry(entry)
}
@ -256,7 +264,7 @@ func (logger *Logger) Warnln(args ...interface{}) {
}
func (logger *Logger) Warningln(args ...interface{}) {
logger.Warn(args...)
logger.Warnln(args...)
}
func (logger *Logger) Errorln(args ...interface{}) {

View File

@ -74,7 +74,7 @@ func (level Level) MarshalText() ([]byte, error) {
return []byte("panic"), nil
}
return nil, fmt.Errorf("not a valid lorus level %q", level)
return nil, fmt.Errorf("not a valid logrus level %d", level)
}
// A constant exposing all logging levels

View File

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

View File

@ -0,0 +1,13 @@
// +build darwin dragonfly freebsd netbsd openbsd
package logrus
import "golang.org/x/sys/unix"
const ioctlReadTermios = unix.TIOCGETA
func isTerminal(fd int) bool {
_, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
return err == nil
}

View File

@ -1,18 +1,16 @@
// +build !appengine,!js,!windows,!aix
// +build !appengine,!js,!windows
package logrus
import (
"io"
"os"
"golang.org/x/crypto/ssh/terminal"
)
func checkIfTerminal(w io.Writer) bool {
switch v := w.(type) {
case *os.File:
return terminal.IsTerminal(int(v.Fd()))
return isTerminal(int(v.Fd()))
default:
return false
}

View File

@ -0,0 +1,13 @@
// +build linux aix
package logrus
import "golang.org/x/sys/unix"
const ioctlReadTermios = unix.TCGETS
func isTerminal(fd int) bool {
_, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
return err == nil
}

View File

@ -12,18 +12,13 @@ import (
)
const (
nocolor = 0
red = 31
green = 32
yellow = 33
blue = 36
gray = 37
red = 31
yellow = 33
blue = 36
gray = 37
)
var (
baseTimestamp time.Time
emptyFieldMap FieldMap
)
var baseTimestamp time.Time
func init() {
baseTimestamp = time.Now()
@ -77,6 +72,12 @@ type TextFormatter struct {
// FieldKeyMsg: "@message"}}
FieldMap FieldMap
// CallerPrettyfier can be set by the user to modify the content
// of the function and file keys in the data when ReportCaller is
// activated. If any of the returned value is the empty string the
// corresponding key will be removed from fields.
CallerPrettyfier func(*runtime.Frame) (function string, file string)
terminalInitOnce sync.Once
}
@ -118,6 +119,8 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
keys = append(keys, k)
}
var funcVal, fileVal string
fixedKeys := make([]string, 0, 4+len(data))
if !f.DisableTimestamp {
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyTime))
@ -130,8 +133,19 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLogrusError))
}
if entry.HasCaller() {
fixedKeys = append(fixedKeys,
f.FieldMap.resolve(FieldKeyFunc), f.FieldMap.resolve(FieldKeyFile))
if f.CallerPrettyfier != nil {
funcVal, fileVal = f.CallerPrettyfier(entry.Caller)
} else {
funcVal = entry.Caller.Function
fileVal = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
}
if funcVal != "" {
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyFunc))
}
if fileVal != "" {
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyFile))
}
}
if !f.DisableSorting {
@ -166,6 +180,7 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
if f.isColored() {
f.printColored(b, entry, keys, data, timestampFormat)
} else {
for _, key := range fixedKeys {
var value interface{}
switch {
@ -178,9 +193,9 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
case key == f.FieldMap.resolve(FieldKeyLogrusError):
value = entry.err
case key == f.FieldMap.resolve(FieldKeyFunc) && entry.HasCaller():
value = entry.Caller.Function
value = funcVal
case key == f.FieldMap.resolve(FieldKeyFile) && entry.HasCaller():
value = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
value = fileVal
default:
value = data[key]
}
@ -215,10 +230,21 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin
entry.Message = strings.TrimSuffix(entry.Message, "\n")
caller := ""
if entry.HasCaller() {
caller = fmt.Sprintf("%s:%d %s()",
entry.Caller.File, entry.Caller.Line, entry.Caller.Function)
funcVal := fmt.Sprintf("%s()", entry.Caller.Function)
fileVal := fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
if f.CallerPrettyfier != nil {
funcVal, fileVal = f.CallerPrettyfier(entry.Caller)
}
if fileVal == "" {
caller = funcVal
} else if funcVal == "" {
caller = fileVal
} else {
caller = fileVal + " " + funcVal
}
}
if f.DisableTimestamp {