diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json
index a64ab359..45c1c5ac 100644
--- a/Godeps/Godeps.json
+++ b/Godeps/Godeps.json
@@ -24,8 +24,8 @@
},
{
"ImportPath": "github.com/Sirupsen/logrus",
- "Comment": "v0.6.1-8-gcc09837",
- "Rev": "cc09837bcd512ffe6bb2e3f635bed138c4cd6bc8"
+ "Comment": "v0.6.4-12-g467d9d5",
+ "Rev": "467d9d55c2d2c17248441a8fc661561161f40d5e"
},
{
"ImportPath": "github.com/bugsnag/bugsnag-go",
diff --git a/Godeps/_workspace/src/github.com/Sirupsen/logrus/.travis.yml b/Godeps/_workspace/src/github.com/Sirupsen/logrus/.travis.yml
index c3af3ce2..2d8c0866 100644
--- a/Godeps/_workspace/src/github.com/Sirupsen/logrus/.travis.yml
+++ b/Godeps/_workspace/src/github.com/Sirupsen/logrus/.travis.yml
@@ -2,9 +2,7 @@ language: go
go:
- 1.2
- 1.3
+ - 1.4
- tip
install:
- - go get github.com/stretchr/testify
- - go get github.com/stvp/go-udp-testing
- - go get github.com/tobi/airbrake-go
- - go get github.com/getsentry/raven-go
+ - go get -t ./...
diff --git a/Godeps/_workspace/src/github.com/Sirupsen/logrus/README.md b/Godeps/_workspace/src/github.com/Sirupsen/logrus/README.md
index cabd027a..6227b3f3 100644
--- a/Godeps/_workspace/src/github.com/Sirupsen/logrus/README.md
+++ b/Godeps/_workspace/src/github.com/Sirupsen/logrus/README.md
@@ -1,8 +1,8 @@
-# Logrus [![Build Status](https://travis-ci.org/Sirupsen/logrus.svg?branch=master)](https://travis-ci.org/Sirupsen/logrus)
+# Logrus [![Build Status](https://travis-ci.org/Sirupsen/logrus.svg?branch=master)](https://travis-ci.org/Sirupsen/logrus) [![godoc reference](https://godoc.org/github.com/Sirupsen/logrus?status.png)][godoc]
Logrus is a structured logger for Go (golang), completely API compatible with
the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not
-yet stable (pre 1.0), the core API is unlikely change much but please version
+yet stable (pre 1.0), the core API is unlikely to change much but please version
control your Logrus to make sure you aren't fetching latest `master` on every
build.**
@@ -33,7 +33,7 @@ ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"}
With the default `log.Formatter = new(logrus.TextFormatter)` when a TTY is not
attached, the output is compatible with the
-[l2met](http://r.32k.io/l2met-introduction) format:
+[logfmt](http://godoc.org/github.com/kr/logfmt) format:
```text
time="2014-04-20 15:36:23.830442383 -0400 EDT" level="info" msg="A group of walrus emerges from the ocean" animal="walrus" size=10
@@ -235,6 +235,12 @@ func init() {
* [`github.com/nubo/hiprus`](https://github.com/nubo/hiprus)
Send errors to a channel in hipchat.
+* [`github.com/sebest/logrusly`](https://github.com/sebest/logrusly)
+ Send logs to Loggly (https://www.loggly.com/)
+
+* [`github.com/johntdyer/slackrus`](https://github.com/johntdyer/slackrus)
+ Hook for Slack chat.
+
#### Level logging
Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic.
@@ -314,7 +320,7 @@ The built-in logging formatters are:
Third party logging formatters:
-* [`zalgo`](https://github.com/aybabtme/logzalgo): invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
+* [`zalgo`](https://github.com/aybabtme/logzalgo): invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
You can define your formatter by implementing the `Formatter` interface,
requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a
@@ -339,6 +345,24 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
}
```
+#### Logger as an `io.Writer`
+
+Logrus can be transormed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsability to close it.
+
+```go
+w := logger.Writer()
+defer w.Close()
+
+srv := http.Server{
+ // create a stdlib log.Logger that writes to
+ // logrus.Logger.
+ ErrorLog: log.New(w, "", 0),
+}
+```
+
+Each line written to that writer will be printed the usual way, using formatters
+and hooks. The level for those entries is `info`.
+
#### Rotation
Log rotation is not provided with Logrus. Log rotation should be done by an
diff --git a/Godeps/_workspace/src/github.com/Sirupsen/logrus/entry.go b/Godeps/_workspace/src/github.com/Sirupsen/logrus/entry.go
index e164eecb..17fe6f70 100644
--- a/Godeps/_workspace/src/github.com/Sirupsen/logrus/entry.go
+++ b/Godeps/_workspace/src/github.com/Sirupsen/logrus/entry.go
@@ -126,6 +126,10 @@ func (entry *Entry) Warn(args ...interface{}) {
}
}
+func (entry *Entry) Warning(args ...interface{}) {
+ entry.Warn(args...)
+}
+
func (entry *Entry) Error(args ...interface{}) {
if entry.Logger.Level >= ErrorLevel {
entry.log(ErrorLevel, fmt.Sprint(args...))
diff --git a/Godeps/_workspace/src/github.com/Sirupsen/logrus/exported.go b/Godeps/_workspace/src/github.com/Sirupsen/logrus/exported.go
index d0871244..fd092fc7 100644
--- a/Godeps/_workspace/src/github.com/Sirupsen/logrus/exported.go
+++ b/Godeps/_workspace/src/github.com/Sirupsen/logrus/exported.go
@@ -9,6 +9,10 @@ var (
std = New()
)
+func StandardLogger() *Logger {
+ return std
+}
+
// SetOutput sets the standard logger output.
func SetOutput(out io.Writer) {
std.mu.Lock()
diff --git a/Godeps/_workspace/src/github.com/Sirupsen/logrus/formatter.go b/Godeps/_workspace/src/github.com/Sirupsen/logrus/formatter.go
index 74c49a0e..038ce9fd 100644
--- a/Godeps/_workspace/src/github.com/Sirupsen/logrus/formatter.go
+++ b/Godeps/_workspace/src/github.com/Sirupsen/logrus/formatter.go
@@ -26,19 +26,19 @@ 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(entry *Entry) {
- _, ok := entry.Data["time"]
+func prefixFieldClashes(data Fields) {
+ _, ok := data["time"]
if ok {
- entry.Data["fields.time"] = entry.Data["time"]
+ data["fields.time"] = data["time"]
}
- _, ok = entry.Data["msg"]
+ _, ok = data["msg"]
if ok {
- entry.Data["fields.msg"] = entry.Data["msg"]
+ data["fields.msg"] = data["msg"]
}
- _, ok = entry.Data["level"]
+ _, ok = data["level"]
if ok {
- entry.Data["fields.level"] = entry.Data["level"]
+ data["fields.level"] = data["level"]
}
}
diff --git a/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go b/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go
index 12c56f29..c0f10c1b 100644
--- a/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go
+++ b/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go
@@ -30,7 +30,8 @@ func NewPapertrailHook(host string, port int, appName string) (*PapertrailHook,
// Fire is called when a log event is fired.
func (hook *PapertrailHook) Fire(entry *logrus.Entry) error {
date := time.Now().Format(format)
- payload := fmt.Sprintf("<22> %s %s: [%s] %s", date, hook.AppName, entry.Level, entry.Message)
+ msg, _ := entry.String()
+ payload := fmt.Sprintf("<22> %s %s: %s", date, hook.AppName, msg)
bytesWritten, err := hook.UDPConn.Write([]byte(payload))
if err != nil {
diff --git a/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/syslog/README.md b/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/syslog/README.md
index cd706bc1..4dbb8e72 100644
--- a/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/syslog/README.md
+++ b/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/syslog/README.md
@@ -6,7 +6,7 @@
import (
"log/syslog"
"github.com/Sirupsen/logrus"
- "github.com/Sirupsen/logrus/hooks/syslog"
+ logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
)
func main() {
@@ -17,4 +17,4 @@ func main() {
log.Hooks.Add(hook)
}
}
-```
\ No newline at end of file
+```
diff --git a/Godeps/_workspace/src/github.com/Sirupsen/logrus/json_formatter.go b/Godeps/_workspace/src/github.com/Sirupsen/logrus/json_formatter.go
index 9d11b642..b09227c2 100644
--- a/Godeps/_workspace/src/github.com/Sirupsen/logrus/json_formatter.go
+++ b/Godeps/_workspace/src/github.com/Sirupsen/logrus/json_formatter.go
@@ -9,12 +9,16 @@ import (
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()
+ data := make(Fields, len(entry.Data)+3)
+ for k, v := range entry.Data {
+ data[k] = v
+ }
+ prefixFieldClashes(data)
+ data["time"] = entry.Time.Format(time.RFC3339)
+ data["msg"] = entry.Message
+ data["level"] = entry.Level.String()
- serialized, err := json.Marshal(entry.Data)
+ serialized, err := json.Marshal(data)
if err != nil {
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
}
diff --git a/Godeps/_workspace/src/github.com/Sirupsen/logrus/logger.go b/Godeps/_workspace/src/github.com/Sirupsen/logrus/logger.go
index 7374fe36..b392e547 100644
--- a/Godeps/_workspace/src/github.com/Sirupsen/logrus/logger.go
+++ b/Godeps/_workspace/src/github.com/Sirupsen/logrus/logger.go
@@ -38,7 +38,7 @@ type Logger struct {
// Out: os.Stderr,
// Formatter: new(JSONFormatter),
// Hooks: make(levelHooks),
-// Level: logrus.Debug,
+// Level: logrus.DebugLevel,
// }
//
// It's recommended to make this a global instance called `log`.
diff --git a/Godeps/_workspace/src/github.com/Sirupsen/logrus/logrus_test.go b/Godeps/_workspace/src/github.com/Sirupsen/logrus/logrus_test.go
index 15157d17..7f52c6fb 100644
--- a/Godeps/_workspace/src/github.com/Sirupsen/logrus/logrus_test.go
+++ b/Godeps/_workspace/src/github.com/Sirupsen/logrus/logrus_test.go
@@ -44,8 +44,12 @@ func LogAndAssertText(t *testing.T, log func(*Logger), assertions func(fields ma
}
kvArr := strings.Split(kv, "=")
key := strings.TrimSpace(kvArr[0])
- val, err := strconv.Unquote(kvArr[1])
- assert.NoError(t, err)
+ val := kvArr[1]
+ if kvArr[1][0] == '"' {
+ var err error
+ val, err = strconv.Unquote(val)
+ assert.NoError(t, err)
+ }
fields[key] = val
}
assertions(fields)
@@ -204,6 +208,38 @@ func TestDefaultFieldsAreNotPrefixed(t *testing.T) {
})
}
+func TestDoubleLoggingDoesntPrefixPreviousFields(t *testing.T) {
+
+ var buffer bytes.Buffer
+ var fields Fields
+
+ logger := New()
+ logger.Out = &buffer
+ logger.Formatter = new(JSONFormatter)
+
+ llog := logger.WithField("context", "eating raw fish")
+
+ llog.Info("looks delicious")
+
+ err := json.Unmarshal(buffer.Bytes(), &fields)
+ assert.NoError(t, err, "should have decoded first message")
+ assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields")
+ assert.Equal(t, fields["msg"], "looks delicious")
+ assert.Equal(t, fields["context"], "eating raw fish")
+
+ buffer.Reset()
+
+ llog.Warn("omg it is!")
+
+ err = json.Unmarshal(buffer.Bytes(), &fields)
+ assert.NoError(t, err, "should have decoded second message")
+ assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields")
+ assert.Equal(t, fields["msg"], "omg it is!")
+ assert.Equal(t, fields["context"], "eating raw fish")
+ assert.Nil(t, fields["fields.msg"], "should not have prefixed previous `msg` entry")
+
+}
+
func TestConvertLevelToString(t *testing.T) {
assert.Equal(t, "debug", DebugLevel.String())
assert.Equal(t, "info", InfoLevel.String())
diff --git a/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_notwindows.go b/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_notwindows.go
index 276447bd..80edd323 100644
--- a/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_notwindows.go
+++ b/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_notwindows.go
@@ -3,7 +3,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build linux,!appengine darwin freebsd
+// +build linux,!appengine darwin freebsd openbsd
package logrus
diff --git a/Godeps/_workspace/src/github.com/Sirupsen/logrus/text_formatter.go b/Godeps/_workspace/src/github.com/Sirupsen/logrus/text_formatter.go
index fc0a4082..78e78893 100644
--- a/Godeps/_workspace/src/github.com/Sirupsen/logrus/text_formatter.go
+++ b/Godeps/_workspace/src/github.com/Sirupsen/logrus/text_formatter.go
@@ -3,6 +3,7 @@ package logrus
import (
"bytes"
"fmt"
+ "regexp"
"sort"
"strings"
"time"
@@ -19,6 +20,7 @@ const (
var (
baseTimestamp time.Time
isTerminal bool
+ noQuoteNeeded *regexp.Regexp
)
func init() {
@@ -34,6 +36,9 @@ type TextFormatter struct {
// Set to true to bypass checking for a TTY before outputting colors.
ForceColors bool
DisableColors bool
+ // Set to true to disable timestamp logging (useful when the output
+ // is redirected to a logging system already adding a timestamp)
+ DisableTimestamp bool
}
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
@@ -46,14 +51,16 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
b := &bytes.Buffer{}
- prefixFieldClashes(entry)
+ prefixFieldClashes(entry.Data)
isColored := (f.ForceColors || isTerminal) && !f.DisableColors
if isColored {
printColored(b, entry, keys)
} else {
- f.appendKeyValue(b, "time", entry.Time.Format(time.RFC3339))
+ if !f.DisableTimestamp {
+ 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 {
@@ -85,10 +92,32 @@ func printColored(b *bytes.Buffer, entry *Entry, keys []string) {
}
}
+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, value interface{}) {
switch value.(type) {
- case string, error:
- fmt.Fprintf(b, "%v=%q ", key, value)
+ case string:
+ if needsQuoting(value.(string)) {
+ fmt.Fprintf(b, "%v=%s ", key, value)
+ } else {
+ fmt.Fprintf(b, "%v=%q ", key, value)
+ }
+ case error:
+ if needsQuoting(value.(error).Error()) {
+ fmt.Fprintf(b, "%v=%s ", key, value)
+ } else {
+ fmt.Fprintf(b, "%v=%q ", key, value)
+ }
default:
fmt.Fprintf(b, "%v=%v ", key, value)
}