瀏覽代碼

Merge pull request #8932 from duglin/UpdateLogrus

Update logrus to the latest so we can use ParseLevel() for PR #8335
Tibor Vass 10 年之前
父節點
當前提交
38d3888194

+ 1 - 1
hack/vendor.sh

@@ -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

+ 4 - 2
vendor/src/github.com/Sirupsen/logrus/.travis.yml

@@ -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

+ 11 - 5
vendor/src/github.com/Sirupsen/logrus/README.md

@@ -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.
@@ -295,7 +301,7 @@ The built-in logging formatters are:
 * `logrus.TextFormatter`. Logs the event in colors if stdout is a tty, otherwise
   without colors.
   * *Note:* to force colored output when there is no TTY, set the `ForceColors`
-    field to `true`.  To force no colored output even if there is a TTY  set the 
+    field to `true`.  To force no colored output even if there is a TTY  set the
     `DisableColors` field to `true`
 * `logrus.JSONFormatter`. Logs fields as JSON.
 

+ 16 - 10
vendor/src/github.com/Sirupsen/logrus/entry.go

@@ -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...))
 }

+ 2 - 2
vendor/src/github.com/Sirupsen/logrus/exported.go

@@ -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 - 11
vendor/src/github.com/Sirupsen/logrus/formatter.go

@@ -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()
 }

+ 5 - 2
vendor/src/github.com/Sirupsen/logrus/json_formatter.go

@@ -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 - 0
vendor/src/github.com/Sirupsen/logrus/logrus.go

@@ -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 (

+ 74 - 0
vendor/src/github.com/Sirupsen/logrus/logrus_test.go

@@ -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())
+}

+ 45 - 36
vendor/src/github.com/Sirupsen/logrus/text_formatter.go

@@ -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) {
-	b := &bytes.Buffer{}
-
-	prefixFieldClashes(entry)
 
-	if (f.ForceColors || IsTerminal()) && !f.DisableColors {
-		levelText := strings.ToUpper(entry.Data["level"].(string))[0:4]
+	var keys []string
+	for k := range entry.Data {
+		keys = append(keys, k)
+	}
+	sort.Strings(keys)
 
-		levelColor := blue
+	b := &bytes.Buffer{}
 
-		if entry.Data["level"] == "warning" {
-			levelColor = yellow
-		} else if entry.Data["level"] == "error" ||
-			entry.Data["level"] == "fatal" ||
-			entry.Data["level"] == "panic" {
-			levelColor = red
-		}
+	prefixFieldClashes(entry)
 
-		fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Data["msg"])
+	isColored := (f.ForceColors || isTerminal) && !f.DisableColors
 
-		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)
 	}
 }