mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Update logrus to v0.6.0 so we can use ParseLevel() for PR #8335
Signed-off-by: Doug Davis <dug@us.ibm.com>
This commit is contained in:
parent
025363848b
commit
a12d897394
10 changed files with 181 additions and 69 deletions
|
@ -53,7 +53,7 @@ clone hg code.google.com/p/gosqlite 74691fb6f837
|
|||
|
||||
clone git github.com/docker/libtrust d273ef2565ca
|
||||
|
||||
clone git github.com/Sirupsen/logrus v0.5.1
|
||||
clone git github.com/Sirupsen/logrus v0.6.0
|
||||
|
||||
# get Go tip's archive/tar, for xattr support and improved performance
|
||||
# TODO after Go 1.4 drops, bump our minimum supported version and drop this vendored dep
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
language: go
|
||||
go:
|
||||
- 1.1
|
||||
- 1.2
|
||||
- 1.3
|
||||
- tip
|
||||
before_script:
|
||||
install:
|
||||
- go get github.com/stretchr/testify
|
||||
- go get github.com/stvp/go-udp-testing
|
||||
- go get github.com/tobi/airbrake-go
|
||||
|
|
14
vendor/src/github.com/Sirupsen/logrus/README.md
vendored
14
vendor/src/github.com/Sirupsen/logrus/README.md
vendored
|
@ -81,7 +81,7 @@ func init() {
|
|||
|
||||
// Use the Airbrake hook to report errors that have Error severity or above to
|
||||
// an exception tracker. You can create custom hooks, see the Hooks section.
|
||||
log.AddHook(logrus_airbrake.AirbrakeHook)
|
||||
log.AddHook(&logrus_airbrake.AirbrakeHook{})
|
||||
|
||||
// Output to stderr instead of stdout, could also be a file.
|
||||
log.SetOutput(os.Stderr)
|
||||
|
@ -126,7 +126,7 @@ func main() {
|
|||
// exported logger. See Godoc.
|
||||
log.Out = os.Stderr
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"animal": "walrus",
|
||||
"size": 10,
|
||||
}).Info("A group of walrus emerges from the ocean")
|
||||
|
@ -214,14 +214,20 @@ func init() {
|
|||
}
|
||||
```
|
||||
|
||||
* [`github.com/Sirupsen/logrus/hooks/airbrake`](https://github.com/Sirupsen/logrus/blob/master/hooks/airbrake/airbrake.go).
|
||||
* [`github.com/Sirupsen/logrus/hooks/airbrake`](https://github.com/Sirupsen/logrus/blob/master/hooks/airbrake/airbrake.go)
|
||||
Send errors to an exception tracking service compatible with the Airbrake API.
|
||||
Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes.
|
||||
|
||||
* [`github.com/Sirupsen/logrus/hooks/syslog`](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go).
|
||||
* [`github.com/Sirupsen/logrus/hooks/papertrail`](https://github.com/Sirupsen/logrus/blob/master/hooks/papertrail/papertrail.go)
|
||||
Send errors to the Papertrail hosted logging service via UDP.
|
||||
|
||||
* [`github.com/Sirupsen/logrus/hooks/syslog`](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go)
|
||||
Send errors to remote syslog server.
|
||||
Uses standard library `log/syslog` behind the scenes.
|
||||
|
||||
* [`github.com/nubo/hiprus`](https://github.com/nubo/hiprus)
|
||||
Send errors to a channel in hipchat.
|
||||
|
||||
#### Level logging
|
||||
|
||||
Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic.
|
||||
|
|
26
vendor/src/github.com/Sirupsen/logrus/entry.go
vendored
26
vendor/src/github.com/Sirupsen/logrus/entry.go
vendored
|
@ -8,7 +8,7 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
// An entry is the final or intermediate Logrus logging entry. It containts all
|
||||
// An entry is the final or intermediate Logrus logging entry. It contains all
|
||||
// the fields passed with WithField{,s}. It's finally logged when Debug, Info,
|
||||
// Warn, Error, Fatal or Panic is called on it. These objects can be reused and
|
||||
// passed around as much as you wish to avoid field duplication.
|
||||
|
@ -28,8 +28,6 @@ type Entry struct {
|
|||
Message string
|
||||
}
|
||||
|
||||
var baseTimestamp time.Time
|
||||
|
||||
func NewEntry(logger *Logger) *Entry {
|
||||
return &Entry{
|
||||
Logger: logger,
|
||||
|
@ -72,18 +70,22 @@ func (entry *Entry) WithFields(fields Fields) *Entry {
|
|||
return &Entry{Logger: entry.Logger, Data: data}
|
||||
}
|
||||
|
||||
func (entry *Entry) log(level Level, msg string) string {
|
||||
func (entry *Entry) log(level Level, msg string) {
|
||||
entry.Time = time.Now()
|
||||
entry.Level = level
|
||||
entry.Message = msg
|
||||
|
||||
if err := entry.Logger.Hooks.Fire(level, entry); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to fire hook", err)
|
||||
entry.Logger.mu.Lock()
|
||||
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
|
||||
entry.Logger.mu.Unlock()
|
||||
}
|
||||
|
||||
reader, err := entry.Reader()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v", err)
|
||||
entry.Logger.mu.Lock()
|
||||
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
|
||||
entry.Logger.mu.Unlock()
|
||||
}
|
||||
|
||||
entry.Logger.mu.Lock()
|
||||
|
@ -91,10 +93,15 @@ func (entry *Entry) log(level Level, msg string) string {
|
|||
|
||||
_, err = io.Copy(entry.Logger.Out, reader)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to write to log, %v", err)
|
||||
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
|
||||
}
|
||||
|
||||
return reader.String()
|
||||
// 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
|
||||
// directly here.
|
||||
if level <= PanicLevel {
|
||||
panic(reader.String())
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Debug(args ...interface{}) {
|
||||
|
@ -134,8 +141,7 @@ func (entry *Entry) Fatal(args ...interface{}) {
|
|||
|
||||
func (entry *Entry) Panic(args ...interface{}) {
|
||||
if entry.Logger.Level >= PanicLevel {
|
||||
msg := entry.log(PanicLevel, fmt.Sprint(args...))
|
||||
panic(msg)
|
||||
entry.log(PanicLevel, fmt.Sprint(args...))
|
||||
}
|
||||
panic(fmt.Sprint(args...))
|
||||
}
|
||||
|
|
|
@ -96,7 +96,7 @@ func Fatal(args ...interface{}) {
|
|||
std.Fatal(args...)
|
||||
}
|
||||
|
||||
// Debugf logs a message at level Debugf on the standard logger.
|
||||
// Debugf logs a message at level Debug on the standard logger.
|
||||
func Debugf(format string, args ...interface{}) {
|
||||
std.Debugf(format, args...)
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ func Errorf(format string, args ...interface{}) {
|
|||
std.Errorf(format, args...)
|
||||
}
|
||||
|
||||
// Panicf logs a message at level Pancf on the standard logger.
|
||||
// Panicf logs a message at level Panic on the standard logger.
|
||||
func Panicf(format string, args ...interface{}) {
|
||||
std.Panicf(format, args...)
|
||||
}
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// The Formatter interface is used to implement a custom Formatter. It takes an
|
||||
// `Entry`. It exposes all the fields, including the default ones:
|
||||
//
|
||||
|
@ -28,7 +24,7 @@ type Formatter interface {
|
|||
//
|
||||
// {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."}
|
||||
//
|
||||
// It's not exported because it's still using Data in an opionated way. It's to
|
||||
// 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(entry *Entry) {
|
||||
_, ok := entry.Data["time"]
|
||||
|
@ -36,19 +32,13 @@ func prefixFieldClashes(entry *Entry) {
|
|||
entry.Data["fields.time"] = entry.Data["time"]
|
||||
}
|
||||
|
||||
entry.Data["time"] = entry.Time.Format(time.RFC3339)
|
||||
|
||||
_, ok = entry.Data["msg"]
|
||||
if ok {
|
||||
entry.Data["fields.msg"] = entry.Data["msg"]
|
||||
}
|
||||
|
||||
entry.Data["msg"] = entry.Message
|
||||
|
||||
_, ok = entry.Data["level"]
|
||||
if ok {
|
||||
entry.Data["fields.level"] = entry.Data["level"]
|
||||
}
|
||||
|
||||
entry.Data["level"] = entry.Level.String()
|
||||
}
|
||||
|
|
|
@ -3,13 +3,16 @@ package logrus
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
type JSONFormatter struct {
|
||||
}
|
||||
type JSONFormatter struct{}
|
||||
|
||||
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||
prefixFieldClashes(entry)
|
||||
entry.Data["time"] = entry.Time.Format(time.RFC3339)
|
||||
entry.Data["msg"] = entry.Message
|
||||
entry.Data["level"] = entry.Level.String()
|
||||
|
||||
serialized, err := json.Marshal(entry.Data)
|
||||
if err != nil {
|
||||
|
|
22
vendor/src/github.com/Sirupsen/logrus/logrus.go
vendored
22
vendor/src/github.com/Sirupsen/logrus/logrus.go
vendored
|
@ -1,6 +1,7 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
|
@ -30,6 +31,27 @@ func (level Level) String() string {
|
|||
return "unknown"
|
||||
}
|
||||
|
||||
// ParseLevel takes a string level and returns the Logrus log level constant.
|
||||
func ParseLevel(lvl string) (Level, error) {
|
||||
switch lvl {
|
||||
case "panic":
|
||||
return PanicLevel, nil
|
||||
case "fatal":
|
||||
return FatalLevel, nil
|
||||
case "error":
|
||||
return ErrorLevel, nil
|
||||
case "warn", "warning":
|
||||
return WarnLevel, nil
|
||||
case "info":
|
||||
return InfoLevel, nil
|
||||
case "debug":
|
||||
return DebugLevel, nil
|
||||
}
|
||||
|
||||
var l Level
|
||||
return l, fmt.Errorf("not a valid logrus Level: %q", lvl)
|
||||
}
|
||||
|
||||
// These are the different logging levels. You can set the logging level to log
|
||||
// on your instance of logger, obtained with `logrus.New()`.
|
||||
const (
|
||||
|
|
|
@ -3,6 +3,8 @@ package logrus
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -24,6 +26,31 @@ func LogAndAssertJSON(t *testing.T, log func(*Logger), assertions func(fields Fi
|
|||
assertions(fields)
|
||||
}
|
||||
|
||||
func LogAndAssertText(t *testing.T, log func(*Logger), assertions func(fields map[string]string)) {
|
||||
var buffer bytes.Buffer
|
||||
|
||||
logger := New()
|
||||
logger.Out = &buffer
|
||||
logger.Formatter = &TextFormatter{
|
||||
DisableColors: true,
|
||||
}
|
||||
|
||||
log(logger)
|
||||
|
||||
fields := make(map[string]string)
|
||||
for _, kv := range strings.Split(buffer.String(), " ") {
|
||||
if !strings.Contains(kv, "=") {
|
||||
continue
|
||||
}
|
||||
kvArr := strings.Split(kv, "=")
|
||||
key := strings.TrimSpace(kvArr[0])
|
||||
val, err := strconv.Unquote(kvArr[1])
|
||||
assert.NoError(t, err)
|
||||
fields[key] = val
|
||||
}
|
||||
assertions(fields)
|
||||
}
|
||||
|
||||
func TestPrint(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Print("test")
|
||||
|
@ -163,6 +190,20 @@ func TestUserSuppliedLevelFieldHasPrefix(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestDefaultFieldsAreNotPrefixed(t *testing.T) {
|
||||
LogAndAssertText(t, func(log *Logger) {
|
||||
ll := log.WithField("herp", "derp")
|
||||
ll.Info("hello")
|
||||
ll.Info("bye")
|
||||
}, func(fields map[string]string) {
|
||||
for _, fieldName := range []string{"fields.level", "fields.time", "fields.msg"} {
|
||||
if _, ok := fields[fieldName]; ok {
|
||||
t.Fatalf("should not have prefixed %q: %v", fieldName, fields)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestConvertLevelToString(t *testing.T) {
|
||||
assert.Equal(t, "debug", DebugLevel.String())
|
||||
assert.Equal(t, "info", InfoLevel.String())
|
||||
|
@ -171,3 +212,36 @@ func TestConvertLevelToString(t *testing.T) {
|
|||
assert.Equal(t, "fatal", FatalLevel.String())
|
||||
assert.Equal(t, "panic", PanicLevel.String())
|
||||
}
|
||||
|
||||
func TestParseLevel(t *testing.T) {
|
||||
l, err := ParseLevel("panic")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, PanicLevel, l)
|
||||
|
||||
l, err = ParseLevel("fatal")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, FatalLevel, l)
|
||||
|
||||
l, err = ParseLevel("error")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, ErrorLevel, l)
|
||||
|
||||
l, err = ParseLevel("warn")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, WarnLevel, l)
|
||||
|
||||
l, err = ParseLevel("warning")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, WarnLevel, l)
|
||||
|
||||
l, err = ParseLevel("info")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, InfoLevel, l)
|
||||
|
||||
l, err = ParseLevel("debug")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, DebugLevel, l)
|
||||
|
||||
l, err = ParseLevel("invalid")
|
||||
assert.Equal(t, "not a valid logrus Level: \"invalid\"", err.Error())
|
||||
}
|
||||
|
|
|
@ -16,8 +16,14 @@ const (
|
|||
blue = 34
|
||||
)
|
||||
|
||||
var (
|
||||
baseTimestamp time.Time
|
||||
isTerminal bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
baseTimestamp = time.Now()
|
||||
isTerminal = IsTerminal()
|
||||
}
|
||||
|
||||
func miniTS() int {
|
||||
|
@ -31,45 +37,27 @@ type TextFormatter struct {
|
|||
}
|
||||
|
||||
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||
|
||||
var keys []string
|
||||
for k := range entry.Data {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
b := &bytes.Buffer{}
|
||||
|
||||
prefixFieldClashes(entry)
|
||||
|
||||
if (f.ForceColors || IsTerminal()) && !f.DisableColors {
|
||||
levelText := strings.ToUpper(entry.Data["level"].(string))[0:4]
|
||||
isColored := (f.ForceColors || isTerminal) && !f.DisableColors
|
||||
|
||||
levelColor := blue
|
||||
|
||||
if entry.Data["level"] == "warning" {
|
||||
levelColor = yellow
|
||||
} else if entry.Data["level"] == "error" ||
|
||||
entry.Data["level"] == "fatal" ||
|
||||
entry.Data["level"] == "panic" {
|
||||
levelColor = red
|
||||
}
|
||||
|
||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Data["msg"])
|
||||
|
||||
keys := make([]string, 0)
|
||||
for k, _ := range entry.Data {
|
||||
if k != "level" && k != "time" && k != "msg" {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
v := entry.Data[k]
|
||||
fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=%v", levelColor, k, v)
|
||||
}
|
||||
if isColored {
|
||||
printColored(b, entry, keys)
|
||||
} else {
|
||||
f.AppendKeyValue(b, "time", entry.Data["time"].(string))
|
||||
f.AppendKeyValue(b, "level", entry.Data["level"].(string))
|
||||
f.AppendKeyValue(b, "msg", entry.Data["msg"].(string))
|
||||
|
||||
for key, value := range entry.Data {
|
||||
if key != "time" && key != "level" && key != "msg" {
|
||||
f.AppendKeyValue(b, key, value)
|
||||
}
|
||||
f.appendKeyValue(b, "time", entry.Time.Format(time.RFC3339))
|
||||
f.appendKeyValue(b, "level", entry.Level.String())
|
||||
f.appendKeyValue(b, "msg", entry.Message)
|
||||
for _, key := range keys {
|
||||
f.appendKeyValue(b, key, entry.Data[key])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,10 +65,31 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
|||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
func (f *TextFormatter) AppendKeyValue(b *bytes.Buffer, key, value interface{}) {
|
||||
if _, ok := value.(string); ok {
|
||||
func printColored(b *bytes.Buffer, entry *Entry, keys []string) {
|
||||
var levelColor int
|
||||
switch entry.Level {
|
||||
case WarnLevel:
|
||||
levelColor = yellow
|
||||
case ErrorLevel, FatalLevel, PanicLevel:
|
||||
levelColor = red
|
||||
default:
|
||||
levelColor = blue
|
||||
}
|
||||
|
||||
levelText := strings.ToUpper(entry.Level.String())[0:4]
|
||||
|
||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message)
|
||||
for _, k := range keys {
|
||||
v := entry.Data[k]
|
||||
fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=%v", levelColor, k, v)
|
||||
}
|
||||
}
|
||||
|
||||
func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key, value interface{}) {
|
||||
switch value.(type) {
|
||||
case string, error:
|
||||
fmt.Fprintf(b, "%v=%q ", key, value)
|
||||
} else {
|
||||
default:
|
||||
fmt.Fprintf(b, "%v=%v ", key, value)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue