@cryptotaxi247 / kubo / commits / d69bdecbc

move back to upstream logrus

Henry committed Mar 1, 2015 at 00:59 UTC d69bdecbc7e084f37be3728d7ac581a1849e5c7e
41 files changed +546 -69
Godeps/Godeps.json
+5 -5
@@ -31,6 +31,11 @@
31 "ImportPath": "github.com/ActiveState/tail",
32 "Rev": "068b72961a6bc5b4a82cf4fc14ccc724c0cfa73a"
33 },
34 + {
35 + "ImportPath": "github.com/Sirupsen/logrus",
36 + "Comment": "v0.6.5",
37 + "Rev": "c0f7e35ed2e48f188c37581b4b743cf7383f85c6"
38 + },
39 {
40 "ImportPath": "github.com/braintree/manners",
41 "Comment": "0.3.1-2-g5280e25",
@@ -44,11 +49,6 @@
49 "ImportPath": "github.com/briantigerchow/inflect",
50 "Rev": "cef1f9cc2234281dc58ea10be7e9aad5e282ecab"
51 },
47 - {
48 - "ImportPath": "github.com/briantigerchow/logrus",
49 - "Comment": "v0.6.0-5-gf92b795",
50 - "Rev": "f92b7950b372b1db80bd3527e4d40e42555fe6c2"
51 - },
52 {
53 "ImportPath": "github.com/briantigerchow/pubsub",
54 "Rev": "39ce5f556423a4c7223b370fa17a3bbd75b2d197"
Godeps/_workspace/src/github.com/Sirupsen/logrus/.gitignore renamed
Godeps/_workspace/src/github.com/Sirupsen/logrus/.travis.yml new
+8
@@ -0,0 +1,8 @@
1 +language: go
2 +go:
3 + - 1.2
4 + - 1.3
5 + - 1.4
6 + - tip
7 +install:
8 + - go get -t ./...
Godeps/_workspace/src/github.com/Sirupsen/logrus/LICENSE renamed
Godeps/_workspace/src/github.com/Sirupsen/logrus/README.md renamed
+43 -8
@@ -1,10 +1,11 @@
1 -# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/>&nbsp;[![Build Status](https://travis-ci.org/Sirupsen/logrus.svg?branch=master)](https://travis-ci.org/Sirupsen/logrus)
1 +# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/>&nbsp;[![Build Status](https://travis-ci.org/Sirupsen/logrus.svg?branch=master)](https://travis-ci.org/Sirupsen/logrus)&nbsp;[![godoc reference](https://godoc.org/github.com/Sirupsen/logrus?status.png)][godoc]
2
3 Logrus is a structured logger for Go (golang), completely API compatible with
4 the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not
5 -yet stable (pre 1.0), the core API is unlikely change much but please version
6 -control your Logrus to make sure you aren't fetching latest `master` on every
7 -build.**
5 +yet stable (pre 1.0). Logrus itself is completely stable and has been used in
6 +many large deployments. The core API is unlikely to change much but please
7 +version control your Logrus to make sure you aren't fetching latest `master` on
8 +every build.**
9
10 Nicely color-coded in development (when a TTY is attached, otherwise just
11 plain text):
@@ -33,7 +34,7 @@ ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"}
34
35 With the default `log.Formatter = new(logrus.TextFormatter)` when a TTY is not
36 attached, the output is compatible with the
36 -[l2met](http://r.32k.io/l2met-introduction) format:
37 +[logfmt](http://godoc.org/github.com/kr/logfmt) format:
38
39 ```text
40 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
@@ -206,11 +207,18 @@ import (
207 log "github.com/Sirupsen/logrus"
208 "github.com/Sirupsen/logrus/hooks/airbrake"
209 "github.com/Sirupsen/logrus/hooks/syslog"
210 + "log/syslog"
211 )
212
213 func init() {
214 log.AddHook(new(logrus_airbrake.AirbrakeHook))
213 - log.AddHook(logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, ""))
215 +
216 + hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
217 + if err != nil {
218 + log.Error("Unable to connect to local syslog daemon")
219 + } else {
220 + log.AddHook(hook)
221 + }
222 }
223 ```
224
@@ -228,6 +236,15 @@ func init() {
236 * [`github.com/nubo/hiprus`](https://github.com/nubo/hiprus)
237 Send errors to a channel in hipchat.
238
239 +* [`github.com/sebest/logrusly`](https://github.com/sebest/logrusly)
240 + Send logs to Loggly (https://www.loggly.com/)
241 +
242 +* [`github.com/johntdyer/slackrus`](https://github.com/johntdyer/slackrus)
243 + Hook for Slack chat.
244 +
245 +* [`github.com/wercker/journalhook`](https://github.com/wercker/journalhook).
246 + Hook for logging to `systemd-journald`.
247 +
248 #### Level logging
249
250 Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic.
@@ -307,7 +324,7 @@ The built-in logging formatters are:
324
325 Third party logging formatters:
326
310 -* [`zalgo`](https://github.com/aybabtme/logzalgo): invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
327 +* [`zalgo`](https://github.com/aybabtme/logzalgo): invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
328
329 You can define your formatter by implementing the `Formatter` interface,
330 requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a
@@ -332,10 +349,28 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
349 }
350 ```
351
352 +#### Logger as an `io.Writer`
353 +
354 +Logrus can be transormed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsibility to close it.
355 +
356 +```go
357 +w := logger.Writer()
358 +defer w.Close()
359 +
360 +srv := http.Server{
361 + // create a stdlib log.Logger that writes to
362 + // logrus.Logger.
363 + ErrorLog: log.New(w, "", 0),
364 +}
365 +```
366 +
367 +Each line written to that writer will be printed the usual way, using formatters
368 +and hooks. The level for those entries is `info`.
369 +
370 #### Rotation
371
372 Log rotation is not provided with Logrus. Log rotation should be done by an
338 -external program (like `logrotated(8)`) that can compress and delete old log
373 +external program (like `logrotate(8)`) that can compress and delete old log
374 entries. It should not be a feature of the application-level logger.
375
376
Godeps/_workspace/src/github.com/Sirupsen/logrus/entry.go renamed
+4
@@ -126,6 +126,10 @@ func (entry *Entry) Warn(args ...interface{}) {
126 }
127 }
128
129 +func (entry *Entry) Warning(args ...interface{}) {
130 + entry.Warn(args...)
131 +}
132 +
133 func (entry *Entry) Error(args ...interface{}) {
134 if entry.Logger.Level >= ErrorLevel {
135 entry.log(ErrorLevel, fmt.Sprint(args...))
Godeps/_workspace/src/github.com/Sirupsen/logrus/entry_test.go renamed
Godeps/_workspace/src/github.com/Sirupsen/logrus/examples/basic/basic.go renamed
+1 -1
@@ -1,7 +1,7 @@
1 package main
2
3 import (
4 - "github.com/Sirupsen/logrus"
4 + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/Sirupsen/logrus"
5 )
6
7 var log = logrus.New()
Godeps/_workspace/src/github.com/Sirupsen/logrus/examples/hook/hook.go renamed
+2 -2
@@ -1,8 +1,8 @@
1 package main
2
3 import (
4 - "github.com/Sirupsen/logrus"
5 - "github.com/Sirupsen/logrus/hooks/airbrake"
4 + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/Sirupsen/logrus"
5 + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/airbrake"
6 "github.com/tobi/airbrake-go"
7 )
8
Godeps/_workspace/src/github.com/Sirupsen/logrus/exported.go renamed
+11
@@ -9,6 +9,10 @@ var (
9 std = New()
10 )
11
12 +func StandardLogger() *Logger {
13 + return std
14 +}
15 +
16 // SetOutput sets the standard logger output.
17 func SetOutput(out io.Writer) {
18 std.mu.Lock()
@@ -30,6 +34,13 @@ func SetLevel(level Level) {
34 std.Level = level
35 }
36
37 +// GetLevel returns the standard logger level.
38 +func GetLevel() Level {
39 + std.mu.Lock()
40 + defer std.mu.Unlock()
41 + return std.Level
42 +}
43 +
44 // AddHook adds a hook to the standard logger hooks.
45 func AddHook(hook Hook) {
46 std.mu.Lock()
Godeps/_workspace/src/github.com/Sirupsen/logrus/formatter.go renamed
+7 -7
@@ -26,19 +26,19 @@ type Formatter interface {
26 //
27 // It's not exported because it's still using Data in an opinionated way. It's to
28 // avoid code duplication between the two default formatters.
29 -func prefixFieldClashes(entry *Entry) {
30 - _, ok := entry.Data["time"]
29 +func prefixFieldClashes(data Fields) {
30 + _, ok := data["time"]
31 if ok {
32 - entry.Data["fields.time"] = entry.Data["time"]
32 + data["fields.time"] = data["time"]
33 }
34
35 - _, ok = entry.Data["msg"]
35 + _, ok = data["msg"]
36 if ok {
37 - entry.Data["fields.msg"] = entry.Data["msg"]
37 + data["fields.msg"] = data["msg"]
38 }
39
40 - _, ok = entry.Data["level"]
40 + _, ok = data["level"]
41 if ok {
42 - entry.Data["fields.level"] = entry.Data["level"]
42 + data["fields.level"] = data["level"]
43 }
44 }
Godeps/_workspace/src/github.com/Sirupsen/logrus/formatter_bench_test.go renamed
Godeps/_workspace/src/github.com/Sirupsen/logrus/hook_test.go renamed
Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks.go renamed
Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/airbrake/airbrake.go renamed
+1 -1
@@ -1,7 +1,7 @@
1 package logrus_airbrake
2
3 import (
4 - "github.com/Sirupsen/logrus"
4 + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/Sirupsen/logrus"
5 "github.com/tobi/airbrake-go"
6 )
7
Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/papertrail/README.md renamed
Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go renamed
+3 -2
@@ -6,7 +6,7 @@ import (
6 "os"
7 "time"
8
9 - "github.com/Sirupsen/logrus"
9 + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/Sirupsen/logrus"
10 )
11
12 const (
@@ -30,7 +30,8 @@ func NewPapertrailHook(host string, port int, appName string) (*PapertrailHook,
30 // Fire is called when a log event is fired.
31 func (hook *PapertrailHook) Fire(entry *logrus.Entry) error {
32 date := time.Now().Format(format)
33 - payload := fmt.Sprintf("<22> %s %s: [%s] %s", date, hook.AppName, entry.Data["level"], entry.Message)
33 + msg, _ := entry.String()
34 + payload := fmt.Sprintf("<22> %s %s: %s", date, hook.AppName, msg)
35
36 bytesWritten, err := hook.UDPConn.Write([]byte(payload))
37 if err != nil {
Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail_test.go renamed
+1 -1
@@ -4,7 +4,7 @@ import (
4 "fmt"
5 "testing"
6
7 - "github.com/Sirupsen/logrus"
7 + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/Sirupsen/logrus"
8 "github.com/stvp/go-udp-testing"
9 )
10
Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/sentry/README.md new
+61
@@ -0,0 +1,61 @@
1 +# Sentry Hook for Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:" />
2 +
3 +[Sentry](https://getsentry.com) provides both self-hosted and hosted
4 +solutions for exception tracking.
5 +Both client and server are
6 +[open source](https://github.com/getsentry/sentry).
7 +
8 +## Usage
9 +
10 +Every sentry application defined on the server gets a different
11 +[DSN](https://www.getsentry.com/docs/). In the example below replace
12 +`YOUR_DSN` with the one created for your application.
13 +
14 +```go
15 +import (
16 + "github.com/Sirupsen/logrus"
17 + "github.com/Sirupsen/logrus/hooks/sentry"
18 +)
19 +
20 +func main() {
21 + log := logrus.New()
22 + hook, err := logrus_sentry.NewSentryHook(YOUR_DSN, []logrus.Level{
23 + logrus.PanicLevel,
24 + logrus.FatalLevel,
25 + logrus.ErrorLevel,
26 + })
27 +
28 + if err == nil {
29 + log.Hooks.Add(hook)
30 + }
31 +}
32 +```
33 +
34 +## Special fields
35 +
36 +Some logrus fields have a special meaning in this hook,
37 +these are server_name and logger.
38 +When logs are sent to sentry these fields are treated differently.
39 +- server_name (also known as hostname) is the name of the server which
40 +is logging the event (hostname.example.com)
41 +- logger is the part of the application which is logging the event.
42 +In go this usually means setting it to the name of the package.
43 +
44 +## Timeout
45 +
46 +`Timeout` is the time the sentry hook will wait for a response
47 +from the sentry server.
48 +
49 +If this time elapses with no response from
50 +the server an error will be returned.
51 +
52 +If `Timeout` is set to 0 the SentryHook will not wait for a reply
53 +and will assume a correct delivery.
54 +
55 +The SentryHook has a default timeout of `100 milliseconds` when created
56 +with a call to `NewSentryHook`. This can be changed by assigning a value to the `Timeout` field:
57 +
58 +```go
59 +hook, _ := logrus_sentry.NewSentryHook(...)
60 +hook.Timeout = 20*time.Seconds
61 +```
Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/sentry/sentry.go new
+100
@@ -0,0 +1,100 @@
1 +package logrus_sentry
2 +
3 +import (
4 + "fmt"
5 + "time"
6 +
7 + "github.com/getsentry/raven-go"
8 + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/Sirupsen/logrus"
9 +)
10 +
11 +var (
12 + severityMap = map[logrus.Level]raven.Severity{
13 + logrus.DebugLevel: raven.DEBUG,
14 + logrus.InfoLevel: raven.INFO,
15 + logrus.WarnLevel: raven.WARNING,
16 + logrus.ErrorLevel: raven.ERROR,
17 + logrus.FatalLevel: raven.FATAL,
18 + logrus.PanicLevel: raven.FATAL,
19 + }
20 +)
21 +
22 +func getAndDel(d logrus.Fields, key string) (string, bool) {
23 + var (
24 + ok bool
25 + v interface{}
26 + val string
27 + )
28 + if v, ok = d[key]; !ok {
29 + return "", false
30 + }
31 +
32 + if val, ok = v.(string); !ok {
33 + return "", false
34 + }
35 + delete(d, key)
36 + return val, true
37 +}
38 +
39 +// SentryHook delivers logs to a sentry server.
40 +type SentryHook struct {
41 + // Timeout sets the time to wait for a delivery error from the sentry server.
42 + // If this is set to zero the server will not wait for any response and will
43 + // consider the message correctly sent
44 + Timeout time.Duration
45 +
46 + client *raven.Client
47 + levels []logrus.Level
48 +}
49 +
50 +// NewSentryHook creates a hook to be added to an instance of logger
51 +// and initializes the raven client.
52 +// This method sets the timeout to 100 milliseconds.
53 +func NewSentryHook(DSN string, levels []logrus.Level) (*SentryHook, error) {
54 + client, err := raven.NewClient(DSN, nil)
55 + if err != nil {
56 + return nil, err
57 + }
58 + return &SentryHook{100 * time.Millisecond, client, levels}, nil
59 +}
60 +
61 +// Called when an event should be sent to sentry
62 +// Special fields that sentry uses to give more information to the server
63 +// are extracted from entry.Data (if they are found)
64 +// These fields are: logger and server_name
65 +func (hook *SentryHook) Fire(entry *logrus.Entry) error {
66 + packet := &raven.Packet{
67 + Message: entry.Message,
68 + Timestamp: raven.Timestamp(entry.Time),
69 + Level: severityMap[entry.Level],
70 + Platform: "go",
71 + }
72 +
73 + d := entry.Data
74 +
75 + if logger, ok := getAndDel(d, "logger"); ok {
76 + packet.Logger = logger
77 + }
78 + if serverName, ok := getAndDel(d, "server_name"); ok {
79 + packet.ServerName = serverName
80 + }
81 + packet.Extra = map[string]interface{}(d)
82 +
83 + _, errCh := hook.client.Capture(packet, nil)
84 + timeout := hook.Timeout
85 + if timeout != 0 {
86 + timeoutCh := time.After(timeout)
87 + select {
88 + case err := <-errCh:
89 + return err
90 + case <-timeoutCh:
91 + return fmt.Errorf("no response from sentry server in %s", timeout)
92 + }
93 + }
94 + return nil
95 +}
96 +
97 +// Levels returns the available logging levels.
98 +func (hook *SentryHook) Levels() []logrus.Level {
99 + return hook.levels
100 +}
Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/sentry/sentry_test.go new
+97
@@ -0,0 +1,97 @@
1 +package logrus_sentry
2 +
3 +import (
4 + "encoding/json"
5 + "fmt"
6 + "io/ioutil"
7 + "net/http"
8 + "net/http/httptest"
9 + "strings"
10 + "testing"
11 +
12 + "github.com/getsentry/raven-go"
13 + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/Sirupsen/logrus"
14 +)
15 +
16 +const (
17 + message = "error message"
18 + server_name = "testserver.internal"
19 + logger_name = "test.logger"
20 +)
21 +
22 +func getTestLogger() *logrus.Logger {
23 + l := logrus.New()
24 + l.Out = ioutil.Discard
25 + return l
26 +}
27 +
28 +func WithTestDSN(t *testing.T, tf func(string, <-chan *raven.Packet)) {
29 + pch := make(chan *raven.Packet, 1)
30 + s := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
31 + defer req.Body.Close()
32 + d := json.NewDecoder(req.Body)
33 + p := &raven.Packet{}
34 + err := d.Decode(p)
35 + if err != nil {
36 + t.Fatal(err.Error())
37 + }
38 +
39 + pch <- p
40 + }))
41 + defer s.Close()
42 +
43 + fragments := strings.SplitN(s.URL, "://", 2)
44 + dsn := fmt.Sprintf(
45 + "%s://public:secret@%s/sentry/project-id",
46 + fragments[0],
47 + fragments[1],
48 + )
49 + tf(dsn, pch)
50 +}
51 +
52 +func TestSpecialFields(t *testing.T) {
53 + WithTestDSN(t, func(dsn string, pch <-chan *raven.Packet) {
54 + logger := getTestLogger()
55 +
56 + hook, err := NewSentryHook(dsn, []logrus.Level{
57 + logrus.ErrorLevel,
58 + })
59 +
60 + if err != nil {
61 + t.Fatal(err.Error())
62 + }
63 + logger.Hooks.Add(hook)
64 + logger.WithFields(logrus.Fields{
65 + "server_name": server_name,
66 + "logger": logger_name,
67 + }).Error(message)
68 +
69 + packet := <-pch
70 + if packet.Logger != logger_name {
71 + t.Errorf("logger should have been %s, was %s", logger_name, packet.Logger)
72 + }
73 +
74 + if packet.ServerName != server_name {
75 + t.Errorf("server_name should have been %s, was %s", server_name, packet.ServerName)
76 + }
77 + })
78 +}
79 +
80 +func TestSentryHandler(t *testing.T) {
81 + WithTestDSN(t, func(dsn string, pch <-chan *raven.Packet) {
82 + logger := getTestLogger()
83 + hook, err := NewSentryHook(dsn, []logrus.Level{
84 + logrus.ErrorLevel,
85 + })
86 + if err != nil {
87 + t.Fatal(err.Error())
88 + }
89 + logger.Hooks.Add(hook)
90 +
91 + logger.Error(message)
92 + packet := <-pch
93 + if packet.Message != message {
94 + t.Errorf("message should have been %s, was %s", message, packet.Message)
95 + }
96 + })
97 +}
Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/syslog/README.md renamed
+2 -2
@@ -6,7 +6,7 @@
6 import (
7 "log/syslog"
8 "github.com/Sirupsen/logrus"
9 - "github.com/Sirupsen/logrus/hooks/syslog"
9 + logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
10 )
11
12 func main() {
@@ -17,4 +17,4 @@ func main() {
17 log.Hooks.Add(hook)
18 }
19 }
20 -```
\ No newline at end of file
20 +```
Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/syslog/syslog.go renamed
+8 -8
@@ -2,7 +2,7 @@ package logrus_syslog
2
3 import (
4 "fmt"
5 - "github.com/Sirupsen/logrus"
5 + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/Sirupsen/logrus"
6 "log/syslog"
7 "os"
8 )
@@ -29,18 +29,18 @@ func (hook *SyslogHook) Fire(entry *logrus.Entry) error {
29 return err
30 }
31
32 - switch entry.Data["level"] {
33 - case "panic":
32 + switch entry.Level {
33 + case logrus.PanicLevel:
34 return hook.Writer.Crit(line)
35 - case "fatal":
35 + case logrus.FatalLevel:
36 return hook.Writer.Crit(line)
37 - case "error":
37 + case logrus.ErrorLevel:
38 return hook.Writer.Err(line)
39 - case "warn":
39 + case logrus.WarnLevel:
40 return hook.Writer.Warning(line)
41 - case "info":
41 + case logrus.InfoLevel:
42 return hook.Writer.Info(line)
43 - case "debug":
43 + case logrus.DebugLevel:
44 return hook.Writer.Debug(line)
45 default:
46 return nil
Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go renamed
+1 -1
@@ -1,7 +1,7 @@
1 package logrus_syslog
2
3 import (
4 - "github.com/Sirupsen/logrus"
4 + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/Sirupsen/logrus"
5 "log/syslog"
6 "testing"
7 )
Godeps/_workspace/src/github.com/Sirupsen/logrus/json_formatter.go renamed
+9 -5
@@ -9,12 +9,16 @@ import (
9 type JSONFormatter struct{}
10
11 func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
12 - prefixFieldClashes(entry)
13 - entry.Data["time"] = entry.Time.Format(time.RFC3339)
14 - entry.Data["msg"] = entry.Message
15 - entry.Data["level"] = entry.Level.String()
12 + data := make(Fields, len(entry.Data)+3)
13 + for k, v := range entry.Data {
14 + data[k] = v
15 + }
16 + prefixFieldClashes(data)
17 + data["time"] = entry.Time.Format(time.RFC3339)
18 + data["msg"] = entry.Message
19 + data["level"] = entry.Level.String()
20
17 - serialized, err := json.Marshal(entry.Data)
21 + serialized, err := json.Marshal(data)
22 if err != nil {
23 return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
24 }
Godeps/_workspace/src/github.com/Sirupsen/logrus/logger.go renamed
+1 -1
@@ -38,7 +38,7 @@ type Logger struct {
38 // Out: os.Stderr,
39 // Formatter: new(JSONFormatter),
40 // Hooks: make(levelHooks),
41 -// Level: logrus.Debug,
41 +// Level: logrus.DebugLevel,
42 // }
43 //
44 // It's recommended to make this a global instance called `log`.
Godeps/_workspace/src/github.com/Sirupsen/logrus/logrus.go renamed
Godeps/_workspace/src/github.com/Sirupsen/logrus/logrus_test.go renamed
+56 -2
@@ -5,6 +5,7 @@ import (
5 "encoding/json"
6 "strconv"
7 "strings"
8 + "sync"
9 "testing"
10
11 "github.com/stretchr/testify/assert"
@@ -44,8 +45,12 @@ func LogAndAssertText(t *testing.T, log func(*Logger), assertions func(fields ma
45 }
46 kvArr := strings.Split(kv, "=")
47 key := strings.TrimSpace(kvArr[0])
47 - val, err := strconv.Unquote(kvArr[1])
48 - assert.NoError(t, err)
48 + val := kvArr[1]
49 + if kvArr[1][0] == '"' {
50 + var err error
51 + val, err = strconv.Unquote(val)
52 + assert.NoError(t, err)
53 + }
54 fields[key] = val
55 }
56 assertions(fields)
@@ -204,6 +209,38 @@ func TestDefaultFieldsAreNotPrefixed(t *testing.T) {
209 })
210 }
211
212 +func TestDoubleLoggingDoesntPrefixPreviousFields(t *testing.T) {
213 +
214 + var buffer bytes.Buffer
215 + var fields Fields
216 +
217 + logger := New()
218 + logger.Out = &buffer
219 + logger.Formatter = new(JSONFormatter)
220 +
221 + llog := logger.WithField("context", "eating raw fish")
222 +
223 + llog.Info("looks delicious")
224 +
225 + err := json.Unmarshal(buffer.Bytes(), &fields)
226 + assert.NoError(t, err, "should have decoded first message")
227 + assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields")
228 + assert.Equal(t, fields["msg"], "looks delicious")
229 + assert.Equal(t, fields["context"], "eating raw fish")
230 +
231 + buffer.Reset()
232 +
233 + llog.Warn("omg it is!")
234 +
235 + err = json.Unmarshal(buffer.Bytes(), &fields)
236 + assert.NoError(t, err, "should have decoded second message")
237 + assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields")
238 + assert.Equal(t, fields["msg"], "omg it is!")
239 + assert.Equal(t, fields["context"], "eating raw fish")
240 + assert.Nil(t, fields["fields.msg"], "should not have prefixed previous `msg` entry")
241 +
242 +}
243 +
244 func TestConvertLevelToString(t *testing.T) {
245 assert.Equal(t, "debug", DebugLevel.String())
246 assert.Equal(t, "info", InfoLevel.String())
@@ -245,3 +282,20 @@ func TestParseLevel(t *testing.T) {
282 l, err = ParseLevel("invalid")
283 assert.Equal(t, "not a valid logrus Level: \"invalid\"", err.Error())
284 }
285 +
286 +func TestGetSetLevelRace(t *testing.T) {
287 + wg := sync.WaitGroup{}
288 + for i := 0; i < 100; i++ {
289 + wg.Add(1)
290 + go func(i int) {
291 + defer wg.Done()
292 + if i%2 == 0 {
293 + SetLevel(InfoLevel)
294 + } else {
295 + GetLevel()
296 + }
297 + }(i)
298 +
299 + }
300 + wg.Wait()
301 +}
Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_darwin.go renamed
Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_freebsd.go renamed
Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_linux.go renamed
Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_notwindows.go renamed
+1 -1
@@ -3,7 +3,7 @@
3 // Use of this source code is governed by a BSD-style
4 // license that can be found in the LICENSE file.
5
6 -// +build linux,!appengine darwin freebsd
6 +// +build linux darwin freebsd openbsd
7
8 package logrus
9
Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_openbsd.go new
+8
@@ -0,0 +1,8 @@
1 +
2 +package logrus
3 +
4 +import "syscall"
5 +
6 +const ioctlReadTermios = syscall.TIOCGETA
7 +
8 +type Termios syscall.Termios
Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_windows.go renamed
Godeps/_workspace/src/github.com/Sirupsen/logrus/text_formatter.go renamed
+49 -9
@@ -3,6 +3,7 @@ package logrus
3 import (
4 "bytes"
5 "fmt"
6 + "regexp"
7 "sort"
8 "strings"
9 "time"
@@ -19,6 +20,7 @@ const (
20 var (
21 baseTimestamp time.Time
22 isTerminal bool
23 + noQuoteNeeded *regexp.Regexp
24 )
25
26 func init() {
@@ -32,13 +34,23 @@ func miniTS() int {
34
35 type TextFormatter struct {
36 // Set to true to bypass checking for a TTY before outputting colors.
35 - ForceColors bool
37 + ForceColors bool
38 +
39 + // Force disabling colors.
40 DisableColors bool
41 +
42 + // Disable timestamp logging. useful when output is redirected to logging
43 + // system that already adds timestamps.
44 + DisableTimestamp bool
45 +
46 + // Enable logging the full timestamp when a TTY is attached instead of just
47 + // the time passed since beginning of execution.
48 + FullTimestamp bool
49 }
50
51 func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
52
41 - var keys []string
53 + var keys []string = make([]string, 0, len(entry.Data))
54 for k := range entry.Data {
55 keys = append(keys, k)
56 }
@@ -46,14 +58,16 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
58
59 b := &bytes.Buffer{}
60
49 - prefixFieldClashes(entry)
61 + prefixFieldClashes(entry.Data)
62
63 isColored := (f.ForceColors || isTerminal) && !f.DisableColors
64
65 if isColored {
54 - printColored(b, entry, keys)
66 + f.printColored(b, entry, keys)
67 } else {
56 - f.appendKeyValue(b, "time", entry.Time.Format(time.RFC3339))
68 + if !f.DisableTimestamp {
69 + f.appendKeyValue(b, "time", entry.Time.Format(time.RFC3339))
70 + }
71 f.appendKeyValue(b, "level", entry.Level.String())
72 f.appendKeyValue(b, "msg", entry.Message)
73 for _, key := range keys {
@@ -65,7 +79,7 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
79 return b.Bytes(), nil
80 }
81
68 -func printColored(b *bytes.Buffer, entry *Entry, keys []string) {
82 +func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string) {
83 var levelColor int
84 switch entry.Level {
85 case WarnLevel:
@@ -78,17 +92,43 @@ func printColored(b *bytes.Buffer, entry *Entry, keys []string) {
92
93 levelText := strings.ToUpper(entry.Level.String())[0:4]
94
81 - fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message)
95 + if !f.FullTimestamp {
96 + fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message)
97 + } else {
98 + fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(time.RFC3339), entry.Message)
99 + }
100 for _, k := range keys {
101 v := entry.Data[k]
102 fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=%v", levelColor, k, v)
103 }
104 }
105
106 +func needsQuoting(text string) bool {
107 + for _, ch := range text {
108 + if !((ch >= 'a' && ch <= 'z') ||
109 + (ch >= 'A' && ch <= 'Z') ||
110 + (ch >= '0' && ch < '9') ||
111 + ch == '-' || ch == '.') {
112 + return false
113 + }
114 + }
115 + return true
116 +}
117 +
118 func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key, value interface{}) {
119 switch value.(type) {
90 - case string, error:
91 - fmt.Fprintf(b, "%v=%q ", key, value)
120 + case string:
121 + if needsQuoting(value.(string)) {
122 + fmt.Fprintf(b, "%v=%s ", key, value)
123 + } else {
124 + fmt.Fprintf(b, "%v=%q ", key, value)
125 + }
126 + case error:
127 + if needsQuoting(value.(error).Error()) {
128 + fmt.Fprintf(b, "%v=%s ", key, value)
129 + } else {
130 + fmt.Fprintf(b, "%v=%q ", key, value)
131 + }
132 default:
133 fmt.Fprintf(b, "%v=%v ", key, value)
134 }
Godeps/_workspace/src/github.com/Sirupsen/logrus/text_formatter_test.go new
+33
@@ -0,0 +1,33 @@
1 +package logrus
2 +
3 +import (
4 + "bytes"
5 + "errors"
6 +
7 + "testing"
8 +)
9 +
10 +func TestQuoting(t *testing.T) {
11 + tf := &TextFormatter{DisableColors: true}
12 +
13 + checkQuoting := func(q bool, value interface{}) {
14 + b, _ := tf.Format(WithField("test", value))
15 + idx := bytes.Index(b, ([]byte)("test="))
16 + cont := bytes.Contains(b[idx+5:], []byte{'"'})
17 + if cont != q {
18 + if q {
19 + t.Errorf("quoting expected for: %#v", value)
20 + } else {
21 + t.Errorf("quoting not expected for: %#v", value)
22 + }
23 + }
24 + }
25 +
26 + checkQuoting(false, "abcd")
27 + checkQuoting(false, "v1.0")
28 + checkQuoting(true, "/foobar")
29 + checkQuoting(true, "x y")
30 + checkQuoting(true, "x,y")
31 + checkQuoting(false, errors.New("invalid"))
32 + checkQuoting(true, errors.New("invalid argument"))
33 +}
Godeps/_workspace/src/github.com/Sirupsen/logrus/writer.go new
+31
@@ -0,0 +1,31 @@
1 +package logrus
2 +
3 +import (
4 + "bufio"
5 + "io"
6 + "runtime"
7 +)
8 +
9 +func (logger *Logger) Writer() (*io.PipeWriter) {
10 + reader, writer := io.Pipe()
11 +
12 + go logger.writerScanner(reader)
13 + runtime.SetFinalizer(writer, writerFinalizer)
14 +
15 + return writer
16 +}
17 +
18 +func (logger *Logger) writerScanner(reader *io.PipeReader) {
19 + scanner := bufio.NewScanner(reader)
20 + for scanner.Scan() {
21 + logger.Print(scanner.Text())
22 + }
23 + if err := scanner.Err(); err != nil {
24 + logger.Errorf("Error while reading from Writer: %s", err)
25 + }
26 + reader.Close()
27 +}
28 +
29 +func writerFinalizer(writer *io.PipeWriter) {
30 + writer.Close()
31 +}
Godeps/_workspace/src/github.com/briantigerchow/logrus/.travis.yml deleted
-9
@@ -1,9 +0,0 @@
1 -language: go
2 -go:
3 - - 1.2
4 - - 1.3
5 - - tip
6 -install:
7 - - go get github.com/stretchr/testify
8 - - go get github.com/stvp/go-udp-testing
9 - - go get github.com/tobi/airbrake-go
thirdparty/eventlog/entry.go
+1 -2
@@ -3,8 +3,7 @@ package eventlog
3 import (
4 "time"
5
6 - "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/briantigerchow/logrus"
7 -
6 + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/Sirupsen/logrus"
7 "github.com/jbenet/go-ipfs/util"
8 )
9
thirdparty/eventlog/option.go
+1 -1
@@ -4,7 +4,7 @@ import (
4 "io"
5 "os"
6
7 - "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/briantigerchow/logrus"
7 + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/Sirupsen/logrus"
8 "github.com/jbenet/go-ipfs/Godeps/_workspace/src/gopkg.in/natefinch/lumberjack.v2"
9 )
10
thirdparty/eventlog/polite_json_formatter.go
+1 -1
@@ -4,7 +4,7 @@ import (
4 "encoding/json"
5 "fmt"
6
7 - "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/briantigerchow/logrus"
7 + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/Sirupsen/logrus"
8 )
9
10 // PoliteJSONFormatter marshals entries into JSON encoded slices (without