From 7a1f601cfd7604dd99fa6d6af0aa3e2a3f3de6b4 Mon Sep 17 00:00:00 2001 From: Tony Lee Date: Wed, 31 Aug 2016 23:54:59 +1000 Subject: [PATCH 01/92] Added ability to disable level text truncation. Fixes #406 --- text_formatter.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/text_formatter.go b/text_formatter.go index cce61f2..a51bf19 100644 --- a/text_formatter.go +++ b/text_formatter.go @@ -54,6 +54,9 @@ type TextFormatter struct { // that log extremely frequently and don't use the JSON formatter this may not // be desired. DisableSorting bool + + // Disables the truncation of the level text to 4 characters. + DisableLevelTruncation bool } func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { @@ -113,7 +116,10 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin levelColor = blue } - levelText := strings.ToUpper(entry.Level.String())[0:4] + levelText := strings.ToUpper(entry.Level.String()) + if !f.DisableLevelTruncation { + levelText = levelText[0:4] + } if !f.FullTimestamp { fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message) From e5b6713580618875560ec106fc60a2ac82e14c96 Mon Sep 17 00:00:00 2001 From: Tony Lee Date: Thu, 1 Sep 2016 00:28:23 +1000 Subject: [PATCH 02/92] Added testing for DisableLevelTruncation --- text_formatter_test.go | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/text_formatter_test.go b/text_formatter_test.go index e25a44f..6b5353d 100644 --- a/text_formatter_test.go +++ b/text_formatter_test.go @@ -3,6 +3,7 @@ package logrus import ( "bytes" "errors" + "strings" "testing" "time" ) @@ -57,5 +58,43 @@ func TestTimestampFormat(t *testing.T) { checkTimeStr("") } +func TestDisableLevelTruncation(t *testing.T) { + entry := &Entry{ + Time: time.Now(), + Message: "testing", + } + keys := []string{} + timestampFormat := "Mon Jan 2 15:04:05 -0700 MST 2006" + checkDisableTruncation := func(disabled bool, level Level) { + tf := &TextFormatter{DisableLevelTruncation: disabled} + var b bytes.Buffer + entry.Level = level + tf.printColored(&b, entry, keys, timestampFormat) + logLine := (&b).String() + if disabled { + expected := strings.ToUpper(level.String()) + if !strings.Contains(logLine, expected) { + t.Errorf("level string expected to be %s when truncation disabled", expected) + } + } else { + expected := strings.ToUpper(level.String()) + if len(level.String()) > 4 { + if strings.Contains(logLine, expected) { + t.Errorf("level string %s expected to be truncated to %s when truncation is enabled", expected, expected[0:4]) + } + } else { + if !strings.Contains(logLine, expected) { + t.Errorf("level string expected to be %s when truncation is enabled and level string is below truncation threshold", expected) + } + } + } + } + + checkDisableTruncation(true, DebugLevel) + checkDisableTruncation(true, InfoLevel) + checkDisableTruncation(false, ErrorLevel) + checkDisableTruncation(false, InfoLevel) +} + // TODO add tests for sorting etc., this requires a parser for the text // formatter output. From 1f59c9ad125a4f3f3d172f2b3d67cee2fa217b74 Mon Sep 17 00:00:00 2001 From: Tony Lee Date: Tue, 24 Jan 2017 23:05:25 +1100 Subject: [PATCH 03/92] Add DisableLevelTruncation description to README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 206c746..7622d31 100644 --- a/README.md +++ b/README.md @@ -318,6 +318,8 @@ The built-in logging formatters are: * *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 `DisableColors` field to `true` + * When colors are enabled, levels are truncated to 4 characters by default. To disable + truncation set the `DisableLevelTruncation` field to `true`. * `logrus.JSONFormatter`. Logs fields as JSON. Third party logging formatters: From c44d5246287d92a71847107c7907dd52ce55142a Mon Sep 17 00:00:00 2001 From: Aditya Mukerjee Date: Mon, 9 Oct 2017 11:18:43 -0400 Subject: [PATCH 04/92] Fix typo in docstring --- logger.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logger.go b/logger.go index fdaf8a6..03a5de2 100644 --- a/logger.go +++ b/logger.go @@ -10,7 +10,7 @@ import ( type Logger struct { // The logs are `io.Copy`'d to this in a mutex. It's common to set this to a // file, or leave it default which is `os.Stderr`. You can also set this to - // something more adventorous, such as logging to Kafka. + // something more adventurous, such as logging to Kafka. Out io.Writer // Hooks for the logger instance. These allow firing events based on logging // levels and log entries. For example, to send errors to an error tracking From 639325f81ab8f8610fc69be7b810769c1d99f500 Mon Sep 17 00:00:00 2001 From: Marianne Feng Date: Mon, 6 Nov 2017 16:19:47 -0800 Subject: [PATCH 05/92] added pretty print option for json logs --- README.md | 2 ++ json_formatter.go | 13 ++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5f656c3..f13335e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Logrus :walrus: [![Build Status](https://travis-ci.org/sirupsen/logrus.svg?branch=master)](https://travis-ci.org/sirupsen/logrus) [![GoDoc](https://godoc.org/github.com/sirupsen/logrus?status.svg)](https://godoc.org/github.com/sirupsen/logrus) +**this is an exact clone of the Logrus repo [here](https://github.com/sirupsen/logrus), the only change that has been made is json formatter takes in a setting to pretty print json logs for easier debugging** + Logrus is a structured logger for Go (golang), completely API compatible with the standard library logger. diff --git a/json_formatter.go b/json_formatter.go index fb01c1b..e52ab17 100644 --- a/json_formatter.go +++ b/json_formatter.go @@ -43,6 +43,9 @@ type JSONFormatter struct { // }, // } FieldMap FieldMap + + // PrettyPrint will indent all json logs + PrettyPrint bool } // Format renders a single log entry @@ -71,7 +74,15 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String() - serialized, err := json.Marshal(data) + var serialized []byte + var err error + + if f.PrettyPrint { + serialized, err = json.MarshalIndent(data, "", "\t") + } else { + serialized, err = json.Marshal(data) + } + if err != nil { return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) } From 10d6a5b4272fa06109decc537a040d6a89f9a42f Mon Sep 17 00:00:00 2001 From: Marianne Feng Date: Mon, 6 Nov 2017 16:28:37 -0800 Subject: [PATCH 06/92] removed useless line from readme --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index f13335e..5f656c3 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ # Logrus :walrus: [![Build Status](https://travis-ci.org/sirupsen/logrus.svg?branch=master)](https://travis-ci.org/sirupsen/logrus) [![GoDoc](https://godoc.org/github.com/sirupsen/logrus?status.svg)](https://godoc.org/github.com/sirupsen/logrus) -**this is an exact clone of the Logrus repo [here](https://github.com/sirupsen/logrus), the only change that has been made is json formatter takes in a setting to pretty print json logs for easier debugging** - Logrus is a structured logger for Go (golang), completely API compatible with the standard library logger. From bf1fb70b2b4308a0aed02f31c5f327be46620269 Mon Sep 17 00:00:00 2001 From: Neil Isaac Date: Tue, 21 Nov 2017 22:43:47 -0500 Subject: [PATCH 07/92] Add FieldMap support to TestFormatter --- text_formatter.go | 15 ++++++++++++--- text_formatter_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/text_formatter.go b/text_formatter.go index be412aa..8592825 100644 --- a/text_formatter.go +++ b/text_formatter.go @@ -60,6 +60,15 @@ type TextFormatter struct { // Whether the logger's out is to a terminal isTerminal bool + // FieldMap allows users to customize the names of keys for default fields. + // As an example: + // formatter := &JSONFormatter{ + // FieldMap: FieldMap{ + // FieldKeyTime: "@timestamp", + // FieldKeyLevel: "@level", + // FieldKeyMsg: "@message"}} + FieldMap FieldMap + sync.Once } @@ -109,11 +118,11 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { f.printColored(b, entry, keys, timestampFormat) } else { if !f.DisableTimestamp { - f.appendKeyValue(b, "time", entry.Time.Format(timestampFormat)) + f.appendKeyValue(b, f.FieldMap.resolve(FieldKeyTime), entry.Time.Format(timestampFormat)) } - f.appendKeyValue(b, "level", entry.Level.String()) + f.appendKeyValue(b, f.FieldMap.resolve(FieldKeyLevel), entry.Level.String()) if entry.Message != "" { - f.appendKeyValue(b, "msg", entry.Message) + f.appendKeyValue(b, f.FieldMap.resolve(FieldKeyMsg), entry.Message) } for _, key := range keys { f.appendKeyValue(b, key, entry.Data[key]) diff --git a/text_formatter_test.go b/text_formatter_test.go index d93b931..789d52d 100644 --- a/text_formatter_test.go +++ b/text_formatter_test.go @@ -7,6 +7,8 @@ import ( "strings" "testing" "time" + + "github.com/stretchr/testify/assert" ) func TestFormatting(t *testing.T) { @@ -137,5 +139,32 @@ func TestDisableTimestampWithColoredOutput(t *testing.T) { } } +func TestTextFormatterFieldMap(t *testing.T) { + formatter := &TextFormatter{ + DisableColors: true, + FieldMap: FieldMap{ + FieldKeyMsg: "message", + FieldKeyLevel: "somelevel", + FieldKeyTime: "timeywimey", + }, + } + + entry := &Entry{ + Message: "oh hi", + Level: WarnLevel, + Time: time.Date(1981, time.February, 24, 4, 28, 3, 100, time.UTC), + } + + b, err := formatter.Format(entry) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + + assert.Equal(t, + `timeywimey="1981-02-24T04:28:03Z" somelevel=warning message="oh hi"`+"\n", + string(b), + "Formatted doesn't respect correct FieldMap") +} + // TODO add tests for sorting etc., this requires a parser for the text // formatter output. From b9eceae8f663facb1b89f517fa03e4ae43a5c517 Mon Sep 17 00:00:00 2001 From: Neil Isaac Date: Tue, 21 Nov 2017 22:56:37 -0500 Subject: [PATCH 08/92] fix example --- text_formatter.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/text_formatter.go b/text_formatter.go index 8592825..aa0694c 100644 --- a/text_formatter.go +++ b/text_formatter.go @@ -62,11 +62,11 @@ type TextFormatter struct { // FieldMap allows users to customize the names of keys for default fields. // As an example: - // formatter := &JSONFormatter{ + // formatter := &TextFormatter{ // FieldMap: FieldMap{ - // FieldKeyTime: "@timestamp", + // FieldKeyTime: "@timestamp", // FieldKeyLevel: "@level", - // FieldKeyMsg: "@message"}} + // FieldKeyMsg: "@message"}} FieldMap FieldMap sync.Once From 0c03a05a0e896c23dcd631acafd2f35add6a3fec Mon Sep 17 00:00:00 2001 From: conor Date: Thu, 21 Dec 2017 14:04:49 -0500 Subject: [PATCH 09/92] mirror and wrap Logger instance methods in exported.go --- .gitignore | 1 + exported.go | 16 +++------------- logger.go | 21 +++++++++++++++++++++ 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index 66be63a..c722487 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ logrus +.idea \ No newline at end of file diff --git a/exported.go b/exported.go index 013183e..141e951 100644 --- a/exported.go +++ b/exported.go @@ -15,36 +15,26 @@ func StandardLogger() *Logger { // SetOutput sets the standard logger output. func SetOutput(out io.Writer) { - std.mu.Lock() - defer std.mu.Unlock() - std.Out = out + std.SetOutput(out) } // SetFormatter sets the standard logger formatter. func SetFormatter(formatter Formatter) { - std.mu.Lock() - defer std.mu.Unlock() - std.Formatter = formatter + std.SetFormatter(formatter) } // SetLevel sets the standard logger level. func SetLevel(level Level) { - std.mu.Lock() - defer std.mu.Unlock() std.SetLevel(level) } // GetLevel returns the standard logger level. func GetLevel() Level { - std.mu.Lock() - defer std.mu.Unlock() - return std.level() + return std.GetLevel() } // AddHook adds a hook to the standard logger hooks. func AddHook(hook Hook) { - std.mu.Lock() - defer std.mu.Unlock() std.Hooks.Add(hook) } diff --git a/logger.go b/logger.go index fdaf8a6..91617fc 100644 --- a/logger.go +++ b/logger.go @@ -312,12 +312,33 @@ func (logger *Logger) level() Level { return Level(atomic.LoadUint32((*uint32)(&logger.Level))) } +// SetLevel sets the logger level. func (logger *Logger) SetLevel(level Level) { atomic.StoreUint32((*uint32)(&logger.Level), uint32(level)) } +// GetLevel returns the logger level. +func (logger *Logger) GetLevel() Level { + return logger.level() +} + +// AddHook adds a hook to the logger hooks. func (logger *Logger) AddHook(hook Hook) { logger.mu.Lock() defer logger.mu.Unlock() logger.Hooks.Add(hook) } + +// SetFormatter sets the logger formatter. +func (logger *Logger) SetFormatter(formatter Formatter) { + logger.mu.Lock() + defer logger.mu.Unlock() + logger.Formatter = formatter +} + +// SetOutput sets the logger output. +func (logger *Logger) SetOutput(output io.Writer) { + logger.mu.Lock() + defer logger.mu.Unlock() + logger.Out = output +} From 20cc8e2bc33863de7191b9bfb55d27804e05e90e Mon Sep 17 00:00:00 2001 From: conor Date: Thu, 21 Dec 2017 14:10:48 -0500 Subject: [PATCH 10/92] remove .gitignore changes --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index c722487..bb7e111 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ -logrus -.idea \ No newline at end of file +logrus \ No newline at end of file From eb156905d7c48f0f2191a3f805e59849c9c018ed Mon Sep 17 00:00:00 2001 From: conor Date: Thu, 21 Dec 2017 14:16:49 -0500 Subject: [PATCH 11/92] remove .gitignore changes and update AddHook --- .gitignore | 2 +- exported.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index bb7e111..66be63a 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -logrus \ No newline at end of file +logrus diff --git a/exported.go b/exported.go index 141e951..e5e484f 100644 --- a/exported.go +++ b/exported.go @@ -35,7 +35,7 @@ func GetLevel() Level { // AddHook adds a hook to the standard logger hooks. func AddHook(hook Hook) { - std.Hooks.Add(hook) + std.AddHook(hook) } // WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key. From 92aece568bf7ac7d2008928efa09da14b63395fe Mon Sep 17 00:00:00 2001 From: Dennis de Reus Date: Fri, 29 Dec 2017 20:26:35 +0100 Subject: [PATCH 12/92] TextFormatter behaviour aligned with stdlib log (fixes #167) stdlib `log` adds a newline at the end of a message if none is present, otherwise does not. Before this change logrus would always add a newline, resulting in inconsistent behaviour if stdlib log was replaced with logrus, and a user would e.g. use 'log.printf("test\n")' --- text_formatter.go | 4 ++++ text_formatter_test.go | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/text_formatter.go b/text_formatter.go index 61b21ca..9f7dc35 100644 --- a/text_formatter.go +++ b/text_formatter.go @@ -126,6 +126,10 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin levelText := strings.ToUpper(entry.Level.String())[0:4] + // Remove a single newline if it already exists in the message to keep + // the behavior of logrus text_formatter the same as the stdlib log package + entry.Message = strings.TrimSuffix(entry.Message, "\n") + if f.DisableTimestamp { fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m %-44s ", levelColor, levelText, entry.Message) } else if !f.FullTimestamp { diff --git a/text_formatter_test.go b/text_formatter_test.go index d93b931..aea8727 100644 --- a/text_formatter_test.go +++ b/text_formatter_test.go @@ -137,5 +137,28 @@ func TestDisableTimestampWithColoredOutput(t *testing.T) { } } +func TestNewlineBehavior(t *testing.T) { + tf := &TextFormatter{ForceColors: true} + + // Ensure a single new line is removed as per stdlib log + e := NewEntry(StandardLogger()) + e.Message = "test message\n" + b, _ := tf.Format(e) + if bytes.Contains(b, []byte("test message\n")) { + t.Error("first newline at end of Entry.Message resulted in unexpected 2 newlines in output. Expected newline to be removed.") + } + + // Ensure a double new line is reduced to a single new line + e = NewEntry(StandardLogger()) + e.Message = "test message\n\n" + b, _ = tf.Format(e) + if bytes.Contains(b, []byte("test message\n\n")) { + t.Error("Double newline at end of Entry.Message resulted in unexpected 2 newlines in output. Expected single newline") + } + if !bytes.Contains(b, []byte("test message\n")) { + t.Error("Double newline at end of Entry.Message did not result in a single newline after formatting") + } +} + // TODO add tests for sorting etc., this requires a parser for the text // formatter output. From efbfdb5f09fe8f6efee1efd21ae690156304cf36 Mon Sep 17 00:00:00 2001 From: Michael Haines Date: Mon, 5 Feb 2018 12:42:00 -0700 Subject: [PATCH 13/92] Add failing test for using a FieldLogger with hooks inside goroutines --- logrus_test.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/logrus_test.go b/logrus_test.go index 78cbc28..1585709 100644 --- a/logrus_test.go +++ b/logrus_test.go @@ -343,6 +343,24 @@ func TestLoggingRace(t *testing.T) { wg.Wait() } +func TestLoggingRaceWithHooksOnFieldLogger(t *testing.T) { + logger := New() + hook := new(ModifyHook) + logger.AddHook(hook) + fieldLogger := logger.WithField("context", "clue") + + var wg sync.WaitGroup + wg.Add(100) + + for i := 0; i < 100; i++ { + go func() { + fieldLogger.Info("info") + wg.Done() + }() + } + wg.Wait() +} + // Compile test func TestLogrusInterface(t *testing.T) { var buffer bytes.Buffer From eeb653535cb49f0aee7aefce8583b2593d4466fd Mon Sep 17 00:00:00 2001 From: Michael Haines Date: Mon, 5 Feb 2018 12:44:11 -0700 Subject: [PATCH 14/92] Lock mutex before formatting to avoid race --- entry.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entry.go b/entry.go index df6f92d..24ded45 100644 --- a/entry.go +++ b/entry.go @@ -123,9 +123,9 @@ func (entry *Entry) fireHooks() { } func (entry *Entry) write() { - serialized, err := entry.Logger.Formatter.Format(entry) entry.Logger.mu.Lock() defer entry.Logger.mu.Unlock() + serialized, err := entry.Logger.Formatter.Format(entry) if err != nil { fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err) } else { From 828a649ef2d3660936a7182dadbf5573de38433d Mon Sep 17 00:00:00 2001 From: Michael Haines Date: Mon, 5 Feb 2018 12:52:11 -0700 Subject: [PATCH 15/92] rename fieldLogger to entry --- logrus_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/logrus_test.go b/logrus_test.go index 1585709..cd17602 100644 --- a/logrus_test.go +++ b/logrus_test.go @@ -343,18 +343,18 @@ func TestLoggingRace(t *testing.T) { wg.Wait() } -func TestLoggingRaceWithHooksOnFieldLogger(t *testing.T) { +func TestLoggingRaceWithHooksOnEntry(t *testing.T) { logger := New() hook := new(ModifyHook) logger.AddHook(hook) - fieldLogger := logger.WithField("context", "clue") + entry := logger.WithField("context", "clue") var wg sync.WaitGroup wg.Add(100) for i := 0; i < 100; i++ { go func() { - fieldLogger.Info("info") + entry.Info("info") wg.Done() }() } From efab7f37b72e69e1112ed5f79384698df7030da8 Mon Sep 17 00:00:00 2001 From: Lyra Naeseth Date: Tue, 13 Feb 2018 17:44:51 -0800 Subject: [PATCH 16/92] Have prefixFieldClashes respect the JSON FieldMap Currently, it will fix clashes that don't exist and miss clashes that do exist due to field remapping. Fixes #708 --- formatter.go | 17 +++++++------ json_formatter.go | 2 +- json_formatter_test.go | 55 ++++++++++++++++++++++++++++++++++++++++++ text_formatter.go | 3 ++- 4 files changed, 68 insertions(+), 9 deletions(-) diff --git a/formatter.go b/formatter.go index b183ff5..849dc8b 100644 --- a/formatter.go +++ b/formatter.go @@ -30,16 +30,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(data Fields) { - if t, ok := data["time"]; ok { - data["fields.time"] = t +func prefixFieldClashes(data Fields, fieldMap FieldMap) { + timeKey := fieldMap.resolve(FieldKeyTime) + if t, ok := data[timeKey]; ok { + data["fields."+timeKey] = t } - if m, ok := data["msg"]; ok { - data["fields.msg"] = m + msgKey := fieldMap.resolve(FieldKeyMsg) + if m, ok := data[msgKey]; ok { + data["fields."+msgKey] = m } - if l, ok := data["level"]; ok { - data["fields.level"] = l + levelKey := fieldMap.resolve(FieldKeyLevel) + if l, ok := data[levelKey]; ok { + data["fields."+levelKey] = l } } diff --git a/json_formatter.go b/json_formatter.go index fb01c1b..7064947 100644 --- a/json_formatter.go +++ b/json_formatter.go @@ -58,7 +58,7 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { data[k] = v } } - prefixFieldClashes(data) + prefixFieldClashes(data, f.FieldMap) timestampFormat := f.TimestampFormat if timestampFormat == "" { diff --git a/json_formatter_test.go b/json_formatter_test.go index 51093a7..1c140d0 100644 --- a/json_formatter_test.go +++ b/json_formatter_test.go @@ -3,6 +3,7 @@ package logrus import ( "encoding/json" "errors" + "fmt" "strings" "testing" ) @@ -106,6 +107,60 @@ func TestFieldClashWithLevel(t *testing.T) { } } +func TestFieldClashWithRemappedFields(t *testing.T) { + formatter := &JSONFormatter{ + FieldMap: FieldMap{ + FieldKeyTime: "@timestamp", + FieldKeyLevel: "@level", + FieldKeyMsg: "@message", + }, + } + + b, err := formatter.Format(WithFields(Fields{ + "@timestamp": "@timestamp", + "@level": "@level", + "@message": "@message", + "timestamp": "timestamp", + "level": "level", + "msg": "msg", + })) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + + entry := make(map[string]interface{}) + err = json.Unmarshal(b, &entry) + if err != nil { + t.Fatal("Unable to unmarshal formatted entry: ", err) + } + + for _, field := range []string{"timestamp", "level", "msg"} { + if entry[field] != field { + t.Errorf("Expected field %v to be untouched; got %v", field, entry[field]) + } + + remappedKey := fmt.Sprintf("fields.%s", field) + if remapped, ok := entry[remappedKey]; ok { + t.Errorf("Expected %s to be empty; got %v", remappedKey, remapped) + } + } + + for _, field := range []string{"@timestamp", "@level", "@message"} { + if entry[field] == field { + t.Errorf("Expected field %v to be mapped to an Entry value", field) + } + + remappedKey := fmt.Sprintf("fields.%s", field) + if remapped, ok := entry[remappedKey]; ok { + if remapped != field { + t.Errorf("Expected field %v to be copied to %s; got %v", field, remappedKey, remapped) + } + } else { + t.Errorf("Expected field %v to be copied to %s; was absent", field, remappedKey) + } + } +} + func TestJSONEntryEndsWithNewline(t *testing.T) { formatter := &JSONFormatter{} diff --git a/text_formatter.go b/text_formatter.go index 61b21ca..62763eb 100644 --- a/text_formatter.go +++ b/text_formatter.go @@ -20,6 +20,7 @@ const ( var ( baseTimestamp time.Time + emptyFieldMap FieldMap ) func init() { @@ -82,7 +83,7 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { b = &bytes.Buffer{} } - prefixFieldClashes(entry.Data) + prefixFieldClashes(entry.Data, emptyFieldMap) f.Do(func() { f.init(entry) }) From f4118d2ead4e96d931fd6751a831165147c99889 Mon Sep 17 00:00:00 2001 From: Andrew Rezcov Date: Fri, 16 Feb 2018 16:50:54 +0300 Subject: [PATCH 17/92] reamde: add logrus-clickhouse-hook --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index bc3f9bc..be18d2f 100644 --- a/README.md +++ b/README.md @@ -250,6 +250,7 @@ Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/v | [Application Insights](https://github.com/jjcollinge/logrus-appinsights) | Hook for logging to [Application Insights](https://azure.microsoft.com/en-us/services/application-insights/) | [AzureTableHook](https://github.com/kpfaulkner/azuretablehook/) | Hook for logging to Azure Table Storage| | [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. | +| [ClickHouse](https://github.com/oxgrouby/logrus-clickhouse-hook) | Send logs to [ClickHouse](https://clickhouse.yandex/) | | [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic | | [Discordrus](https://github.com/kz/discordrus) | Hook for logging to [Discord](https://discordapp.com/) | | [ElasticSearch](https://github.com/sohlich/elogrus) | Hook for logging to ElasticSearch| From 1893e9a3ed8dc59e4aee1e08451d2e2b68030f23 Mon Sep 17 00:00:00 2001 From: earlzo Date: Tue, 20 Feb 2018 16:28:12 +0800 Subject: [PATCH 18/92] Fixed: comment --- entry.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entry.go b/entry.go index 778f4c9..d075d72 100644 --- a/entry.go +++ b/entry.go @@ -48,7 +48,7 @@ type Entry struct { func NewEntry(logger *Logger) *Entry { return &Entry{ Logger: logger, - // Default is three fields, give a little extra room + // Default is five fields, give a little extra room Data: make(Fields, 5), } } From c155da19408a8799da419ed3eeb0cb5db0ad5dbc Mon Sep 17 00:00:00 2001 From: Simon Eskildsen Date: Sun, 11 Mar 2018 18:51:37 -0400 Subject: [PATCH 19/92] changelog: add 1.0.5 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc58f64..1bd1deb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# 1.0.5 + +* Fix hooks race (#707) +* Fix panic deadlock (#695) + # 1.0.4 * Fix race when adding hooks (#612) From 723dd3cd1f7a69421a05118059a9ed644bdd3d12 Mon Sep 17 00:00:00 2001 From: Marianne Feng Date: Tue, 20 Mar 2018 18:20:51 -0700 Subject: [PATCH 20/92] changed prettyprinting to use spaces as opposed to /t --- json_formatter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json_formatter.go b/json_formatter.go index e52ab17..dab5a10 100644 --- a/json_formatter.go +++ b/json_formatter.go @@ -78,7 +78,7 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { var err error if f.PrettyPrint { - serialized, err = json.MarshalIndent(data, "", "\t") + serialized, err = json.MarshalIndent(data, "", " ") } else { serialized, err = json.Marshal(data) } From b537da569f520c93fccbef2c4f327d6001a487a3 Mon Sep 17 00:00:00 2001 From: Wilson Date: Fri, 9 Mar 2018 21:57:56 -0800 Subject: [PATCH 21/92] Fix run-on sentence --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f77819b..1d8eb0d 100644 --- a/README.md +++ b/README.md @@ -495,7 +495,7 @@ logrus.RegisterExitHandler(handler) #### Thread safety -By default Logger is protected by mutex for concurrent writes, this mutex is invoked when calling hooks and writing logs. +By default, Logger is protected by a mutex for concurrent writes. The mutex is held when calling hooks and writing logs. If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking. Situation when locking is not needed includes: From 19b9c9e1ff590d9fd87306010add170f8f4cf07d Mon Sep 17 00:00:00 2001 From: Olzhas Ilyubayev Date: Wed, 28 Mar 2018 12:10:14 +0600 Subject: [PATCH 22/92] delete dead link https://github.com/ripcurld00d/logrus-logzio-hook isn't available now --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 9751da1..e2dbb27 100644 --- a/README.md +++ b/README.md @@ -294,7 +294,6 @@ Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/v | [Telegram](https://github.com/rossmcdonald/telegram_hook) | Hook for logging errors to [Telegram](https://telegram.org/) | | [TraceView](https://github.com/evalphobia/logrus_appneta) | Hook for logging to [AppNeta TraceView](https://www.appneta.com/products/traceview/) | | [Typetalk](https://github.com/dragon3/logrus-typetalk-hook) | Hook for logging to [Typetalk](https://www.typetalk.in/) | -| [logz.io](https://github.com/ripcurld00d/logrus-logzio-hook) | Hook for logging to [logz.io](https://logz.io), a Log as a Service using Logstash | | [SQS-Hook](https://github.com/tsarpaul/logrus_sqs) | Hook for logging to [Amazon Simple Queue Service (SQS)](https://aws.amazon.com/sqs/) | #### Level logging From bb487e068c121ad7129d3d4b6628507038d85d7a Mon Sep 17 00:00:00 2001 From: Felix Kollmann Date: Tue, 3 Apr 2018 00:25:30 +0200 Subject: [PATCH 23/92] Added support for text coloring on Windows 10 --- text_formatter.go | 2 ++ text_formatter_linux.go | 6 ++++++ text_formatter_windows.go | 19 +++++++++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 text_formatter_linux.go create mode 100644 text_formatter_windows.go diff --git a/text_formatter.go b/text_formatter.go index ae91edd..afd9ffb 100644 --- a/text_formatter.go +++ b/text_formatter.go @@ -67,6 +67,8 @@ type TextFormatter struct { func (f *TextFormatter) init(entry *Entry) { if entry.Logger != nil { f.isTerminal = checkIfTerminal(entry.Logger.Out) + + f.initTerminal(entry) } } diff --git a/text_formatter_linux.go b/text_formatter_linux.go new file mode 100644 index 0000000..e5fa6a9 --- /dev/null +++ b/text_formatter_linux.go @@ -0,0 +1,6 @@ +// +build !appengine,!gopherjs + +package logrus + +func (f *TextFormatter) initTerminal(entry *Entry) { +} diff --git a/text_formatter_windows.go b/text_formatter_windows.go new file mode 100644 index 0000000..552c5f3 --- /dev/null +++ b/text_formatter_windows.go @@ -0,0 +1,19 @@ +// +build !appengine,!gopherjs + +package logrus + +import ( + "os" + "syscall" + + sequences "github.com/konsorten/go-windows-terminal-sequences" +) + +func (f *TextFormatter) initTerminal(entry *Entry) { + switch v := entry.Logger.Out.(type) { + case *os.File: + handle := syscall.Handle(v.Fd()) + + sequences.EnableVirtualTerminalProcessing(handle, true) + } +} From f142d8145bc6c072eb15937ab37cb6ede92d579e Mon Sep 17 00:00:00 2001 From: Felix Kollmann Date: Tue, 3 Apr 2018 01:15:45 +0200 Subject: [PATCH 24/92] Improved building of non-windows code --- text_formatter_linux.go => text_formatter_nonwindows.go | 2 +- text_formatter_windows.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename text_formatter_linux.go => text_formatter_nonwindows.go (64%) diff --git a/text_formatter_linux.go b/text_formatter_nonwindows.go similarity index 64% rename from text_formatter_linux.go rename to text_formatter_nonwindows.go index e5fa6a9..f732b8b 100644 --- a/text_formatter_linux.go +++ b/text_formatter_nonwindows.go @@ -1,4 +1,4 @@ -// +build !appengine,!gopherjs +// +build !appengine,!gopherjs,!windows package logrus diff --git a/text_formatter_windows.go b/text_formatter_windows.go index 552c5f3..c9045a0 100644 --- a/text_formatter_windows.go +++ b/text_formatter_windows.go @@ -1,4 +1,4 @@ -// +build !appengine,!gopherjs +// +build !appengine,!gopherjs,windows package logrus From 7d2a5214bf851c9c13289e475a486b1761375216 Mon Sep 17 00:00:00 2001 From: Felix Kollmann Date: Tue, 3 Apr 2018 01:23:44 +0200 Subject: [PATCH 25/92] Extended conditions to include non-native builds --- text_formatter_nonwindows.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text_formatter_nonwindows.go b/text_formatter_nonwindows.go index f732b8b..0c0802a 100644 --- a/text_formatter_nonwindows.go +++ b/text_formatter_nonwindows.go @@ -1,4 +1,4 @@ -// +build !appengine,!gopherjs,!windows +// +build appengine gopherjs !windows package logrus From c9a46a1e7c34ec07a1ffd66147e654d85ac94e36 Mon Sep 17 00:00:00 2001 From: Felix Kollmann Date: Tue, 3 Apr 2018 04:40:58 +0200 Subject: [PATCH 26/92] Added terminal check on Windows --- terminal_check_notappengine.go | 2 +- terminal_check_windows.go | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 terminal_check_windows.go diff --git a/terminal_check_notappengine.go b/terminal_check_notappengine.go index 067047a..e5a5186 100644 --- a/terminal_check_notappengine.go +++ b/terminal_check_notappengine.go @@ -1,4 +1,4 @@ -// +build !appengine,!gopherjs +// +build !appengine,!gopherjs,!windows package logrus diff --git a/terminal_check_windows.go b/terminal_check_windows.go new file mode 100644 index 0000000..17ebe80 --- /dev/null +++ b/terminal_check_windows.go @@ -0,0 +1,20 @@ +// +build !appengine,!gopherjs,windows + +package logrus + +import ( + "io" + "os" + "syscall" +) + +func checkIfTerminal(w io.Writer) bool { + switch v := w.(type) { + case *os.File: + var mode uint32 + err := syscall.GetConsoleMode(syscall.Handle(v.Fd()), &mode) + return err == nil + default: + return false + } +} From cf5eba7dfdefae2d33eb00af1e805bc31f6c4151 Mon Sep 17 00:00:00 2001 From: Felix Kollmann Date: Tue, 3 Apr 2018 04:47:29 +0200 Subject: [PATCH 27/92] Simplified file structure --- terminal_bsd.go | 3 +++ terminal_linux.go | 3 +++ text_formatter_windows.go => terminal_windows.go | 0 text_formatter_nonwindows.go | 6 ------ 4 files changed, 6 insertions(+), 6 deletions(-) rename text_formatter_windows.go => terminal_windows.go (100%) delete mode 100644 text_formatter_nonwindows.go diff --git a/terminal_bsd.go b/terminal_bsd.go index 4880d13..3b20604 100644 --- a/terminal_bsd.go +++ b/terminal_bsd.go @@ -8,3 +8,6 @@ import "golang.org/x/sys/unix" const ioctlReadTermios = unix.TIOCGETA type Termios unix.Termios + +func (f *TextFormatter) initTerminal(entry *Entry) { +} diff --git a/terminal_linux.go b/terminal_linux.go index f29a009..78c4298 100644 --- a/terminal_linux.go +++ b/terminal_linux.go @@ -12,3 +12,6 @@ import "golang.org/x/sys/unix" const ioctlReadTermios = unix.TCGETS type Termios unix.Termios + +func (f *TextFormatter) initTerminal(entry *Entry) { +} diff --git a/text_formatter_windows.go b/terminal_windows.go similarity index 100% rename from text_formatter_windows.go rename to terminal_windows.go diff --git a/text_formatter_nonwindows.go b/text_formatter_nonwindows.go deleted file mode 100644 index 0c0802a..0000000 --- a/text_formatter_nonwindows.go +++ /dev/null @@ -1,6 +0,0 @@ -// +build appengine gopherjs !windows - -package logrus - -func (f *TextFormatter) initTerminal(entry *Entry) { -} From 9bc59a596929f70e795b6a59bdf95b8c90cb9a7f Mon Sep 17 00:00:00 2001 From: Felix Kollmann Date: Tue, 3 Apr 2018 04:50:50 +0200 Subject: [PATCH 28/92] Fixed initTerminal() was run for non-terminals --- text_formatter.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/text_formatter.go b/text_formatter.go index afd9ffb..c62c412 100644 --- a/text_formatter.go +++ b/text_formatter.go @@ -51,7 +51,6 @@ type TextFormatter struct { // be desired. DisableSorting bool - // Disables the truncation of the level text to 4 characters. DisableLevelTruncation bool @@ -68,7 +67,9 @@ func (f *TextFormatter) init(entry *Entry) { if entry.Logger != nil { f.isTerminal = checkIfTerminal(entry.Logger.Out) - f.initTerminal(entry) + if f.isTerminal { + f.initTerminal(entry) + } } } From 2f58bc83cb1aaa88d642d561af062b7a04d15129 Mon Sep 17 00:00:00 2001 From: Felix Kollmann Date: Tue, 3 Apr 2018 04:55:52 +0200 Subject: [PATCH 29/92] Unified terminal initialization code handling --- terminal_bsd.go | 8 ++++++-- terminal_linux.go | 8 ++++++-- terminal_windows.go | 9 ++++----- text_formatter.go | 2 +- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/terminal_bsd.go b/terminal_bsd.go index 3b20604..c498bcd 100644 --- a/terminal_bsd.go +++ b/terminal_bsd.go @@ -3,11 +3,15 @@ package logrus -import "golang.org/x/sys/unix" +import ( + "io" + + "golang.org/x/sys/unix" +) const ioctlReadTermios = unix.TIOCGETA type Termios unix.Termios -func (f *TextFormatter) initTerminal(entry *Entry) { +func initTerminal(w io.Writer) { } diff --git a/terminal_linux.go b/terminal_linux.go index 78c4298..6eb013e 100644 --- a/terminal_linux.go +++ b/terminal_linux.go @@ -7,11 +7,15 @@ package logrus -import "golang.org/x/sys/unix" +import ( + "io" + + "golang.org/x/sys/unix" +) const ioctlReadTermios = unix.TCGETS type Termios unix.Termios -func (f *TextFormatter) initTerminal(entry *Entry) { +func initTerminal(w io.Writer) { } diff --git a/terminal_windows.go b/terminal_windows.go index c9045a0..2494950 100644 --- a/terminal_windows.go +++ b/terminal_windows.go @@ -3,17 +3,16 @@ package logrus import ( + "io" "os" "syscall" sequences "github.com/konsorten/go-windows-terminal-sequences" ) -func (f *TextFormatter) initTerminal(entry *Entry) { - switch v := entry.Logger.Out.(type) { +func initTerminal(w io.Writer) { + switch v := w.(type) { case *os.File: - handle := syscall.Handle(v.Fd()) - - sequences.EnableVirtualTerminalProcessing(handle, true) + sequences.EnableVirtualTerminalProcessing(syscall.Handle(v.Fd()), true) } } diff --git a/text_formatter.go b/text_formatter.go index c62c412..b4e1f0a 100644 --- a/text_formatter.go +++ b/text_formatter.go @@ -68,7 +68,7 @@ func (f *TextFormatter) init(entry *Entry) { f.isTerminal = checkIfTerminal(entry.Logger.Out) if f.isTerminal { - f.initTerminal(entry) + initTerminal(entry.Logger.Out) } } } From 5513c600346d78234f1addc60f4953908cdd79c5 Mon Sep 17 00:00:00 2001 From: David Bariod Date: Mon, 16 Apr 2018 14:16:44 +0200 Subject: [PATCH 30/92] Improve documentation for Fatal* class functions --- exported.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/exported.go b/exported.go index 013183e..dfd982a 100644 --- a/exported.go +++ b/exported.go @@ -107,7 +107,7 @@ func Panic(args ...interface{}) { std.Panic(args...) } -// Fatal logs a message at level Fatal on the standard logger. +// Fatal logs a message at level Fatal on the standard logger then the process will exit with status set to 1. func Fatal(args ...interface{}) { std.Fatal(args...) } @@ -147,7 +147,7 @@ func Panicf(format string, args ...interface{}) { std.Panicf(format, args...) } -// Fatalf logs a message at level Fatal on the standard logger. +// Fatalf logs a message at level Fatal on the standard logger then the process will exit with status set to 1. func Fatalf(format string, args ...interface{}) { std.Fatalf(format, args...) } @@ -187,7 +187,7 @@ func Panicln(args ...interface{}) { std.Panicln(args...) } -// Fatalln logs a message at level Fatal on the standard logger. +// Fatalln logs a message at level Fatal on the standard logger then the process will exit with status set to 1. func Fatalln(args ...interface{}) { std.Fatalln(args...) } From e63a8df3408cef283af0fdc0335b235093e2f657 Mon Sep 17 00:00:00 2001 From: dbs5 Date: Mon, 16 Apr 2018 20:20:18 +0200 Subject: [PATCH 31/92] added Anexia CloudLog to list of hooks --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a29222c..46a63e5 100644 --- a/README.md +++ b/README.md @@ -247,6 +247,7 @@ Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/v | [Airbrake](https://github.com/gemnasium/logrus-airbrake-hook) | Send errors to the Airbrake API V3. Uses the official [`gobrake`](https://github.com/airbrake/gobrake) behind the scenes. | | [Amazon Kinesis](https://github.com/evalphobia/logrus_kinesis) | Hook for logging to [Amazon Kinesis](https://aws.amazon.com/kinesis/) | | [Amqp-Hook](https://github.com/vladoatanasov/logrus_amqp) | Hook for logging to Amqp broker (Like RabbitMQ) | +| [Anexia CloudLog](https://github.com/anexia-it/go-logrus-cloudlog) | Hook for logging to Anexia CloudLog | | [Application Insights](https://github.com/jjcollinge/logrus-appinsights) | Hook for logging to [Application Insights](https://azure.microsoft.com/en-us/services/application-insights/) | [AzureTableHook](https://github.com/kpfaulkner/azuretablehook/) | Hook for logging to Azure Table Storage| | [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. | From 507c822874d4d270d57b229fb5fcee832fbe92d4 Mon Sep 17 00:00:00 2001 From: lyric Date: Fri, 27 Apr 2018 17:53:47 +0800 Subject: [PATCH 32/92] add mysql hook --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a29222c..33711e4 100644 --- a/README.md +++ b/README.md @@ -275,6 +275,7 @@ Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/v | [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail | | [Mattermost](https://github.com/shuLhan/mattermost-integration/tree/master/hooks/logrus) | Hook for logging to [Mattermost](https://mattermost.com/) | | [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb | +| [MySQL](https://github.com/LyricTian/logrus-mysql-hook) | Hook for logging to mysql | | [NATS-Hook](https://github.com/rybit/nats_logrus_hook) | Hook for logging to [NATS](https://nats.io) | | [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit | | [Papertrail](https://github.com/polds/logrus-papertrail-hook) | Send errors to the [Papertrail](https://papertrailapp.com) hosted logging service via UDP. | From 8369e2f077642788e2ef31f342a0a4621b2b4607 Mon Sep 17 00:00:00 2001 From: David Bariod Date: Sat, 12 May 2018 15:51:19 +0200 Subject: [PATCH 33/92] Fix a race condition in TestLoggingWithHooksRace --- hooks/test/test_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hooks/test/test_test.go b/hooks/test/test_test.go index dea768e..742be55 100644 --- a/hooks/test/test_test.go +++ b/hooks/test/test_test.go @@ -51,11 +51,11 @@ func TestLoggingWithHooksRace(t *testing.T) { }() } + wg.Wait() + assert.Equal(logrus.InfoLevel, hook.LastEntry().Level) assert.Equal("info", hook.LastEntry().Message) - wg.Wait() - entries := hook.AllEntries() assert.Equal(100, len(entries)) } From b1e82bef65601dc1a84c16904c337b0a4011ae74 Mon Sep 17 00:00:00 2001 From: David Bariod Date: Sun, 13 May 2018 10:29:45 +0200 Subject: [PATCH 34/92] Update go versions in travis configuration. We only keep the latest 3 language release. Fixes #753 --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index a23296a..aebdc35 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,8 @@ language: go go: - - 1.6.x - - 1.7.x - 1.8.x + - 1.9.x + - 1.10.x - tip env: - GOMAXPROCS=4 GORACE=halt_on_error=1 From aa6766adfe97f5f5d05f9bd694986d171db9b4ff Mon Sep 17 00:00:00 2001 From: taylorchu Date: Tue, 15 May 2018 10:07:01 -0700 Subject: [PATCH 35/92] PERF: use buffer pool in json formatter benchmark old ns/op new ns/op delta BenchmarkLogrus-8 4163 4369 +4.95% benchmark old allocs new allocs delta BenchmarkLogrus-8 36 31 -13.89% benchmark old bytes new bytes delta BenchmarkLogrus-8 3027 2163 -28.54% --- json_formatter.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/json_formatter.go b/json_formatter.go index 7064947..82a1da8 100644 --- a/json_formatter.go +++ b/json_formatter.go @@ -1,6 +1,7 @@ package logrus import ( + "bytes" "encoding/json" "fmt" ) @@ -71,9 +72,15 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String() - serialized, err := json.Marshal(data) + var b *bytes.Buffer + if entry.Buffer != nil { + b = entry.Buffer + } else { + b = &bytes.Buffer{} + } + err := json.NewEncoder(b).Encode(data) if err != nil { return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) } - return append(serialized, '\n'), nil + return b.Bytes(), nil } From caed59ec68033ac87a3ef67eccf1d52282efc1bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=87o?= Date: Thu, 17 May 2018 11:02:39 +0200 Subject: [PATCH 36/92] Fix Logger.WithField doscription I was puzzled by function documentation not mentioning it works with Error level, so I had to check it out by creating example before I add logrus as a dependency on the company project. Example confirmed what logic was telling me that Logger.WithFields works with Error level of logs. This is is a fix of this small documentation oversight. --- logger.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logger.go b/logger.go index fdaf8a6..0ac8ce2 100644 --- a/logger.go +++ b/logger.go @@ -88,7 +88,7 @@ func (logger *Logger) releaseEntry(entry *Entry) { } // Adds a field to the log entry, note that it doesn't log until you call -// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry. +// Debug, Print, Info, Warn, Error, Fatal or Panic. It only creates a log entry. // If you want multiple fields, use `WithFields`. func (logger *Logger) WithField(key string, value interface{}) *Entry { entry := logger.newEntry() From 098a5a7cd74c3ce1cf98e83aed6d823ebe96fe3e Mon Sep 17 00:00:00 2001 From: David Bariod Date: Sat, 19 May 2018 21:26:32 +0200 Subject: [PATCH 37/92] Move the hook services list to a wiki page --- README.md | 58 ++----------------------------------------------------- 1 file changed, 2 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index 7f86254..072e99b 100644 --- a/README.md +++ b/README.md @@ -241,62 +241,8 @@ func init() { ``` Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md). -| Hook | Description | -| ----- | ----------- | -| [Airbrake "legacy"](https://github.com/gemnasium/logrus-airbrake-legacy-hook) | Send errors to an exception tracking service compatible with the Airbrake API V2. Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes. | -| [Airbrake](https://github.com/gemnasium/logrus-airbrake-hook) | Send errors to the Airbrake API V3. Uses the official [`gobrake`](https://github.com/airbrake/gobrake) behind the scenes. | -| [Amazon Kinesis](https://github.com/evalphobia/logrus_kinesis) | Hook for logging to [Amazon Kinesis](https://aws.amazon.com/kinesis/) | -| [Amqp-Hook](https://github.com/vladoatanasov/logrus_amqp) | Hook for logging to Amqp broker (Like RabbitMQ) | -| [Anexia CloudLog](https://github.com/anexia-it/go-logrus-cloudlog) | Hook for logging to Anexia CloudLog | -| [Application Insights](https://github.com/jjcollinge/logrus-appinsights) | Hook for logging to [Application Insights](https://azure.microsoft.com/en-us/services/application-insights/) -| [AzureTableHook](https://github.com/kpfaulkner/azuretablehook/) | Hook for logging to Azure Table Storage| -| [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. | -| [ClickHouse](https://github.com/oxgrouby/logrus-clickhouse-hook) | Send logs to [ClickHouse](https://clickhouse.yandex/) | -| [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic | -| [Discordrus](https://github.com/kz/discordrus) | Hook for logging to [Discord](https://discordapp.com/) | -| [ElasticSearch](https://github.com/sohlich/elogrus) | Hook for logging to ElasticSearch| -| [Firehose](https://github.com/beaubrewer/logrus_firehose) | Hook for logging to [Amazon Firehose](https://aws.amazon.com/kinesis/firehose/) -| [Fluentd](https://github.com/evalphobia/logrus_fluent) | Hook for logging to fluentd | -| [Go-Slack](https://github.com/multiplay/go-slack) | Hook for logging to [Slack](https://slack.com) | -| [Graylog](https://github.com/gemnasium/logrus-graylog-hook) | Hook for logging to [Graylog](http://graylog2.org/) | -| [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. | -| [Honeybadger](https://github.com/agonzalezro/logrus_honeybadger) | Hook for sending exceptions to Honeybadger | -| [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb | -| [Influxus](http://github.com/vlad-doru/influxus) | Hook for concurrently logging to [InfluxDB](http://influxdata.com/) | -| [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` | -| [KafkaLogrus](https://github.com/tracer0tong/kafkalogrus) | Hook for logging to Kafka | -| [Kafka REST Proxy](https://github.com/Nordstrom/logrus-kafka-rest-proxy) | Hook for logging to [Kafka REST Proxy](https://docs.confluent.io/current/kafka-rest/docs) | -| [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem | -| [Logbeat](https://github.com/macandmia/logbeat) | Hook for logging to [Opbeat](https://opbeat.com/) | -| [Logentries](https://github.com/jcftang/logentriesrus) | Hook for logging to [Logentries](https://logentries.com/) | -| [Logentrus](https://github.com/puddingfactory/logentrus) | Hook for logging to [Logentries](https://logentries.com/) | -| [Logmatic.io](https://github.com/logmatic/logmatic-go) | Hook for logging to [Logmatic.io](http://logmatic.io/) | -| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) | -| [Logstash](https://github.com/bshuster-repo/logrus-logstash-hook) | Hook for logging to [Logstash](https://www.elastic.co/products/logstash) | -| [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail | -| [Mattermost](https://github.com/shuLhan/mattermost-integration/tree/master/hooks/logrus) | Hook for logging to [Mattermost](https://mattermost.com/) | -| [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb | -| [MySQL](https://github.com/LyricTian/logrus-mysql-hook) | Hook for logging to mysql | -| [NATS-Hook](https://github.com/rybit/nats_logrus_hook) | Hook for logging to [NATS](https://nats.io) | -| [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit | -| [Papertrail](https://github.com/polds/logrus-papertrail-hook) | Send errors to the [Papertrail](https://papertrailapp.com) hosted logging service via UDP. | -| [PostgreSQL](https://github.com/gemnasium/logrus-postgresql-hook) | Send logs to [PostgreSQL](http://postgresql.org) | -| [Promrus](https://github.com/weaveworks/promrus) | Expose number of log messages as [Prometheus](https://prometheus.io/) metrics | -| [Pushover](https://github.com/toorop/logrus_pushover) | Send error via [Pushover](https://pushover.net) | -| [Raygun](https://github.com/squirkle/logrus-raygun-hook) | Hook for logging to [Raygun.io](http://raygun.io/) | -| [Redis-Hook](https://github.com/rogierlommers/logrus-redis-hook) | Hook for logging to a ELK stack (through Redis) | -| [Rollrus](https://github.com/heroku/rollrus) | Hook for sending errors to rollbar | -| [Scribe](https://github.com/sagar8192/logrus-scribe-hook) | Hook for logging to [Scribe](https://github.com/facebookarchive/scribe)| -| [Sentry](https://github.com/evalphobia/logrus_sentry) | Send errors to the Sentry error logging and aggregation service. | -| [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. | -| [Stackdriver](https://github.com/knq/sdhook) | Hook for logging to [Google Stackdriver](https://cloud.google.com/logging/) | -| [Sumorus](https://github.com/doublefree/sumorus) | Hook for logging to [SumoLogic](https://www.sumologic.com/)| -| [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. | -| [Syslog TLS](https://github.com/shinji62/logrus-syslog-ng) | Send errors to remote syslog server with TLS support. | -| [Telegram](https://github.com/rossmcdonald/telegram_hook) | Hook for logging errors to [Telegram](https://telegram.org/) | -| [TraceView](https://github.com/evalphobia/logrus_appneta) | Hook for logging to [AppNeta TraceView](https://www.appneta.com/products/traceview/) | -| [Typetalk](https://github.com/dragon3/logrus-typetalk-hook) | Hook for logging to [Typetalk](https://www.typetalk.in/) | -| [SQS-Hook](https://github.com/tsarpaul/logrus_sqs) | Hook for logging to [Amazon Simple Queue Service (SQS)](https://aws.amazon.com/sqs/) | +A list of currently known of service hook can be found in this wiki [page](https://github.com/sirupsen/logrus/wiki/Hooks) + #### Level logging From 070c81def33f6362a8267b6a4e56fb7bf23fc6b5 Mon Sep 17 00:00:00 2001 From: Moriyoshi Koizumi Date: Wed, 30 May 2018 09:50:59 +0000 Subject: [PATCH 38/92] Revert the change introduced in #707 and do the proper fix. Fixes #729 --- entry.go | 6 ++---- hooks/test/test.go | 15 ++++++--------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/entry.go b/entry.go index d075d72..1be48ab 100644 --- a/entry.go +++ b/entry.go @@ -113,12 +113,10 @@ func (entry Entry) log(level Level, msg string) { } } -// This function is not declared with a pointer value because otherwise -// race conditions will occur when using multiple goroutines -func (entry Entry) fireHooks() { +func (entry *Entry) fireHooks() { entry.Logger.mu.Lock() defer entry.Logger.mu.Unlock() - err := entry.Logger.Hooks.Fire(entry.Level, &entry) + err := entry.Logger.Hooks.Fire(entry.Level, entry) if err != nil { fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err) } diff --git a/hooks/test/test.go b/hooks/test/test.go index 62c4845..234a17d 100644 --- a/hooks/test/test.go +++ b/hooks/test/test.go @@ -15,7 +15,7 @@ type Hook struct { // Entries is an array of all entries that have been received by this hook. // For safe access, use the AllEntries() method, rather than reading this // value directly. - Entries []*logrus.Entry + Entries []logrus.Entry mu sync.RWMutex } @@ -52,7 +52,7 @@ func NewNullLogger() (*logrus.Logger, *Hook) { func (t *Hook) Fire(e *logrus.Entry) error { t.mu.Lock() defer t.mu.Unlock() - t.Entries = append(t.Entries, e) + t.Entries = append(t.Entries, *e) return nil } @@ -68,9 +68,7 @@ func (t *Hook) LastEntry() *logrus.Entry { if i < 0 { return nil } - // Make a copy, for safety - e := *t.Entries[i] - return &e + return &t.Entries[i] } // AllEntries returns all entries that were logged. @@ -79,10 +77,9 @@ func (t *Hook) AllEntries() []*logrus.Entry { defer t.mu.RUnlock() // Make a copy so the returned value won't race with future log requests entries := make([]*logrus.Entry, len(t.Entries)) - for i, entry := range t.Entries { + for i := 0; i < len(t.Entries); i++ { // Make a copy, for safety - e := *entry - entries[i] = &e + entries[i] = &t.Entries[i] } return entries } @@ -91,5 +88,5 @@ func (t *Hook) AllEntries() []*logrus.Entry { func (t *Hook) Reset() { t.mu.Lock() defer t.mu.Unlock() - t.Entries = make([]*logrus.Entry, 0) + t.Entries = make([]logrus.Entry, 0) } From 4225d694ba95bda1ce8bcbd67c5701beef4491d0 Mon Sep 17 00:00:00 2001 From: Logan HAUSPIE Date: Wed, 30 May 2018 01:47:39 +0200 Subject: [PATCH 39/92] feat: new methods to check enabled log level Adding 6 methods on 'exported', 'logger' and 'entry': - IsDebugEnabled() bool - IsInfoEnabled() bool - IsWarnEnabled() bool - IsErrorEnabled() bool - IsFatalEnabled() bool - IsPanicEnabled() bool Replace duplicated 'if logger.level() >= XxxxLevel' by a call to the new methods in 'logger' and 'entry' Closes #761 --- entry.go | 60 +++++++++++++++++++++++++++++++-------------- exported.go | 24 ++++++++++++++++++ logger.go | 66 ++++++++++++++++++++++++++++++++++---------------- logrus.go | 7 ++++++ logrus_test.go | 51 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 169 insertions(+), 39 deletions(-) diff --git a/entry.go b/entry.go index d075d72..29bcae6 100644 --- a/entry.go +++ b/entry.go @@ -139,7 +139,7 @@ func (entry *Entry) write() { } func (entry *Entry) Debug(args ...interface{}) { - if entry.Logger.level() >= DebugLevel { + if entry.IsDebugEnabled() { entry.log(DebugLevel, fmt.Sprint(args...)) } } @@ -149,13 +149,13 @@ func (entry *Entry) Print(args ...interface{}) { } func (entry *Entry) Info(args ...interface{}) { - if entry.Logger.level() >= InfoLevel { + if entry.IsInfoEnabled() { entry.log(InfoLevel, fmt.Sprint(args...)) } } func (entry *Entry) Warn(args ...interface{}) { - if entry.Logger.level() >= WarnLevel { + if entry.IsWarnEnabled() { entry.log(WarnLevel, fmt.Sprint(args...)) } } @@ -165,20 +165,20 @@ func (entry *Entry) Warning(args ...interface{}) { } func (entry *Entry) Error(args ...interface{}) { - if entry.Logger.level() >= ErrorLevel { + if entry.IsErrorEnabled() { entry.log(ErrorLevel, fmt.Sprint(args...)) } } func (entry *Entry) Fatal(args ...interface{}) { - if entry.Logger.level() >= FatalLevel { + if entry.IsFatalEnabled() { entry.log(FatalLevel, fmt.Sprint(args...)) } Exit(1) } func (entry *Entry) Panic(args ...interface{}) { - if entry.Logger.level() >= PanicLevel { + if entry.IsPanicEnabled() { entry.log(PanicLevel, fmt.Sprint(args...)) } panic(fmt.Sprint(args...)) @@ -187,13 +187,13 @@ func (entry *Entry) Panic(args ...interface{}) { // Entry Printf family functions func (entry *Entry) Debugf(format string, args ...interface{}) { - if entry.Logger.level() >= DebugLevel { + if entry.IsDebugEnabled() { entry.Debug(fmt.Sprintf(format, args...)) } } func (entry *Entry) Infof(format string, args ...interface{}) { - if entry.Logger.level() >= InfoLevel { + if entry.IsInfoEnabled() { entry.Info(fmt.Sprintf(format, args...)) } } @@ -203,7 +203,7 @@ func (entry *Entry) Printf(format string, args ...interface{}) { } func (entry *Entry) Warnf(format string, args ...interface{}) { - if entry.Logger.level() >= WarnLevel { + if entry.IsWarnEnabled() { entry.Warn(fmt.Sprintf(format, args...)) } } @@ -213,20 +213,20 @@ func (entry *Entry) Warningf(format string, args ...interface{}) { } func (entry *Entry) Errorf(format string, args ...interface{}) { - if entry.Logger.level() >= ErrorLevel { + if entry.IsErrorEnabled() { entry.Error(fmt.Sprintf(format, args...)) } } func (entry *Entry) Fatalf(format string, args ...interface{}) { - if entry.Logger.level() >= FatalLevel { + if entry.IsFatalEnabled() { entry.Fatal(fmt.Sprintf(format, args...)) } Exit(1) } func (entry *Entry) Panicf(format string, args ...interface{}) { - if entry.Logger.level() >= PanicLevel { + if entry.IsPanicEnabled() { entry.Panic(fmt.Sprintf(format, args...)) } } @@ -234,13 +234,13 @@ func (entry *Entry) Panicf(format string, args ...interface{}) { // Entry Println family functions func (entry *Entry) Debugln(args ...interface{}) { - if entry.Logger.level() >= DebugLevel { + if entry.IsDebugEnabled() { entry.Debug(entry.sprintlnn(args...)) } } func (entry *Entry) Infoln(args ...interface{}) { - if entry.Logger.level() >= InfoLevel { + if entry.IsInfoEnabled() { entry.Info(entry.sprintlnn(args...)) } } @@ -250,7 +250,7 @@ func (entry *Entry) Println(args ...interface{}) { } func (entry *Entry) Warnln(args ...interface{}) { - if entry.Logger.level() >= WarnLevel { + if entry.IsWarnEnabled() { entry.Warn(entry.sprintlnn(args...)) } } @@ -260,24 +260,48 @@ func (entry *Entry) Warningln(args ...interface{}) { } func (entry *Entry) Errorln(args ...interface{}) { - if entry.Logger.level() >= ErrorLevel { + if entry.IsErrorEnabled() { entry.Error(entry.sprintlnn(args...)) } } func (entry *Entry) Fatalln(args ...interface{}) { - if entry.Logger.level() >= FatalLevel { + if entry.IsFatalEnabled() { entry.Fatal(entry.sprintlnn(args...)) } Exit(1) } func (entry *Entry) Panicln(args ...interface{}) { - if entry.Logger.level() >= PanicLevel { + if entry.IsPanicEnabled() { entry.Panic(entry.sprintlnn(args...)) } } +func (entry *Entry) IsDebugEnabled() bool { + return entry.Logger.IsDebugEnabled() +} + +func (entry *Entry) IsInfoEnabled() bool { + return entry.Logger.IsInfoEnabled() +} + +func (entry *Entry) IsWarnEnabled() bool { + return entry.Logger.IsWarnEnabled() +} + +func (entry *Entry) IsErrorEnabled() bool { + return entry.Logger.IsErrorEnabled() +} + +func (entry *Entry) IsFatalEnabled() bool { + return entry.Logger.IsFatalEnabled() +} + +func (entry *Entry) IsPanicEnabled() bool { + return entry.Logger.IsPanicEnabled() +} + // Sprintlnn => Sprint no newline. This is to get the behavior of how // fmt.Sprintln where spaces are always added between operands, regardless of // their type. Instead of vendoring the Sprintln implementation to spare a diff --git a/exported.go b/exported.go index 013183e..f2df9e3 100644 --- a/exported.go +++ b/exported.go @@ -41,6 +41,30 @@ func GetLevel() Level { return std.level() } +func IsDebugEnabled() bool { + return std.IsDebugEnabled() +} + +func IsInfoEnabled() bool { + return std.IsInfoEnabled() +} + +func IsWarnEnabled() bool { + return std.IsWarnEnabled() +} + +func IsErrorEnabled() bool { + return std.IsErrorEnabled() +} + +func IsFatalEnabled() bool { + return std.IsFatalEnabled() +} + +func IsPanicEnabled() bool { + return std.IsPanicEnabled() +} + // AddHook adds a hook to the standard logger hooks. func AddHook(hook Hook) { std.mu.Lock() diff --git a/logger.go b/logger.go index fdaf8a6..034fb18 100644 --- a/logger.go +++ b/logger.go @@ -113,7 +113,7 @@ func (logger *Logger) WithError(err error) *Entry { } func (logger *Logger) Debugf(format string, args ...interface{}) { - if logger.level() >= DebugLevel { + if logger.IsDebugEnabled() { entry := logger.newEntry() entry.Debugf(format, args...) logger.releaseEntry(entry) @@ -121,7 +121,7 @@ func (logger *Logger) Debugf(format string, args ...interface{}) { } func (logger *Logger) Infof(format string, args ...interface{}) { - if logger.level() >= InfoLevel { + if logger.IsInfoEnabled() { entry := logger.newEntry() entry.Infof(format, args...) logger.releaseEntry(entry) @@ -135,7 +135,7 @@ func (logger *Logger) Printf(format string, args ...interface{}) { } func (logger *Logger) Warnf(format string, args ...interface{}) { - if logger.level() >= WarnLevel { + if logger.IsWarnEnabled() { entry := logger.newEntry() entry.Warnf(format, args...) logger.releaseEntry(entry) @@ -143,7 +143,7 @@ func (logger *Logger) Warnf(format string, args ...interface{}) { } func (logger *Logger) Warningf(format string, args ...interface{}) { - if logger.level() >= WarnLevel { + if logger.IsWarnEnabled() { entry := logger.newEntry() entry.Warnf(format, args...) logger.releaseEntry(entry) @@ -151,7 +151,7 @@ func (logger *Logger) Warningf(format string, args ...interface{}) { } func (logger *Logger) Errorf(format string, args ...interface{}) { - if logger.level() >= ErrorLevel { + if logger.IsErrorEnabled() { entry := logger.newEntry() entry.Errorf(format, args...) logger.releaseEntry(entry) @@ -159,7 +159,7 @@ func (logger *Logger) Errorf(format string, args ...interface{}) { } func (logger *Logger) Fatalf(format string, args ...interface{}) { - if logger.level() >= FatalLevel { + if logger.IsFatalEnabled() { entry := logger.newEntry() entry.Fatalf(format, args...) logger.releaseEntry(entry) @@ -168,7 +168,7 @@ func (logger *Logger) Fatalf(format string, args ...interface{}) { } func (logger *Logger) Panicf(format string, args ...interface{}) { - if logger.level() >= PanicLevel { + if logger.IsPanicEnabled() { entry := logger.newEntry() entry.Panicf(format, args...) logger.releaseEntry(entry) @@ -176,7 +176,7 @@ func (logger *Logger) Panicf(format string, args ...interface{}) { } func (logger *Logger) Debug(args ...interface{}) { - if logger.level() >= DebugLevel { + if logger.IsDebugEnabled() { entry := logger.newEntry() entry.Debug(args...) logger.releaseEntry(entry) @@ -184,7 +184,7 @@ func (logger *Logger) Debug(args ...interface{}) { } func (logger *Logger) Info(args ...interface{}) { - if logger.level() >= InfoLevel { + if logger.IsInfoEnabled() { entry := logger.newEntry() entry.Info(args...) logger.releaseEntry(entry) @@ -198,7 +198,7 @@ func (logger *Logger) Print(args ...interface{}) { } func (logger *Logger) Warn(args ...interface{}) { - if logger.level() >= WarnLevel { + if logger.IsWarnEnabled() { entry := logger.newEntry() entry.Warn(args...) logger.releaseEntry(entry) @@ -206,7 +206,7 @@ func (logger *Logger) Warn(args ...interface{}) { } func (logger *Logger) Warning(args ...interface{}) { - if logger.level() >= WarnLevel { + if logger.IsWarnEnabled() { entry := logger.newEntry() entry.Warn(args...) logger.releaseEntry(entry) @@ -214,7 +214,7 @@ func (logger *Logger) Warning(args ...interface{}) { } func (logger *Logger) Error(args ...interface{}) { - if logger.level() >= ErrorLevel { + if logger.IsErrorEnabled() { entry := logger.newEntry() entry.Error(args...) logger.releaseEntry(entry) @@ -222,7 +222,7 @@ func (logger *Logger) Error(args ...interface{}) { } func (logger *Logger) Fatal(args ...interface{}) { - if logger.level() >= FatalLevel { + if logger.IsFatalEnabled() { entry := logger.newEntry() entry.Fatal(args...) logger.releaseEntry(entry) @@ -231,7 +231,7 @@ func (logger *Logger) Fatal(args ...interface{}) { } func (logger *Logger) Panic(args ...interface{}) { - if logger.level() >= PanicLevel { + if logger.IsPanicEnabled() { entry := logger.newEntry() entry.Panic(args...) logger.releaseEntry(entry) @@ -239,7 +239,7 @@ func (logger *Logger) Panic(args ...interface{}) { } func (logger *Logger) Debugln(args ...interface{}) { - if logger.level() >= DebugLevel { + if logger.IsDebugEnabled() { entry := logger.newEntry() entry.Debugln(args...) logger.releaseEntry(entry) @@ -247,7 +247,7 @@ func (logger *Logger) Debugln(args ...interface{}) { } func (logger *Logger) Infoln(args ...interface{}) { - if logger.level() >= InfoLevel { + if logger.IsInfoEnabled() { entry := logger.newEntry() entry.Infoln(args...) logger.releaseEntry(entry) @@ -261,7 +261,7 @@ func (logger *Logger) Println(args ...interface{}) { } func (logger *Logger) Warnln(args ...interface{}) { - if logger.level() >= WarnLevel { + if logger.IsWarnEnabled() { entry := logger.newEntry() entry.Warnln(args...) logger.releaseEntry(entry) @@ -269,7 +269,7 @@ func (logger *Logger) Warnln(args ...interface{}) { } func (logger *Logger) Warningln(args ...interface{}) { - if logger.level() >= WarnLevel { + if logger.IsWarnEnabled() { entry := logger.newEntry() entry.Warnln(args...) logger.releaseEntry(entry) @@ -277,7 +277,7 @@ func (logger *Logger) Warningln(args ...interface{}) { } func (logger *Logger) Errorln(args ...interface{}) { - if logger.level() >= ErrorLevel { + if logger.IsErrorEnabled() { entry := logger.newEntry() entry.Errorln(args...) logger.releaseEntry(entry) @@ -285,7 +285,7 @@ func (logger *Logger) Errorln(args ...interface{}) { } func (logger *Logger) Fatalln(args ...interface{}) { - if logger.level() >= FatalLevel { + if logger.IsFatalEnabled() { entry := logger.newEntry() entry.Fatalln(args...) logger.releaseEntry(entry) @@ -294,7 +294,7 @@ func (logger *Logger) Fatalln(args ...interface{}) { } func (logger *Logger) Panicln(args ...interface{}) { - if logger.level() >= PanicLevel { + if logger.IsPanicEnabled() { entry := logger.newEntry() entry.Panicln(args...) logger.releaseEntry(entry) @@ -321,3 +321,27 @@ func (logger *Logger) AddHook(hook Hook) { defer logger.mu.Unlock() logger.Hooks.Add(hook) } + +func (logger *Logger) IsDebugEnabled() bool { + return logger.level() >= DebugLevel +} + +func (logger *Logger) IsInfoEnabled() bool { + return logger.level() >= InfoLevel +} + +func (logger *Logger) IsWarnEnabled() bool { + return logger.level() >= WarnLevel +} + +func (logger *Logger) IsErrorEnabled() bool { + return logger.level() >= ErrorLevel +} + +func (logger *Logger) IsFatalEnabled() bool { + return logger.level() >= FatalLevel +} + +func (logger *Logger) IsPanicEnabled() bool { + return logger.level() >= PanicLevel +} diff --git a/logrus.go b/logrus.go index dd38999..33e07fa 100644 --- a/logrus.go +++ b/logrus.go @@ -140,4 +140,11 @@ type FieldLogger interface { Errorln(args ...interface{}) Fatalln(args ...interface{}) Panicln(args ...interface{}) + + IsDebugEnabled() bool + IsInfoEnabled() bool + IsWarnEnabled() bool + IsErrorEnabled() bool + IsFatalEnabled() bool + IsPanicEnabled() bool } diff --git a/logrus_test.go b/logrus_test.go index 78cbc28..2c59dc9 100644 --- a/logrus_test.go +++ b/logrus_test.go @@ -384,3 +384,54 @@ func TestEntryWriter(t *testing.T) { assert.Equal(t, fields["foo"], "bar") assert.Equal(t, fields["level"], "warning") } + +func TestLogLevelEnabled(t *testing.T) { + log := New() + log.SetLevel(PanicLevel) + assert.Equal(t, true, log.IsPanicEnabled()) + assert.Equal(t, false, log.IsFatalEnabled()) + assert.Equal(t, false, log.IsErrorEnabled()) + assert.Equal(t, false, log.IsWarnEnabled()) + assert.Equal(t, false, log.IsInfoEnabled()) + assert.Equal(t, false, log.IsDebugEnabled()) + + log.SetLevel(FatalLevel) + assert.Equal(t, true, log.IsPanicEnabled()) + assert.Equal(t, true, log.IsFatalEnabled()) + assert.Equal(t, false, log.IsErrorEnabled()) + assert.Equal(t, false, log.IsWarnEnabled()) + assert.Equal(t, false, log.IsInfoEnabled()) + assert.Equal(t, false, log.IsDebugEnabled()) + + log.SetLevel(ErrorLevel) + assert.Equal(t, true, log.IsPanicEnabled()) + assert.Equal(t, true, log.IsFatalEnabled()) + assert.Equal(t, true, log.IsErrorEnabled()) + assert.Equal(t, false, log.IsWarnEnabled()) + assert.Equal(t, false, log.IsInfoEnabled()) + assert.Equal(t, false, log.IsDebugEnabled()) + + log.SetLevel(WarnLevel) + assert.Equal(t, true, log.IsPanicEnabled()) + assert.Equal(t, true, log.IsFatalEnabled()) + assert.Equal(t, true, log.IsErrorEnabled()) + assert.Equal(t, true, log.IsWarnEnabled()) + assert.Equal(t, false, log.IsInfoEnabled()) + assert.Equal(t, false, log.IsDebugEnabled()) + + log.SetLevel(InfoLevel) + assert.Equal(t, true, log.IsPanicEnabled()) + assert.Equal(t, true, log.IsFatalEnabled()) + assert.Equal(t, true, log.IsErrorEnabled()) + assert.Equal(t, true, log.IsWarnEnabled()) + assert.Equal(t, true, log.IsInfoEnabled()) + assert.Equal(t, false, log.IsDebugEnabled()) + + log.SetLevel(DebugLevel) + assert.Equal(t, true, log.IsPanicEnabled()) + assert.Equal(t, true, log.IsFatalEnabled()) + assert.Equal(t, true, log.IsErrorEnabled()) + assert.Equal(t, true, log.IsWarnEnabled()) + assert.Equal(t, true, log.IsInfoEnabled()) + assert.Equal(t, true, log.IsDebugEnabled()) +} From 5d60369ef3a5c165e66ece9cdebb2d4177729d84 Mon Sep 17 00:00:00 2001 From: Neil Isaac Date: Mon, 18 Jun 2018 21:32:35 -0400 Subject: [PATCH 40/92] Fixed prefixFieldClashes for TextFormatter and added coverage --- formatter.go | 3 +++ text_formatter.go | 8 ++++---- text_formatter_test.go | 14 +++++++++++++- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/formatter.go b/formatter.go index 849dc8b..83c7494 100644 --- a/formatter.go +++ b/formatter.go @@ -34,15 +34,18 @@ func prefixFieldClashes(data Fields, fieldMap FieldMap) { timeKey := fieldMap.resolve(FieldKeyTime) if t, ok := data[timeKey]; ok { data["fields."+timeKey] = t + delete(data, timeKey) } msgKey := fieldMap.resolve(FieldKeyMsg) if m, ok := data[msgKey]; ok { data["fields."+msgKey] = m + delete(data, msgKey) } levelKey := fieldMap.resolve(FieldKeyLevel) if l, ok := data[levelKey]; ok { data["fields."+levelKey] = l + delete(data, levelKey) } } diff --git a/text_formatter.go b/text_formatter.go index 5af4e56..3e55040 100644 --- a/text_formatter.go +++ b/text_formatter.go @@ -51,7 +51,6 @@ type TextFormatter struct { // be desired. DisableSorting bool - // Disables the truncation of the level text to 4 characters. DisableLevelTruncation bool @@ -81,7 +80,8 @@ func (f *TextFormatter) init(entry *Entry) { // Format renders a single log entry func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { - var b *bytes.Buffer + prefixFieldClashes(entry.Data, f.FieldMap) + keys := make([]string, 0, len(entry.Data)) for k := range entry.Data { keys = append(keys, k) @@ -90,14 +90,14 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { if !f.DisableSorting { sort.Strings(keys) } + + var b *bytes.Buffer if entry.Buffer != nil { b = entry.Buffer } else { b = &bytes.Buffer{} } - prefixFieldClashes(entry.Data, emptyFieldMap) - f.Do(func() { f.init(entry) }) isColored := (f.ForceColors || f.isTerminal) && !f.DisableColors diff --git a/text_formatter_test.go b/text_formatter_test.go index 4f21861..7245f94 100644 --- a/text_formatter_test.go +++ b/text_formatter_test.go @@ -191,6 +191,12 @@ func TestTextFormatterFieldMap(t *testing.T) { Message: "oh hi", Level: WarnLevel, Time: time.Date(1981, time.February, 24, 4, 28, 3, 100, time.UTC), + Data: Fields{ + "field1": "f1", + "message": "messagefield", + "somelevel": "levelfield", + "timeywimey": "timeywimeyfield", + }, } b, err := formatter.Format(entry) @@ -199,7 +205,13 @@ func TestTextFormatterFieldMap(t *testing.T) { } assert.Equal(t, - `timeywimey="1981-02-24T04:28:03Z" somelevel=warning message="oh hi"`+"\n", + `timeywimey="1981-02-24T04:28:03Z" `+ + `somelevel=warning `+ + `message="oh hi" `+ + `field1=f1 `+ + `fields.message=messagefield `+ + `fields.somelevel=levelfield `+ + `fields.timeywimey=timeywimeyfield`+"\n", string(b), "Formatted doesn't respect correct FieldMap") } From 6b28c2c7d76fb49e829b83ab6dc2f25327db3189 Mon Sep 17 00:00:00 2001 From: Neil Isaac Date: Mon, 18 Jun 2018 21:39:53 -0400 Subject: [PATCH 41/92] error message --- text_formatter_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text_formatter_test.go b/text_formatter_test.go index 7245f94..921d052 100644 --- a/text_formatter_test.go +++ b/text_formatter_test.go @@ -213,7 +213,7 @@ func TestTextFormatterFieldMap(t *testing.T) { `fields.somelevel=levelfield `+ `fields.timeywimey=timeywimeyfield`+"\n", string(b), - "Formatted doesn't respect correct FieldMap") + "Formatted output doesn't respect FieldMap") } // TODO add tests for sorting etc., this requires a parser for the text From 2ce6c0cb44b88b3cf9b97e7513269d00c7eee11c Mon Sep 17 00:00:00 2001 From: Przemyslaw Wegrzyn Date: Tue, 19 Jun 2018 14:31:57 +0200 Subject: [PATCH 42/92] Support for Entry data under nested JSON dictionary. --- json_formatter.go | 10 ++++++++++ json_formatter_test.go | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/json_formatter.go b/json_formatter.go index 7064947..dab1761 100644 --- a/json_formatter.go +++ b/json_formatter.go @@ -33,6 +33,9 @@ type JSONFormatter struct { // DisableTimestamp allows disabling automatic timestamps in output DisableTimestamp bool + // DataKey allows users to put all the log entry parameters into a nested dictionary at a given key. + DataKey string + // FieldMap allows users to customize the names of keys for default fields. // As an example: // formatter := &JSONFormatter{ @@ -58,6 +61,13 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { data[k] = v } } + + if f.DataKey != "" { + newData := make(Fields, 4) + newData[f.DataKey] = data + data = newData + } + prefixFieldClashes(data, f.FieldMap) timestampFormat := f.TimestampFormat diff --git a/json_formatter_test.go b/json_formatter_test.go index 1c140d0..0dde300 100644 --- a/json_formatter_test.go +++ b/json_formatter_test.go @@ -161,6 +161,48 @@ func TestFieldClashWithRemappedFields(t *testing.T) { } } +func TestFieldsInNestedDictionary(t *testing.T) { + formatter := &JSONFormatter{ + DataKey: "args", + } + + logEntry := WithFields(Fields{ + "level": "level", + "test": "test", + }) + logEntry.Level = InfoLevel + + b, err := formatter.Format(logEntry) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + + entry := make(map[string]interface{}) + err = json.Unmarshal(b, &entry) + if err != nil { + t.Fatal("Unable to unmarshal formatted entry: ", err) + } + + args := entry["args"].(map[string]interface{}) + + for _, field := range []string{"test", "level"} { + if value, present := args[field]; !present || value != field { + t.Errorf("Expected field %v to be present under 'args'; untouched", field) + } + } + + for _, field := range []string{"test", "fields.level"} { + if _, present := entry[field]; present { + t.Errorf("Expected field %v not to be present at top level", field) + } + } + + // with nested object, "level" shouldn't clash + if entry["level"] != "info" { + t.Errorf("Expected 'level' field to contain 'info'") + } +} + func TestJSONEntryEndsWithNewline(t *testing.T) { formatter := &JSONFormatter{} From eed1c0f832603c63deae9d5ffa2c4a6e611ed31f Mon Sep 17 00:00:00 2001 From: Christian Stewart Date: Wed, 20 Jun 2018 21:39:23 -0700 Subject: [PATCH 43/92] Fix GopherJS build tags The GopherJS build tag is "js" not "gopherjs" Signed-off-by: Christian Stewart --- terminal_bsd.go | 2 +- terminal_check_appengine.go | 2 +- terminal_check_notappengine.go | 2 +- terminal_linux.go | 2 +- text_formatter_js.go | 11 +++++++++++ text_formatter_other.go | 3 +++ 6 files changed, 18 insertions(+), 4 deletions(-) create mode 100644 text_formatter_js.go create mode 100644 text_formatter_other.go diff --git a/terminal_bsd.go b/terminal_bsd.go index 4880d13..5b6212d 100644 --- a/terminal_bsd.go +++ b/terminal_bsd.go @@ -1,5 +1,5 @@ // +build darwin freebsd openbsd netbsd dragonfly -// +build !appengine,!gopherjs +// +build !appengine,!js package logrus diff --git a/terminal_check_appengine.go b/terminal_check_appengine.go index 3de08e8..26a2867 100644 --- a/terminal_check_appengine.go +++ b/terminal_check_appengine.go @@ -1,4 +1,4 @@ -// +build appengine gopherjs +// +build appengine js package logrus diff --git a/terminal_check_notappengine.go b/terminal_check_notappengine.go index 067047a..87f0b80 100644 --- a/terminal_check_notappengine.go +++ b/terminal_check_notappengine.go @@ -1,4 +1,4 @@ -// +build !appengine,!gopherjs +// +build !appengine,!js package logrus diff --git a/terminal_linux.go b/terminal_linux.go index f29a009..634e39b 100644 --- a/terminal_linux.go +++ b/terminal_linux.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 !appengine,!gopherjs +// +build !appengine,!js package logrus diff --git a/text_formatter_js.go b/text_formatter_js.go new file mode 100644 index 0000000..d52803a --- /dev/null +++ b/text_formatter_js.go @@ -0,0 +1,11 @@ +// +build js + +package logrus + +import ( + "io" +) + +func (f *TextFormatter) checkIfTerminal(w io.Writer) bool { + return false +} diff --git a/text_formatter_other.go b/text_formatter_other.go new file mode 100644 index 0000000..0d9704f --- /dev/null +++ b/text_formatter_other.go @@ -0,0 +1,3 @@ +// +build !js + +package logrus From fc9bbf2f57995271c5cd6911ede7a2ebc5ea7c6f Mon Sep 17 00:00:00 2001 From: Daniel Bershatsky Date: Wed, 27 Jun 2018 20:29:28 +0300 Subject: [PATCH 44/92] [#241] Allow to set writer during logger usage. --- exported.go | 4 +--- logger.go | 6 ++++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/exported.go b/exported.go index 013183e..6c98afd 100644 --- a/exported.go +++ b/exported.go @@ -15,9 +15,7 @@ func StandardLogger() *Logger { // SetOutput sets the standard logger output. func SetOutput(out io.Writer) { - std.mu.Lock() - defer std.mu.Unlock() - std.Out = out + std.SetOutput(out) } // SetFormatter sets the standard logger formatter. diff --git a/logger.go b/logger.go index 0ac8ce2..0c1b05e 100644 --- a/logger.go +++ b/logger.go @@ -316,6 +316,12 @@ func (logger *Logger) SetLevel(level Level) { atomic.StoreUint32((*uint32)(&logger.Level), uint32(level)) } +func (logger *Logger) SetOutput(out io.Writer) { + logger.mu.Lock() + defer logger.mu.Unlock() + logger.Out = out +} + func (logger *Logger) AddHook(hook Hook) { logger.mu.Lock() defer logger.mu.Unlock() From 52b92f5b89ba5a81f021ad845bcd3a0d3ba1b2ac Mon Sep 17 00:00:00 2001 From: Simon Brisson Date: Thu, 28 Jun 2018 16:33:52 -0400 Subject: [PATCH 45/92] Allows overriding Entry.Time. --- entry.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/entry.go b/entry.go index d075d72..c3adf01 100644 --- a/entry.go +++ b/entry.go @@ -90,7 +90,16 @@ func (entry *Entry) WithFields(fields Fields) *Entry { // race conditions will occur when using multiple goroutines func (entry Entry) log(level Level, msg string) { var buffer *bytes.Buffer - entry.Time = time.Now() + + // Default to now, but allow users to override if they want. + // + // We don't have to worry about polluting future calls to Entry#log() + // with this assignment because this function is declared with a + // non-pointer receiver. + if entry.Time.IsZero() { + entry.Time = time.Now() + } + entry.Level = level entry.Message = msg From 725f3be1995f9bb46c7aa065ff200bef3a346cee Mon Sep 17 00:00:00 2001 From: Simon Brisson Date: Fri, 29 Jun 2018 10:53:51 -0400 Subject: [PATCH 46/92] Adds WithTime to Logger and Entry types, as well as a pure module-level function. --- entry.go | 7 +++++- exported.go | 10 +++++++++ logger.go | 8 +++++++ logrus_test.go | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 84 insertions(+), 1 deletion(-) diff --git a/entry.go b/entry.go index c3adf01..14f0a26 100644 --- a/entry.go +++ b/entry.go @@ -83,7 +83,12 @@ func (entry *Entry) WithFields(fields Fields) *Entry { for k, v := range fields { data[k] = v } - return &Entry{Logger: entry.Logger, Data: data} + return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time} +} + +// Overrides the time of the Entry. +func (entry *Entry) WithTime(t time.Time) *Entry { + return &Entry{Logger: entry.Logger, Data: entry.Data, Time: t} } // This function is not declared with a pointer value because otherwise diff --git a/exported.go b/exported.go index 013183e..ec1a417 100644 --- a/exported.go +++ b/exported.go @@ -2,6 +2,7 @@ package logrus import ( "io" + "time" ) var ( @@ -72,6 +73,15 @@ func WithFields(fields Fields) *Entry { return std.WithFields(fields) } +// WithTime creats an entry from the standard logger and overrides the time of +// logs generated with it. +// +// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal +// or Panic on the Entry it returns. +func WithTime(t time.Time) *Entry { + return std.WithTime(t) +} + // Debug logs a message at level Debug on the standard logger. func Debug(args ...interface{}) { std.Debug(args...) diff --git a/logger.go b/logger.go index 0ac8ce2..52b942d 100644 --- a/logger.go +++ b/logger.go @@ -5,6 +5,7 @@ import ( "os" "sync" "sync/atomic" + "time" ) type Logger struct { @@ -112,6 +113,13 @@ func (logger *Logger) WithError(err error) *Entry { return entry.WithError(err) } +// Overrides the time of the log entry. +func (logger *Logger) WithTime(t time.Time) *Entry { + entry := logger.newEntry() + defer logger.releaseEntry(entry) + return entry.WithTime(t) +} + func (logger *Logger) Debugf(format string, args ...interface{}) { if logger.level() >= DebugLevel { entry := logger.newEntry() diff --git a/logrus_test.go b/logrus_test.go index 78cbc28..78e1301 100644 --- a/logrus_test.go +++ b/logrus_test.go @@ -7,6 +7,7 @@ import ( "strings" "sync" "testing" + "time" "github.com/stretchr/testify/assert" ) @@ -209,6 +210,65 @@ func TestDefaultFieldsAreNotPrefixed(t *testing.T) { }) } +func TestWithTimeShouldOverrideTime(t *testing.T) { + now := time.Now().Add(24 * time.Hour) + + LogAndAssertJSON(t, func(log *Logger) { + log.WithTime(now).Info("foobar") + }, func(fields Fields) { + assert.Equal(t, fields["time"], now.Format(defaultTimestampFormat)) + }) +} + +func TestWithTimeShouldNotOverrideFields(t *testing.T) { + now := time.Now().Add(24 * time.Hour) + + LogAndAssertJSON(t, func(log *Logger) { + log.WithField("herp", "derp").WithTime(now).Info("blah") + }, func(fields Fields) { + assert.Equal(t, fields["time"], now.Format(defaultTimestampFormat)) + assert.Equal(t, fields["herp"], "derp") + }) +} + +func TestWithFieldShouldNotOverrideTime(t *testing.T) { + now := time.Now().Add(24 * time.Hour) + + LogAndAssertJSON(t, func(log *Logger) { + log.WithTime(now).WithField("herp", "derp").Info("blah") + }, func(fields Fields) { + assert.Equal(t, fields["time"], now.Format(defaultTimestampFormat)) + assert.Equal(t, fields["herp"], "derp") + }) +} + +func TestTimeOverrideMultipleLogs(t *testing.T) { + var buffer bytes.Buffer + var firstFields, secondFields Fields + + logger := New() + logger.Out = &buffer + formatter := new(JSONFormatter) + formatter.TimestampFormat = time.StampMilli + logger.Formatter = formatter + + llog := logger.WithField("herp", "derp") + llog.Info("foo") + + err := json.Unmarshal(buffer.Bytes(), &firstFields) + assert.NoError(t, err, "should have decoded first message") + + buffer.Reset() + + time.Sleep(10 * time.Millisecond) + llog.Info("bar") + + err = json.Unmarshal(buffer.Bytes(), &secondFields) + assert.NoError(t, err, "should have decoded second message") + + assert.NotEqual(t, firstFields["time"], secondFields["time"], "timestamps should not be equal") +} + func TestDoubleLoggingDoesntPrefixPreviousFields(t *testing.T) { var buffer bytes.Buffer From 6999e59e73b0b94716d9cef60c51e5adb5e5b4c3 Mon Sep 17 00:00:00 2001 From: David Bariod Date: Fri, 20 Jul 2018 13:16:19 +0200 Subject: [PATCH 47/92] properly fix the hooks race test --- hooks/test/test_test.go | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/hooks/test/test_test.go b/hooks/test/test_test.go index 742be55..d6f6d30 100644 --- a/hooks/test/test_test.go +++ b/hooks/test/test_test.go @@ -1,8 +1,10 @@ package test import ( + "math/rand" "sync" "testing" + "time" "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" @@ -38,24 +40,34 @@ func TestAllHooks(t *testing.T) { } func TestLoggingWithHooksRace(t *testing.T) { + + rand.Seed(time.Now().Unix()) + unlocker := rand.Int() % 100 + assert := assert.New(t) logger, hook := NewNullLogger() - var wg sync.WaitGroup - wg.Add(100) + var wgOne, wgAll sync.WaitGroup + wgOne.Add(1) + wgAll.Add(100) for i := 0; i < 100; i++ { - go func() { + go func(i int) { logger.Info("info") - wg.Done() - }() + wgAll.Done() + if i == unlocker { + wgOne.Done() + } + }(i) } - wg.Wait() + wgOne.Wait() assert.Equal(logrus.InfoLevel, hook.LastEntry().Level) assert.Equal("info", hook.LastEntry().Message) + wgAll.Wait() + entries := hook.AllEntries() assert.Equal(100, len(entries)) } From 54db2bb29af499574a7b8f7f86dcf1dc11297823 Mon Sep 17 00:00:00 2001 From: David Bariod Date: Fri, 20 Jul 2018 13:34:26 +0200 Subject: [PATCH 48/92] limit the build/test matrix to the two latest stable version --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index aebdc35..2f19b4a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,7 @@ language: go go: - - 1.8.x - 1.9.x - 1.10.x - - tip env: - GOMAXPROCS=4 GORACE=halt_on_error=1 install: From d3162770a8b8e496c83f63327ede96304f57ddee Mon Sep 17 00:00:00 2001 From: David Bariod Date: Sat, 28 Jul 2018 17:21:06 +0200 Subject: [PATCH 49/92] Add logger benchmark --- logger_bench_test.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/logger_bench_test.go b/logger_bench_test.go index dd23a35..f0a7684 100644 --- a/logger_bench_test.go +++ b/logger_bench_test.go @@ -1,6 +1,7 @@ package logrus import ( + "io/ioutil" "os" "testing" ) @@ -59,3 +60,26 @@ func doLoggerBenchmarkNoLock(b *testing.B, out *os.File, formatter Formatter, fi } }) } + +func BenchmarkLoggerJSONFormatter(b *testing.B) { + doLoggerBenchmarkWithFormatter(b, &JSONFormatter{}) +} + +func BenchmarkLoggerTextFormatter(b *testing.B) { + doLoggerBenchmarkWithFormatter(b, &TextFormatter{}) +} + +func doLoggerBenchmarkWithFormatter(b *testing.B, f Formatter) { + b.SetParallelism(100) + log := New() + log.Formatter = f + log.Out = ioutil.Discard + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + log. + WithField("foo1", "bar1"). + WithField("foo2", "bar2"). + Info("this is a dummy log") + } + }) +} From 179037fcd41cd279507e65aeebb32b0af35958fc Mon Sep 17 00:00:00 2001 From: David Bariod Date: Tue, 31 Jul 2018 18:08:27 +0200 Subject: [PATCH 50/92] Ensure a new entry data fields are empty Fixes #795 --- hook_test.go | 43 +++++++++++++++++++++++++++++++++++++++++++ logger.go | 1 + 2 files changed, 44 insertions(+) diff --git a/hook_test.go b/hook_test.go index 4fea751..80b93b8 100644 --- a/hook_test.go +++ b/hook_test.go @@ -1,10 +1,13 @@ package logrus import ( + "bytes" + "encoding/json" "sync" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) type TestHook struct { @@ -85,6 +88,46 @@ func TestCanFireMultipleHooks(t *testing.T) { }) } +type SingleLevelModifyHook struct { + ModifyHook +} + +func (h *SingleLevelModifyHook) Levels() []Level { + return []Level{InfoLevel} +} + +func TestHookEntryIsPristine(t *testing.T) { + l := New() + b := &bytes.Buffer{} + l.Formatter = &JSONFormatter{} + l.Out = b + l.AddHook(&SingleLevelModifyHook{}) + + l.Error("error message") + data := map[string]string{} + err := json.Unmarshal(b.Bytes(), &data) + require.NoError(t, err) + _, ok := data["wow"] + require.False(t, ok) + b.Reset() + + l.Info("error message") + data = map[string]string{} + err = json.Unmarshal(b.Bytes(), &data) + require.NoError(t, err) + _, ok = data["wow"] + require.True(t, ok) + b.Reset() + + l.Error("error message") + data = map[string]string{} + err = json.Unmarshal(b.Bytes(), &data) + require.NoError(t, err) + _, ok = data["wow"] + require.False(t, ok) + b.Reset() +} + type ErrorHook struct { Fired bool } diff --git a/logger.go b/logger.go index 342f797..7fa8d7d 100644 --- a/logger.go +++ b/logger.go @@ -85,6 +85,7 @@ func (logger *Logger) newEntry() *Entry { } func (logger *Logger) releaseEntry(entry *Entry) { + entry.Data = map[string]interface{}{} logger.entryPool.Put(entry) } From 37d651c1f2847d8514b79d1dd7389be06ec60447 Mon Sep 17 00:00:00 2001 From: Alessio Caiazza Date: Fri, 13 Jul 2018 17:33:25 +0200 Subject: [PATCH 51/92] Add CLICOLOR support This implement CLICOLOR and CLICOLOR_FORCE check on terminal coloring as defined in https://bixense.com/clicolors/ --- text_formatter.go | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/text_formatter.go b/text_formatter.go index 3e55040..cdf3185 100644 --- a/text_formatter.go +++ b/text_formatter.go @@ -3,6 +3,7 @@ package logrus import ( "bytes" "fmt" + "os" "sort" "strings" "sync" @@ -35,6 +36,9 @@ type TextFormatter struct { // Force disabling colors. DisableColors bool + // Override coloring based on CLICOLOR and CLICOLOR_FORCE. - https://bixense.com/clicolors/ + OverrideColors bool + // Disable timestamp logging. useful when output is redirected to logging // system that already adds timestamps. DisableTimestamp bool @@ -78,6 +82,22 @@ func (f *TextFormatter) init(entry *Entry) { } } +func (f *TextFormatter) isColored() bool { + isColored := f.ForceColors || f.isTerminal + + if f.OverrideColors { + if force, ok := os.LookupEnv("CLICOLOR_FORCE"); ok && force != "0" { + isColored = true + } + + if os.Getenv("CLICOLOR") == "0" { + isColored = false + } + } + + return isColored && !f.DisableColors +} + // Format renders a single log entry func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { prefixFieldClashes(entry.Data, f.FieldMap) @@ -100,13 +120,11 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { f.Do(func() { f.init(entry) }) - isColored := (f.ForceColors || f.isTerminal) && !f.DisableColors - timestampFormat := f.TimestampFormat if timestampFormat == "" { timestampFormat = defaultTimestampFormat } - if isColored { + if f.isColored() { f.printColored(b, entry, keys, timestampFormat) } else { if !f.DisableTimestamp { From da39da23485a153e5c9b7902e4b5cefbd924ef78 Mon Sep 17 00:00:00 2001 From: Kwok-kuen Cheung Date: Mon, 6 Aug 2018 00:43:49 +0800 Subject: [PATCH 52/92] Keep terminal check naming convention --- terminal_check_appengine.go | 2 +- text_formatter_js.go => terminal_check_js.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename text_formatter_js.go => terminal_check_js.go (51%) diff --git a/terminal_check_appengine.go b/terminal_check_appengine.go index 26a2867..2403de9 100644 --- a/terminal_check_appengine.go +++ b/terminal_check_appengine.go @@ -1,4 +1,4 @@ -// +build appengine js +// +build appengine package logrus diff --git a/text_formatter_js.go b/terminal_check_js.go similarity index 51% rename from text_formatter_js.go rename to terminal_check_js.go index d52803a..0c20975 100644 --- a/text_formatter_js.go +++ b/terminal_check_js.go @@ -6,6 +6,6 @@ import ( "io" ) -func (f *TextFormatter) checkIfTerminal(w io.Writer) bool { +func checkIfTerminal(w io.Writer) bool { return false } From d950ecd55bc2e1ddaf9af20cb8c6910a5633b031 Mon Sep 17 00:00:00 2001 From: Kwok-kuen Cheung Date: Mon, 6 Aug 2018 00:43:58 +0800 Subject: [PATCH 53/92] Remove unnecessary text_formatter file --- text_formatter_other.go | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 text_formatter_other.go diff --git a/text_formatter_other.go b/text_formatter_other.go deleted file mode 100644 index 0d9704f..0000000 --- a/text_formatter_other.go +++ /dev/null @@ -1,3 +0,0 @@ -// +build !js - -package logrus From 8a6a17c00343eaa23f978b454d878ae304992ef2 Mon Sep 17 00:00:00 2001 From: Dennis Date: Sun, 5 Aug 2018 22:40:58 +0200 Subject: [PATCH 54/92] Fixed missing brace after wrong merge --- text_formatter_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/text_formatter_test.go b/text_formatter_test.go index 72adda1..092b19d 100644 --- a/text_formatter_test.go +++ b/text_formatter_test.go @@ -198,6 +198,7 @@ func TestNewlineBehavior(t *testing.T) { if !bytes.Contains(b, []byte("test message\n")) { t.Error("Double newline at end of Entry.Message did not result in a single newline after formatting") } +} func TestTextFormatterFieldMap(t *testing.T) { formatter := &TextFormatter{ From eb968b65069b7b415d83ba5a6451718d3f93763e Mon Sep 17 00:00:00 2001 From: David Bariod Date: Thu, 9 Aug 2018 15:00:46 +0200 Subject: [PATCH 55/92] Fix for CLICOLOR_FORCE handling --- text_formatter.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/text_formatter.go b/text_formatter.go index cdf3185..beb628f 100644 --- a/text_formatter.go +++ b/text_formatter.go @@ -37,7 +37,7 @@ type TextFormatter struct { DisableColors bool // Override coloring based on CLICOLOR and CLICOLOR_FORCE. - https://bixense.com/clicolors/ - OverrideColors bool + EnvironmentOverrideColors bool // Disable timestamp logging. useful when output is redirected to logging // system that already adds timestamps. @@ -85,12 +85,12 @@ func (f *TextFormatter) init(entry *Entry) { func (f *TextFormatter) isColored() bool { isColored := f.ForceColors || f.isTerminal - if f.OverrideColors { + if f.EnvironmentOverrideColors { if force, ok := os.LookupEnv("CLICOLOR_FORCE"); ok && force != "0" { isColored = true - } - - if os.Getenv("CLICOLOR") == "0" { + } else if ok && force == "0" { + isColored = false + } else if os.Getenv("CLICOLOR") == "0" { isColored = false } } From cadf2ceaf8580dddc21b34895f5fed8d2c3b2e60 Mon Sep 17 00:00:00 2001 From: David Bariod Date: Thu, 9 Aug 2018 15:01:49 +0200 Subject: [PATCH 56/92] Add unit test for TextFormatter.isColored --- text_formatter_test.go | 214 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) diff --git a/text_formatter_test.go b/text_formatter_test.go index 921d052..023f346 100644 --- a/text_formatter_test.go +++ b/text_formatter_test.go @@ -4,6 +4,7 @@ import ( "bytes" "errors" "fmt" + "os" "strings" "testing" "time" @@ -216,5 +217,218 @@ func TestTextFormatterFieldMap(t *testing.T) { "Formatted output doesn't respect FieldMap") } +func TestTextFormatterIsColored(t *testing.T) { + params := []struct { + name string + expectedResult bool + isTerminal bool + disableColor bool + forceColor bool + envColor bool + clicolorIsSet bool + clicolorForceIsSet bool + clicolorVal string + clicolorForceVal string + }{ + // Default values + { + name: "testcase1", + expectedResult: false, + isTerminal: false, + disableColor: false, + forceColor: false, + envColor: false, + clicolorIsSet: false, + clicolorForceIsSet: false, + }, + // Output on terminal + { + name: "testcase2", + expectedResult: true, + isTerminal: true, + disableColor: false, + forceColor: false, + envColor: false, + clicolorIsSet: false, + clicolorForceIsSet: false, + }, + // Output on terminal with color disabled + { + name: "testcase3", + expectedResult: false, + isTerminal: true, + disableColor: true, + forceColor: false, + envColor: false, + clicolorIsSet: false, + clicolorForceIsSet: false, + }, + // Output not on terminal with color disabled + { + name: "testcase4", + expectedResult: false, + isTerminal: false, + disableColor: true, + forceColor: false, + envColor: false, + clicolorIsSet: false, + clicolorForceIsSet: false, + }, + // Output not on terminal with color forced + { + name: "testcase5", + expectedResult: true, + isTerminal: false, + disableColor: false, + forceColor: true, + envColor: false, + clicolorIsSet: false, + clicolorForceIsSet: false, + }, + // Output on terminal with clicolor set to "0" + { + name: "testcase6", + expectedResult: false, + isTerminal: true, + disableColor: false, + forceColor: false, + envColor: true, + clicolorIsSet: true, + clicolorForceIsSet: false, + clicolorVal: "0", + }, + // Output on terminal with clicolor set to "1" + { + name: "testcase7", + expectedResult: true, + isTerminal: true, + disableColor: false, + forceColor: false, + envColor: true, + clicolorIsSet: true, + clicolorForceIsSet: false, + clicolorVal: "1", + }, + // Output not on terminal with clicolor set to "0" + { + name: "testcase8", + expectedResult: false, + isTerminal: false, + disableColor: false, + forceColor: false, + envColor: true, + clicolorIsSet: true, + clicolorForceIsSet: false, + clicolorVal: "0", + }, + // Output not on terminal with clicolor set to "1" + { + name: "testcase9", + expectedResult: false, + isTerminal: false, + disableColor: false, + forceColor: false, + envColor: true, + clicolorIsSet: true, + clicolorForceIsSet: false, + clicolorVal: "1", + }, + // Output not on terminal with clicolor set to "1" and force color + { + name: "testcase10", + expectedResult: true, + isTerminal: false, + disableColor: false, + forceColor: true, + envColor: true, + clicolorIsSet: true, + clicolorForceIsSet: false, + clicolorVal: "1", + }, + // Output not on terminal with clicolor set to "0" and force color + { + name: "testcase11", + expectedResult: false, + isTerminal: false, + disableColor: false, + forceColor: true, + envColor: true, + clicolorIsSet: true, + clicolorForceIsSet: false, + clicolorVal: "0", + }, + // Output not on terminal with clicolor set to "1" + { + name: "testcase12", + expectedResult: false, + isTerminal: false, + disableColor: false, + forceColor: false, + envColor: true, + clicolorIsSet: true, + clicolorForceIsSet: false, + clicolorVal: "1", + }, + // Output not on terminal with clicolor_force set to "1" + { + name: "testcase13", + expectedResult: true, + isTerminal: false, + disableColor: false, + forceColor: false, + envColor: true, + clicolorIsSet: false, + clicolorForceIsSet: true, + clicolorForceVal: "1", + }, + // Output not on terminal with clicolor_force set to "0" + { + name: "testcase14", + expectedResult: false, + isTerminal: false, + disableColor: false, + forceColor: false, + envColor: true, + clicolorIsSet: false, + clicolorForceIsSet: true, + clicolorForceVal: "0", + }, + // Output on terminal with clicolor_force set to "0" + { + name: "testcase14", + expectedResult: false, + isTerminal: true, + disableColor: false, + forceColor: false, + envColor: true, + clicolorIsSet: false, + clicolorForceIsSet: true, + clicolorForceVal: "0", + }, + } + + defer os.Clearenv() + + for _, val := range params { + t.Run("textformatter_"+val.name, func(subT *testing.T) { + tf := TextFormatter{ + isTerminal: val.isTerminal, + DisableColors: val.disableColor, + ForceColors: val.forceColor, + EnvironmentOverrideColors: val.envColor, + } + os.Clearenv() + if val.clicolorIsSet { + os.Setenv("CLICOLOR", val.clicolorVal) + } + if val.clicolorForceIsSet { + os.Setenv("CLICOLOR_FORCE", val.clicolorForceVal) + } + res := tf.isColored() + assert.Equal(subT, val.expectedResult, res) + }) + } +} + // TODO add tests for sorting etc., this requires a parser for the text // formatter output. From b5e6fae4fba49f90e609d6379cc6409fa8f85e2e Mon Sep 17 00:00:00 2001 From: David Bariod Date: Mon, 13 Aug 2018 17:27:32 +0200 Subject: [PATCH 57/92] Cleanup on unit test on isColored --- text_formatter_test.go | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/text_formatter_test.go b/text_formatter_test.go index 023f346..652102d 100644 --- a/text_formatter_test.go +++ b/text_formatter_test.go @@ -357,21 +357,9 @@ func TestTextFormatterIsColored(t *testing.T) { clicolorForceIsSet: false, clicolorVal: "0", }, - // Output not on terminal with clicolor set to "1" - { - name: "testcase12", - expectedResult: false, - isTerminal: false, - disableColor: false, - forceColor: false, - envColor: true, - clicolorIsSet: true, - clicolorForceIsSet: false, - clicolorVal: "1", - }, // Output not on terminal with clicolor_force set to "1" { - name: "testcase13", + name: "testcase12", expectedResult: true, isTerminal: false, disableColor: false, @@ -383,7 +371,7 @@ func TestTextFormatterIsColored(t *testing.T) { }, // Output not on terminal with clicolor_force set to "0" { - name: "testcase14", + name: "testcase13", expectedResult: false, isTerminal: false, disableColor: false, @@ -407,7 +395,12 @@ func TestTextFormatterIsColored(t *testing.T) { }, } - defer os.Clearenv() + cleanenv := func() { + os.Unsetenv("CLICOLOR") + os.Unsetenv("CLICOLOR_FORCE") + } + + defer cleanenv() for _, val := range params { t.Run("textformatter_"+val.name, func(subT *testing.T) { @@ -417,7 +410,7 @@ func TestTextFormatterIsColored(t *testing.T) { ForceColors: val.forceColor, EnvironmentOverrideColors: val.envColor, } - os.Clearenv() + cleanenv() if val.clicolorIsSet { os.Setenv("CLICOLOR", val.clicolorVal) } From 7a0120e2c67ac3a748674a84fbb6ca4fe6231897 Mon Sep 17 00:00:00 2001 From: betrok Date: Wed, 22 Aug 2018 12:10:05 +0300 Subject: [PATCH 58/92] logger.ReplaceHooks --- logger.go | 6 ++++++ logrus_test.go | 16 ++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/logger.go b/logger.go index 7fa8d7d..53bbf95 100644 --- a/logger.go +++ b/logger.go @@ -336,3 +336,9 @@ func (logger *Logger) AddHook(hook Hook) { defer logger.mu.Unlock() logger.Hooks.Add(hook) } + +func (logger *Logger) ReplaceHooks(hooks LevelHooks) { + logger.mu.Lock() + logger.Hooks = hooks + logger.mu.Unlock() +} diff --git a/logrus_test.go b/logrus_test.go index 57fb8d1..7a96686 100644 --- a/logrus_test.go +++ b/logrus_test.go @@ -421,6 +421,22 @@ func TestLoggingRaceWithHooksOnEntry(t *testing.T) { wg.Wait() } +func TestHooksReplace(t *testing.T) { + old, cur := &TestHook{}, &TestHook{} + + logger := New() + logger.AddHook(old) + + hooks := make(LevelHooks) + hooks.Add(cur) + logger.ReplaceHooks(hooks) + + logger.Info("test") + + assert.Equal(t, old.Fired, false) + assert.Equal(t, cur.Fired, true) +} + // Compile test func TestLogrusInterface(t *testing.T) { var buffer bytes.Buffer From 13d10d8d89db071ade54fb0b1667817dd48dc53e Mon Sep 17 00:00:00 2001 From: betrok Date: Sun, 26 Aug 2018 14:40:51 +0300 Subject: [PATCH 59/92] return old hooks from RelplaceHooks --- logger.go | 5 ++++- logrus_test.go | 10 ++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/logger.go b/logger.go index 53bbf95..885f150 100644 --- a/logger.go +++ b/logger.go @@ -337,8 +337,11 @@ func (logger *Logger) AddHook(hook Hook) { logger.Hooks.Add(hook) } -func (logger *Logger) ReplaceHooks(hooks LevelHooks) { +// ReplaceHooks replaces the logger hooks and returns the old ones +func (logger *Logger) ReplaceHooks(hooks LevelHooks) LevelHooks { logger.mu.Lock() + oldHooks := logger.Hooks logger.Hooks = hooks logger.mu.Unlock() + return oldHooks } diff --git a/logrus_test.go b/logrus_test.go index 7a96686..f6db6e9 100644 --- a/logrus_test.go +++ b/logrus_test.go @@ -3,6 +3,7 @@ package logrus import ( "bytes" "encoding/json" + "io/ioutil" "strconv" "strings" "sync" @@ -421,20 +422,25 @@ func TestLoggingRaceWithHooksOnEntry(t *testing.T) { wg.Wait() } -func TestHooksReplace(t *testing.T) { +func TestReplaceHooks(t *testing.T) { old, cur := &TestHook{}, &TestHook{} logger := New() + logger.SetOutput(ioutil.Discard) logger.AddHook(old) hooks := make(LevelHooks) hooks.Add(cur) - logger.ReplaceHooks(hooks) + replaced := logger.ReplaceHooks(hooks) logger.Info("test") assert.Equal(t, old.Fired, false) assert.Equal(t, cur.Fired, true) + + logger.ReplaceHooks(replaced) + logger.Info("test") + assert.Equal(t, old.Fired, true) } // Compile test From 90bf2e7f391a08ecb7d505856924ed3bf1bc771f Mon Sep 17 00:00:00 2001 From: Logan HAUSPIE Date: Sun, 26 Aug 2018 23:51:09 +0200 Subject: [PATCH 60/92] feat(LogLevel): taking in account code review from David Bariod --- entry.go | 60 +++++++++++++---------------------------- exported.go | 25 +++--------------- logger.go | 65 +++++++++++++++++---------------------------- logrus.go | 12 ++++----- logrus_test.go | 72 +++++++++++++++++++++++++------------------------- 5 files changed, 87 insertions(+), 147 deletions(-) diff --git a/entry.go b/entry.go index 82ef93c..8c6a389 100644 --- a/entry.go +++ b/entry.go @@ -151,7 +151,7 @@ func (entry *Entry) write() { } func (entry *Entry) Debug(args ...interface{}) { - if entry.IsDebugEnabled() { + if entry.Logger.IsLevelEnabled(DebugLevel) { entry.log(DebugLevel, fmt.Sprint(args...)) } } @@ -161,13 +161,13 @@ func (entry *Entry) Print(args ...interface{}) { } func (entry *Entry) Info(args ...interface{}) { - if entry.IsInfoEnabled() { + if entry.Logger.IsLevelEnabled(InfoLevel) { entry.log(InfoLevel, fmt.Sprint(args...)) } } func (entry *Entry) Warn(args ...interface{}) { - if entry.IsWarnEnabled() { + if entry.Logger.IsLevelEnabled(WarnLevel) { entry.log(WarnLevel, fmt.Sprint(args...)) } } @@ -177,20 +177,20 @@ func (entry *Entry) Warning(args ...interface{}) { } func (entry *Entry) Error(args ...interface{}) { - if entry.IsErrorEnabled() { + if entry.Logger.IsLevelEnabled(ErrorLevel) { entry.log(ErrorLevel, fmt.Sprint(args...)) } } func (entry *Entry) Fatal(args ...interface{}) { - if entry.IsFatalEnabled() { + if entry.Logger.IsLevelEnabled(FatalLevel) { entry.log(FatalLevel, fmt.Sprint(args...)) } Exit(1) } func (entry *Entry) Panic(args ...interface{}) { - if entry.IsPanicEnabled() { + if entry.Logger.IsLevelEnabled(PanicLevel) { entry.log(PanicLevel, fmt.Sprint(args...)) } panic(fmt.Sprint(args...)) @@ -199,13 +199,13 @@ func (entry *Entry) Panic(args ...interface{}) { // Entry Printf family functions func (entry *Entry) Debugf(format string, args ...interface{}) { - if entry.IsDebugEnabled() { + if entry.Logger.IsLevelEnabled(DebugLevel) { entry.Debug(fmt.Sprintf(format, args...)) } } func (entry *Entry) Infof(format string, args ...interface{}) { - if entry.IsInfoEnabled() { + if entry.Logger.IsLevelEnabled(InfoLevel) { entry.Info(fmt.Sprintf(format, args...)) } } @@ -215,7 +215,7 @@ func (entry *Entry) Printf(format string, args ...interface{}) { } func (entry *Entry) Warnf(format string, args ...interface{}) { - if entry.IsWarnEnabled() { + if entry.Logger.IsLevelEnabled(WarnLevel) { entry.Warn(fmt.Sprintf(format, args...)) } } @@ -225,20 +225,20 @@ func (entry *Entry) Warningf(format string, args ...interface{}) { } func (entry *Entry) Errorf(format string, args ...interface{}) { - if entry.IsErrorEnabled() { + if entry.Logger.IsLevelEnabled(ErrorLevel) { entry.Error(fmt.Sprintf(format, args...)) } } func (entry *Entry) Fatalf(format string, args ...interface{}) { - if entry.IsFatalEnabled() { + if entry.Logger.IsLevelEnabled(FatalLevel) { entry.Fatal(fmt.Sprintf(format, args...)) } Exit(1) } func (entry *Entry) Panicf(format string, args ...interface{}) { - if entry.IsPanicEnabled() { + if entry.Logger.IsLevelEnabled(PanicLevel) { entry.Panic(fmt.Sprintf(format, args...)) } } @@ -246,13 +246,13 @@ func (entry *Entry) Panicf(format string, args ...interface{}) { // Entry Println family functions func (entry *Entry) Debugln(args ...interface{}) { - if entry.IsDebugEnabled() { + if entry.Logger.IsLevelEnabled(DebugLevel) { entry.Debug(entry.sprintlnn(args...)) } } func (entry *Entry) Infoln(args ...interface{}) { - if entry.IsInfoEnabled() { + if entry.Logger.IsLevelEnabled(InfoLevel) { entry.Info(entry.sprintlnn(args...)) } } @@ -262,7 +262,7 @@ func (entry *Entry) Println(args ...interface{}) { } func (entry *Entry) Warnln(args ...interface{}) { - if entry.IsWarnEnabled() { + if entry.Logger.IsLevelEnabled(WarnLevel) { entry.Warn(entry.sprintlnn(args...)) } } @@ -272,48 +272,24 @@ func (entry *Entry) Warningln(args ...interface{}) { } func (entry *Entry) Errorln(args ...interface{}) { - if entry.IsErrorEnabled() { + if entry.Logger.IsLevelEnabled(ErrorLevel) { entry.Error(entry.sprintlnn(args...)) } } func (entry *Entry) Fatalln(args ...interface{}) { - if entry.IsFatalEnabled() { + if entry.Logger.IsLevelEnabled(FatalLevel) { entry.Fatal(entry.sprintlnn(args...)) } Exit(1) } func (entry *Entry) Panicln(args ...interface{}) { - if entry.IsPanicEnabled() { + if entry.Logger.IsLevelEnabled(PanicLevel) { entry.Panic(entry.sprintlnn(args...)) } } -func (entry *Entry) IsDebugEnabled() bool { - return entry.Logger.IsDebugEnabled() -} - -func (entry *Entry) IsInfoEnabled() bool { - return entry.Logger.IsInfoEnabled() -} - -func (entry *Entry) IsWarnEnabled() bool { - return entry.Logger.IsWarnEnabled() -} - -func (entry *Entry) IsErrorEnabled() bool { - return entry.Logger.IsErrorEnabled() -} - -func (entry *Entry) IsFatalEnabled() bool { - return entry.Logger.IsFatalEnabled() -} - -func (entry *Entry) IsPanicEnabled() bool { - return entry.Logger.IsPanicEnabled() -} - // Sprintlnn => Sprint no newline. This is to get the behavior of how // fmt.Sprintln where spaces are always added between operands, regardless of // their type. Instead of vendoring the Sprintln implementation to spare a diff --git a/exported.go b/exported.go index 7643671..fb2a7a1 100644 --- a/exported.go +++ b/exported.go @@ -34,28 +34,9 @@ func GetLevel() Level { return std.GetLevel() } -func IsDebugEnabled() bool { - return std.IsDebugEnabled() -} - -func IsInfoEnabled() bool { - return std.IsInfoEnabled() -} - -func IsWarnEnabled() bool { - return std.IsWarnEnabled() -} - -func IsErrorEnabled() bool { - return std.IsErrorEnabled() -} - -func IsFatalEnabled() bool { - return std.IsFatalEnabled() -} - -func IsPanicEnabled() bool { - return std.IsPanicEnabled() +// IsLevelEnabled checks if the log level of the standard logger is greater than the level param +func IsLevelEnabled(level Level) bool { + return std.IsLevelEnabled(level) } // AddHook adds a hook to the standard logger hooks. diff --git a/logger.go b/logger.go index 61bc1cc..b67bfcb 100644 --- a/logger.go +++ b/logger.go @@ -122,7 +122,7 @@ func (logger *Logger) WithTime(t time.Time) *Entry { } func (logger *Logger) Debugf(format string, args ...interface{}) { - if logger.IsDebugEnabled() { + if logger.IsLevelEnabled(DebugLevel) { entry := logger.newEntry() entry.Debugf(format, args...) logger.releaseEntry(entry) @@ -130,7 +130,7 @@ func (logger *Logger) Debugf(format string, args ...interface{}) { } func (logger *Logger) Infof(format string, args ...interface{}) { - if logger.IsInfoEnabled() { + if logger.IsLevelEnabled(InfoLevel) { entry := logger.newEntry() entry.Infof(format, args...) logger.releaseEntry(entry) @@ -144,7 +144,7 @@ func (logger *Logger) Printf(format string, args ...interface{}) { } func (logger *Logger) Warnf(format string, args ...interface{}) { - if logger.IsWarnEnabled() { + if logger.IsLevelEnabled(WarnLevel) { entry := logger.newEntry() entry.Warnf(format, args...) logger.releaseEntry(entry) @@ -152,7 +152,7 @@ func (logger *Logger) Warnf(format string, args ...interface{}) { } func (logger *Logger) Warningf(format string, args ...interface{}) { - if logger.IsWarnEnabled() { + if logger.IsLevelEnabled(WarnLevel) { entry := logger.newEntry() entry.Warnf(format, args...) logger.releaseEntry(entry) @@ -160,7 +160,7 @@ func (logger *Logger) Warningf(format string, args ...interface{}) { } func (logger *Logger) Errorf(format string, args ...interface{}) { - if logger.IsErrorEnabled() { + if logger.IsLevelEnabled(ErrorLevel) { entry := logger.newEntry() entry.Errorf(format, args...) logger.releaseEntry(entry) @@ -168,7 +168,7 @@ func (logger *Logger) Errorf(format string, args ...interface{}) { } func (logger *Logger) Fatalf(format string, args ...interface{}) { - if logger.IsFatalEnabled() { + if logger.IsLevelEnabled(FatalLevel) { entry := logger.newEntry() entry.Fatalf(format, args...) logger.releaseEntry(entry) @@ -177,7 +177,7 @@ func (logger *Logger) Fatalf(format string, args ...interface{}) { } func (logger *Logger) Panicf(format string, args ...interface{}) { - if logger.IsPanicEnabled() { + if logger.IsLevelEnabled(PanicLevel) { entry := logger.newEntry() entry.Panicf(format, args...) logger.releaseEntry(entry) @@ -185,7 +185,7 @@ func (logger *Logger) Panicf(format string, args ...interface{}) { } func (logger *Logger) Debug(args ...interface{}) { - if logger.IsDebugEnabled() { + if logger.IsLevelEnabled(DebugLevel) { entry := logger.newEntry() entry.Debug(args...) logger.releaseEntry(entry) @@ -193,7 +193,7 @@ func (logger *Logger) Debug(args ...interface{}) { } func (logger *Logger) Info(args ...interface{}) { - if logger.IsInfoEnabled() { + if logger.IsLevelEnabled(InfoLevel) { entry := logger.newEntry() entry.Info(args...) logger.releaseEntry(entry) @@ -207,7 +207,7 @@ func (logger *Logger) Print(args ...interface{}) { } func (logger *Logger) Warn(args ...interface{}) { - if logger.IsWarnEnabled() { + if logger.IsLevelEnabled(WarnLevel) { entry := logger.newEntry() entry.Warn(args...) logger.releaseEntry(entry) @@ -215,7 +215,7 @@ func (logger *Logger) Warn(args ...interface{}) { } func (logger *Logger) Warning(args ...interface{}) { - if logger.IsWarnEnabled() { + if logger.IsLevelEnabled(WarnLevel) { entry := logger.newEntry() entry.Warn(args...) logger.releaseEntry(entry) @@ -223,7 +223,7 @@ func (logger *Logger) Warning(args ...interface{}) { } func (logger *Logger) Error(args ...interface{}) { - if logger.IsErrorEnabled() { + if logger.IsLevelEnabled(ErrorLevel) { entry := logger.newEntry() entry.Error(args...) logger.releaseEntry(entry) @@ -231,7 +231,7 @@ func (logger *Logger) Error(args ...interface{}) { } func (logger *Logger) Fatal(args ...interface{}) { - if logger.IsFatalEnabled() { + if logger.IsLevelEnabled(FatalLevel) { entry := logger.newEntry() entry.Fatal(args...) logger.releaseEntry(entry) @@ -240,7 +240,7 @@ func (logger *Logger) Fatal(args ...interface{}) { } func (logger *Logger) Panic(args ...interface{}) { - if logger.IsPanicEnabled() { + if logger.IsLevelEnabled(PanicLevel) { entry := logger.newEntry() entry.Panic(args...) logger.releaseEntry(entry) @@ -248,7 +248,7 @@ func (logger *Logger) Panic(args ...interface{}) { } func (logger *Logger) Debugln(args ...interface{}) { - if logger.IsDebugEnabled() { + if logger.IsLevelEnabled(DebugLevel) { entry := logger.newEntry() entry.Debugln(args...) logger.releaseEntry(entry) @@ -256,7 +256,7 @@ func (logger *Logger) Debugln(args ...interface{}) { } func (logger *Logger) Infoln(args ...interface{}) { - if logger.IsInfoEnabled() { + if logger.IsLevelEnabled(InfoLevel) { entry := logger.newEntry() entry.Infoln(args...) logger.releaseEntry(entry) @@ -270,7 +270,7 @@ func (logger *Logger) Println(args ...interface{}) { } func (logger *Logger) Warnln(args ...interface{}) { - if logger.IsWarnEnabled() { + if logger.IsLevelEnabled(WarnLevel) { entry := logger.newEntry() entry.Warnln(args...) logger.releaseEntry(entry) @@ -278,7 +278,7 @@ func (logger *Logger) Warnln(args ...interface{}) { } func (logger *Logger) Warningln(args ...interface{}) { - if logger.IsWarnEnabled() { + if logger.IsLevelEnabled(WarnLevel) { entry := logger.newEntry() entry.Warnln(args...) logger.releaseEntry(entry) @@ -286,7 +286,7 @@ func (logger *Logger) Warningln(args ...interface{}) { } func (logger *Logger) Errorln(args ...interface{}) { - if logger.IsErrorEnabled() { + if logger.IsLevelEnabled(ErrorLevel) { entry := logger.newEntry() entry.Errorln(args...) logger.releaseEntry(entry) @@ -294,7 +294,7 @@ func (logger *Logger) Errorln(args ...interface{}) { } func (logger *Logger) Fatalln(args ...interface{}) { - if logger.IsFatalEnabled() { + if logger.IsLevelEnabled(FatalLevel) { entry := logger.newEntry() entry.Fatalln(args...) logger.releaseEntry(entry) @@ -303,7 +303,7 @@ func (logger *Logger) Fatalln(args ...interface{}) { } func (logger *Logger) Panicln(args ...interface{}) { - if logger.IsPanicEnabled() { + if logger.IsLevelEnabled(PanicLevel) { entry := logger.newEntry() entry.Panicln(args...) logger.releaseEntry(entry) @@ -338,28 +338,11 @@ func (logger *Logger) AddHook(hook Hook) { logger.Hooks.Add(hook) } -func (logger *Logger) IsDebugEnabled() bool { - return logger.level() >= DebugLevel +// IsLevelEnabled checks if the log level of the logger is greater than the level param +func (logger *Logger) IsLevelEnabled(level Level) bool { + return logger.level() >= level } -func (logger *Logger) IsInfoEnabled() bool { - return logger.level() >= InfoLevel -} - -func (logger *Logger) IsWarnEnabled() bool { - return logger.level() >= WarnLevel -} - -func (logger *Logger) IsErrorEnabled() bool { - return logger.level() >= ErrorLevel -} - -func (logger *Logger) IsFatalEnabled() bool { - return logger.level() >= FatalLevel -} - -func (logger *Logger) IsPanicEnabled() bool { - return logger.level() >= PanicLevel // SetFormatter sets the logger formatter. func (logger *Logger) SetFormatter(formatter Formatter) { logger.mu.Lock() diff --git a/logrus.go b/logrus.go index 33e07fa..fa0b9de 100644 --- a/logrus.go +++ b/logrus.go @@ -141,10 +141,10 @@ type FieldLogger interface { Fatalln(args ...interface{}) Panicln(args ...interface{}) - IsDebugEnabled() bool - IsInfoEnabled() bool - IsWarnEnabled() bool - IsErrorEnabled() bool - IsFatalEnabled() bool - IsPanicEnabled() bool + // IsDebugEnabled() bool + // IsInfoEnabled() bool + // IsWarnEnabled() bool + // IsErrorEnabled() bool + // IsFatalEnabled() bool + // IsPanicEnabled() bool } diff --git a/logrus_test.go b/logrus_test.go index 4820e33..97d15d7 100644 --- a/logrus_test.go +++ b/logrus_test.go @@ -488,50 +488,50 @@ func TestEntryWriter(t *testing.T) { func TestLogLevelEnabled(t *testing.T) { log := New() log.SetLevel(PanicLevel) - assert.Equal(t, true, log.IsPanicEnabled()) - assert.Equal(t, false, log.IsFatalEnabled()) - assert.Equal(t, false, log.IsErrorEnabled()) - assert.Equal(t, false, log.IsWarnEnabled()) - assert.Equal(t, false, log.IsInfoEnabled()) - assert.Equal(t, false, log.IsDebugEnabled()) + assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) + assert.Equal(t, false, log.IsLevelEnabled(FatalLevel)) + assert.Equal(t, false, log.IsLevelEnabled(ErrorLevel)) + assert.Equal(t, false, log.IsLevelEnabled(WarnLevel)) + assert.Equal(t, false, log.IsLevelEnabled(InfoLevel)) + assert.Equal(t, false, log.IsLevelEnabled(DebugLevel)) log.SetLevel(FatalLevel) - assert.Equal(t, true, log.IsPanicEnabled()) - assert.Equal(t, true, log.IsFatalEnabled()) - assert.Equal(t, false, log.IsErrorEnabled()) - assert.Equal(t, false, log.IsWarnEnabled()) - assert.Equal(t, false, log.IsInfoEnabled()) - assert.Equal(t, false, log.IsDebugEnabled()) + assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) + assert.Equal(t, true, log.IsLevelEnabled(FatalLevel)) + assert.Equal(t, false, log.IsLevelEnabled(ErrorLevel)) + assert.Equal(t, false, log.IsLevelEnabled(WarnLevel)) + assert.Equal(t, false, log.IsLevelEnabled(InfoLevel)) + assert.Equal(t, false, log.IsLevelEnabled(DebugLevel)) log.SetLevel(ErrorLevel) - assert.Equal(t, true, log.IsPanicEnabled()) - assert.Equal(t, true, log.IsFatalEnabled()) - assert.Equal(t, true, log.IsErrorEnabled()) - assert.Equal(t, false, log.IsWarnEnabled()) - assert.Equal(t, false, log.IsInfoEnabled()) - assert.Equal(t, false, log.IsDebugEnabled()) + assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) + assert.Equal(t, true, log.IsLevelEnabled(FatalLevel)) + assert.Equal(t, true, log.IsLevelEnabled(ErrorLevel)) + assert.Equal(t, false, log.IsLevelEnabled(WarnLevel)) + assert.Equal(t, false, log.IsLevelEnabled(InfoLevel)) + assert.Equal(t, false, log.IsLevelEnabled(DebugLevel)) log.SetLevel(WarnLevel) - assert.Equal(t, true, log.IsPanicEnabled()) - assert.Equal(t, true, log.IsFatalEnabled()) - assert.Equal(t, true, log.IsErrorEnabled()) - assert.Equal(t, true, log.IsWarnEnabled()) - assert.Equal(t, false, log.IsInfoEnabled()) - assert.Equal(t, false, log.IsDebugEnabled()) + assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) + assert.Equal(t, true, log.IsLevelEnabled(FatalLevel)) + assert.Equal(t, true, log.IsLevelEnabled(ErrorLevel)) + assert.Equal(t, true, log.IsLevelEnabled(WarnLevel)) + assert.Equal(t, false, log.IsLevelEnabled(InfoLevel)) + assert.Equal(t, false, log.IsLevelEnabled(DebugLevel)) log.SetLevel(InfoLevel) - assert.Equal(t, true, log.IsPanicEnabled()) - assert.Equal(t, true, log.IsFatalEnabled()) - assert.Equal(t, true, log.IsErrorEnabled()) - assert.Equal(t, true, log.IsWarnEnabled()) - assert.Equal(t, true, log.IsInfoEnabled()) - assert.Equal(t, false, log.IsDebugEnabled()) + assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) + assert.Equal(t, true, log.IsLevelEnabled(FatalLevel)) + assert.Equal(t, true, log.IsLevelEnabled(ErrorLevel)) + assert.Equal(t, true, log.IsLevelEnabled(WarnLevel)) + assert.Equal(t, true, log.IsLevelEnabled(InfoLevel)) + assert.Equal(t, false, log.IsLevelEnabled(DebugLevel)) log.SetLevel(DebugLevel) - assert.Equal(t, true, log.IsPanicEnabled()) - assert.Equal(t, true, log.IsFatalEnabled()) - assert.Equal(t, true, log.IsErrorEnabled()) - assert.Equal(t, true, log.IsWarnEnabled()) - assert.Equal(t, true, log.IsInfoEnabled()) - assert.Equal(t, true, log.IsDebugEnabled()) + assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) + assert.Equal(t, true, log.IsLevelEnabled(FatalLevel)) + assert.Equal(t, true, log.IsLevelEnabled(ErrorLevel)) + assert.Equal(t, true, log.IsLevelEnabled(WarnLevel)) + assert.Equal(t, true, log.IsLevelEnabled(InfoLevel)) + assert.Equal(t, true, log.IsLevelEnabled(DebugLevel)) } From 98d0f313feb5dd384db2b29e2c12481d382f8c3c Mon Sep 17 00:00:00 2001 From: David Bariod Date: Thu, 30 Aug 2018 07:17:54 +0200 Subject: [PATCH 61/92] Add previously forgotten v1.0.6 description in changelog fixes #802 --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bd1deb..ff40b2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +# 1.0.6 + +This new release introduces: + * a new api WithTime which allows to easily force the time of the log entry + which is mostly useful for logger wrapper + * a fix reverting the immutability of the entry given as parameter to the hooks + a new configuration field of the json formatter in order to put all the fields + in a nested dictionnary + * a new SetOutput method in the Logger + * a new configuration of the textformatter to configure the name of the default keys + * a new configuration of the text formatter to disable the level truncation + # 1.0.5 * Fix hooks race (#707) From e58aa84bc1ffea0f9a7fa46891bd659a0b414e97 Mon Sep 17 00:00:00 2001 From: David Bariod Date: Thu, 30 Aug 2018 22:06:53 +0200 Subject: [PATCH 62/92] bump go toolchain version in travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2f19b4a..2bd3496 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: go go: - - 1.9.x - 1.10.x + - 1.11.x env: - GOMAXPROCS=4 GORACE=halt_on_error=1 install: From 7556e245e22e7d23e075791afabadce5cfc4516a Mon Sep 17 00:00:00 2001 From: David Bariod Date: Sun, 2 Sep 2018 20:22:06 +0200 Subject: [PATCH 63/92] Use syslog instead of airbrake as syslog example The purpose is to reduce package dependencies, fixes #809. --- example_hook_test.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/example_hook_test.go b/example_hook_test.go index d4ddffc..b997c56 100644 --- a/example_hook_test.go +++ b/example_hook_test.go @@ -2,7 +2,8 @@ package logrus_test import ( "github.com/sirupsen/logrus" - "gopkg.in/gemnasium/logrus-airbrake-hook.v2" + slhooks "github.com/sirupsen/logrus/hooks/syslog" + "log/syslog" "os" ) @@ -10,7 +11,9 @@ func Example_hook() { var log = logrus.New() log.Formatter = new(logrus.TextFormatter) // default log.Formatter.(*logrus.TextFormatter).DisableTimestamp = true // remove timestamp from test output - log.Hooks.Add(airbrake.NewHook(123, "xyz", "development")) + if sl, err := slhooks.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, ""); err != nil { + log.Hooks.Add(sl) + } log.Out = os.Stdout log.WithFields(logrus.Fields{ From 8b120431f3f374c0365f24021322dda147714c24 Mon Sep 17 00:00:00 2001 From: David Bariod Date: Mon, 3 Sep 2018 21:58:50 +0200 Subject: [PATCH 64/92] Fix example build on windows --- example_hook_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/example_hook_test.go b/example_hook_test.go index b997c56..4e4ea1d 100644 --- a/example_hook_test.go +++ b/example_hook_test.go @@ -1,3 +1,5 @@ +// +build !windows + package logrus_test import ( From 4bcb47b846362274026619052b2dcec92328ab62 Mon Sep 17 00:00:00 2001 From: David Bariod Date: Tue, 4 Sep 2018 22:15:13 +0200 Subject: [PATCH 65/92] commit to trigger appveyor build --- example_hook_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/example_hook_test.go b/example_hook_test.go index 4e4ea1d..28bd8ea 100644 --- a/example_hook_test.go +++ b/example_hook_test.go @@ -9,6 +9,7 @@ import ( "os" ) +// An example on how to use a hook func Example_hook() { var log = logrus.New() log.Formatter = new(logrus.TextFormatter) // default From f75951b604e3ef800fc3e6a3e58486a5323210e6 Mon Sep 17 00:00:00 2001 From: Dave Goddard Date: Thu, 6 Sep 2018 09:49:06 -0300 Subject: [PATCH 66/92] Add go module support Travis will only run the "go get" install lines if using go 1.10.x --- .travis.yml | 17 +++++++++-------- go.mod | 23 +++++++++++++++++++++++ go.sum | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 8 deletions(-) create mode 100644 go.mod create mode 100644 go.sum diff --git a/.travis.yml b/.travis.yml index 2bd3496..de38feb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,14 @@ language: go -go: - - 1.10.x - - 1.11.x env: - GOMAXPROCS=4 GORACE=halt_on_error=1 -install: - - go get github.com/stretchr/testify/assert - - go get gopkg.in/gemnasium/logrus-airbrake-hook.v2 - - go get golang.org/x/sys/unix - - go get golang.org/x/sys/windows +matrix: + include: + - go: 1.10.x + install: + - go get github.com/stretchr/testify/assert + - go get gopkg.in/gemnasium/logrus-airbrake-hook.v2 + - go get golang.org/x/sys/unix + - go get golang.org/x/sys/windows + - go: 1.11.x script: - go test -race -v ./... diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..7946fe9 --- /dev/null +++ b/go.mod @@ -0,0 +1,23 @@ +module github.com/dgodd/logrus + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/fsnotify/fsnotify v1.4.7 // indirect + github.com/golang/protobuf v1.2.0 // indirect + github.com/hpcloud/tail v1.0.0 // indirect + github.com/onsi/ginkgo v1.6.0 // indirect + github.com/onsi/gomega v1.4.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/sirupsen/logrus v1.0.6 + github.com/stretchr/testify v1.2.2 + golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 + golang.org/x/net v0.0.0-20180826012351-8a410e7b638d // indirect + golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f // indirect + golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 + golang.org/x/text v0.3.0 // indirect + gopkg.in/airbrake/gobrake.v2 v2.0.9 // indirect + gopkg.in/fsnotify.v1 v1.4.7 // indirect + gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2 // indirect + gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect + gopkg.in/yaml.v2 v2.2.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..24aaefe --- /dev/null +++ b/go.sum @@ -0,0 +1,40 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.4.1 h1:PZSj/UFNaVp3KxrzHOcS7oyuWA7LoOY/77yCTEFu21U= +github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.0.6 h1:hcP1GmhGigz/O7h1WVUM5KklBp1JoNS9FggWKdj/j3s= +github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d h1:g9qWBGx4puODJTMVyoPrpoxPFgVGd+z1DZwjfRu4d0I= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 h1:I6FyU15t786LL7oL/hn43zqTuEGr4PN7F4XJ1p4E3Y8= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/airbrake/gobrake.v2 v2.0.9 h1:7z2uVWwn7oVeeugY1DtlPAy5H+KYgB1KeKTnqjNatLo= +gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2 h1:OAj3g0cR6Dx/R07QgQe8wkA9RNjB2u4i700xBkIT4e0= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= From 88eb166d31087867eb651f4434839644d8c59a6c Mon Sep 17 00:00:00 2001 From: William Huang Date: Thu, 6 Sep 2018 21:11:16 -0500 Subject: [PATCH 67/92] Fix spelling in Entry.Buffer comment --- entry.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entry.go b/entry.go index 8c6a389..4efeddd 100644 --- a/entry.go +++ b/entry.go @@ -41,7 +41,7 @@ type Entry struct { // Message passed to Debug, Info, Warn, Error, Fatal or Panic Message string - // When formatter is called in entry.log(), an Buffer may be set to entry + // When formatter is called in entry.log(), a Buffer may be set to entry Buffer *bytes.Buffer } From 66895ce1655f9b7c12ae5a9df6efe672a041f15d Mon Sep 17 00:00:00 2001 From: David Bariod Date: Sat, 8 Sep 2018 08:27:05 +0200 Subject: [PATCH 68/92] Fix module name and remove unused dependencies --- .travis.yml | 2 ++ go.mod | 16 +--------------- go.sum | 30 ------------------------------ 3 files changed, 3 insertions(+), 45 deletions(-) diff --git a/.travis.yml b/.travis.yml index de38feb..001842f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,5 +10,7 @@ matrix: - go get golang.org/x/sys/unix - go get golang.org/x/sys/windows - go: 1.11.x + install: + - go mod download script: - go test -race -v ./... diff --git a/go.mod b/go.mod index 7946fe9..faee392 100644 --- a/go.mod +++ b/go.mod @@ -1,23 +1,9 @@ -module github.com/dgodd/logrus +module github.com/sirupsen/logrus require ( github.com/davecgh/go-spew v1.1.1 // indirect - github.com/fsnotify/fsnotify v1.4.7 // indirect - github.com/golang/protobuf v1.2.0 // indirect - github.com/hpcloud/tail v1.0.0 // indirect - github.com/onsi/ginkgo v1.6.0 // indirect - github.com/onsi/gomega v1.4.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/sirupsen/logrus v1.0.6 github.com/stretchr/testify v1.2.2 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 - golang.org/x/net v0.0.0-20180826012351-8a410e7b638d // indirect - golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f // indirect golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 - golang.org/x/text v0.3.0 // indirect - gopkg.in/airbrake/gobrake.v2 v2.0.9 // indirect - gopkg.in/fsnotify.v1 v1.4.7 // indirect - gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2 // indirect - gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect - gopkg.in/yaml.v2 v2.2.1 // indirect ) diff --git a/go.sum b/go.sum index 24aaefe..7fd44a1 100644 --- a/go.sum +++ b/go.sum @@ -1,40 +1,10 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.4.1 h1:PZSj/UFNaVp3KxrzHOcS7oyuWA7LoOY/77yCTEFu21U= -github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/sirupsen/logrus v1.0.6 h1:hcP1GmhGigz/O7h1WVUM5KklBp1JoNS9FggWKdj/j3s= -github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d h1:g9qWBGx4puODJTMVyoPrpoxPFgVGd+z1DZwjfRu4d0I= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 h1:I6FyU15t786LL7oL/hn43zqTuEGr4PN7F4XJ1p4E3Y8= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -gopkg.in/airbrake/gobrake.v2 v2.0.9 h1:7z2uVWwn7oVeeugY1DtlPAy5H+KYgB1KeKTnqjNatLo= -gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2 h1:OAj3g0cR6Dx/R07QgQe8wkA9RNjB2u4i700xBkIT4e0= -gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= From eed7c223745826b148628edb742f682d5aaf5e49 Mon Sep 17 00:00:00 2001 From: David Bariod Date: Sat, 8 Sep 2018 09:44:05 +0200 Subject: [PATCH 69/92] Fix travis build for go 1.11 with modules --- .travis.yml | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 001842f..dd1218c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,11 +6,23 @@ matrix: - go: 1.10.x install: - go get github.com/stretchr/testify/assert - - go get gopkg.in/gemnasium/logrus-airbrake-hook.v2 + - go get golang.org/x/crypto/ssh/terminal - go get golang.org/x/sys/unix - go get golang.org/x/sys/windows + script: + - go test -race -v ./... - go: 1.11.x + env: GO111MODULE=on install: - go mod download -script: - - go test -race -v ./... + script: + - go test -race -v ./... + - go: 1.11.x + env: GO111MODULE=off + install: + - go get github.com/stretchr/testify/assert + - go get golang.org/x/crypto/ssh/terminal + - go get golang.org/x/sys/unix + - go get golang.org/x/sys/windows + script: + - go test -race -v ./... From 98c898cc2d6cfa5b8589c1266b9e56cf207981a5 Mon Sep 17 00:00:00 2001 From: David Bariod Date: Sun, 16 Sep 2018 10:14:59 +0200 Subject: [PATCH 70/92] Fix gopherjs build constraint name --- terminal_check_windows.go | 2 +- terminal_windows.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/terminal_check_windows.go b/terminal_check_windows.go index 17ebe80..3b9d286 100644 --- a/terminal_check_windows.go +++ b/terminal_check_windows.go @@ -1,4 +1,4 @@ -// +build !appengine,!gopherjs,windows +// +build !appengine,!js,windows package logrus diff --git a/terminal_windows.go b/terminal_windows.go index 2494950..b4ef528 100644 --- a/terminal_windows.go +++ b/terminal_windows.go @@ -1,4 +1,4 @@ -// +build !appengine,!gopherjs,windows +// +build !appengine,!js,windows package logrus From 90501cfcc53d8ff36297203d6e8e0653da98f7d1 Mon Sep 17 00:00:00 2001 From: Mark Dittmer Date: Mon, 17 Sep 2018 13:50:48 -0400 Subject: [PATCH 71/92] Fix AppEngine builds `go build -tags appengine [...]` currently yields: ``` .../github.com/sirupsen/logrus/text_formatter.go:84:4: undefined: initTerminal ``` This change implements `initTerminal` for AppEngine builds. --- terminal_appengine.go | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 terminal_appengine.go diff --git a/terminal_appengine.go b/terminal_appengine.go new file mode 100644 index 0000000..2f34402 --- /dev/null +++ b/terminal_appengine.go @@ -0,0 +1,11 @@ +// Based on ssh/terminal: +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build appengine + +package logrus + +func initTerminal(w io.Writer) { +} From f1ce1baf5623907d7056fc71a6e4232447f01cc5 Mon Sep 17 00:00:00 2001 From: Mark Dittmer Date: Mon, 17 Sep 2018 13:52:43 -0400 Subject: [PATCH 72/92] Fix copypasta --- terminal_appengine.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/terminal_appengine.go b/terminal_appengine.go index 2f34402..72f679c 100644 --- a/terminal_appengine.go +++ b/terminal_appengine.go @@ -1,5 +1,5 @@ // Based on ssh/terminal: -// Copyright 2013 The Go Authors. All rights reserved. +// Copyright 2018 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -7,5 +7,7 @@ package logrus +import "io" + func initTerminal(w io.Writer) { } From 0a8fc8d77cebf6bb58f90fe8a934a3b516b9e5bd Mon Sep 17 00:00:00 2001 From: Mark Dittmer Date: Mon, 17 Sep 2018 13:56:18 -0400 Subject: [PATCH 73/92] Add AppEngine test configurations to travis to a void regression --- .travis.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/.travis.yml b/.travis.yml index dd1218c..1f953be 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,3 +26,26 @@ matrix: - go get golang.org/x/sys/windows script: - go test -race -v ./... + - go: 1.10.x + install: + - go get github.com/stretchr/testify/assert + - go get golang.org/x/crypto/ssh/terminal + - go get golang.org/x/sys/unix + - go get golang.org/x/sys/windows + script: + - go test -race -v -tags appengine ./... + - go: 1.11.x + env: GO111MODULE=on + install: + - go mod download + script: + - go test -race -v -tags appengine ./... + - go: 1.11.x + env: GO111MODULE=off + install: + - go get github.com/stretchr/testify/assert + - go get golang.org/x/crypto/ssh/terminal + - go get golang.org/x/sys/unix + - go get golang.org/x/sys/windows + script: + - go test -race -v -tags appengine ./... From 629982b4957da4679c12227a2b3d09dd42f659d2 Mon Sep 17 00:00:00 2001 From: Mark Dittmer Date: Tue, 18 Sep 2018 13:54:23 -0400 Subject: [PATCH 74/92] DisableColors in two tests to fix AppEngine configuration --- example_basic_test.go | 4 +++- example_hook_test.go | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/example_basic_test.go b/example_basic_test.go index a2acf55..5f3849b 100644 --- a/example_basic_test.go +++ b/example_basic_test.go @@ -1,14 +1,16 @@ package logrus_test import ( - "github.com/sirupsen/logrus" "os" + + "github.com/sirupsen/logrus" ) func Example_basic() { var log = logrus.New() log.Formatter = new(logrus.JSONFormatter) log.Formatter = new(logrus.TextFormatter) //default + log.Formatter.(*logrus.TextFormatter).DisableColors = true // remove colors log.Formatter.(*logrus.TextFormatter).DisableTimestamp = true // remove timestamp from test output log.Level = logrus.DebugLevel log.Out = os.Stdout diff --git a/example_hook_test.go b/example_hook_test.go index 28bd8ea..15118d2 100644 --- a/example_hook_test.go +++ b/example_hook_test.go @@ -3,16 +3,18 @@ package logrus_test import ( - "github.com/sirupsen/logrus" - slhooks "github.com/sirupsen/logrus/hooks/syslog" "log/syslog" "os" + + "github.com/sirupsen/logrus" + slhooks "github.com/sirupsen/logrus/hooks/syslog" ) // An example on how to use a hook func Example_hook() { var log = logrus.New() log.Formatter = new(logrus.TextFormatter) // default + log.Formatter.(*logrus.TextFormatter).DisableColors = true // remove colors log.Formatter.(*logrus.TextFormatter).DisableTimestamp = true // remove timestamp from test output if sl, err := slhooks.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, ""); err != nil { log.Hooks.Add(sl) From 5a88d3c21dcdb8a18079b3f7d6f4113bbc9044c8 Mon Sep 17 00:00:00 2001 From: David Bariod Date: Wed, 19 Sep 2018 13:46:16 +0200 Subject: [PATCH 75/92] Add missing module dependency for windows build --- go.mod | 1 + go.sum | 2 ++ hooks/syslog/syslog_test.go | 2 ++ 3 files changed, 5 insertions(+) diff --git a/go.mod b/go.mod index faee392..f4fed02 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,7 @@ module github.com/sirupsen/logrus require ( github.com/davecgh/go-spew v1.1.1 // indirect + github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/testify v1.2.2 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 diff --git a/go.sum b/go.sum index 7fd44a1..1f0d719 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe h1:CHRGQ8V7OlCYtwaKPJi3iA7J+YdNKdo8j7nG5IgDhjs= +github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= diff --git a/hooks/syslog/syslog_test.go b/hooks/syslog/syslog_test.go index 5ec3a44..bec6efd 100644 --- a/hooks/syslog/syslog_test.go +++ b/hooks/syslog/syslog_test.go @@ -1,3 +1,5 @@ +// +build !windows,!nacl,!plan9 + package syslog import ( From 73bc94e60c753099e8bae902f81fbd6e7dd95f26 Mon Sep 17 00:00:00 2001 From: David Bariod Date: Tue, 25 Sep 2018 13:45:23 +0200 Subject: [PATCH 76/92] Add custom sorting function in text formatter --- text_formatter.go | 52 ++++++++++++++++++++++++++++++++---------- text_formatter_test.go | 34 +++++++++++++++++++++++++-- 2 files changed, 72 insertions(+), 14 deletions(-) diff --git a/text_formatter.go b/text_formatter.go index 6aee14f..67fb686 100644 --- a/text_formatter.go +++ b/text_formatter.go @@ -55,6 +55,9 @@ type TextFormatter struct { // be desired. DisableSorting bool + // The keys sorting function, when uninitialized it uses sort.Strings. + SortingFunc func([]string) + // Disables the truncation of the level text to 4 characters. DisableLevelTruncation bool @@ -73,7 +76,7 @@ type TextFormatter struct { // FieldKeyMsg: "@message"}} FieldMap FieldMap - sync.Once + terminalInitOnce sync.Once } func (f *TextFormatter) init(entry *Entry) { @@ -111,8 +114,29 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { keys = append(keys, k) } + fixedKeys := make([]string, 0, 3+len(entry.Data)) + if !f.DisableTimestamp { + fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyTime)) + } + fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLevel)) + if entry.Message != "" { + fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyMsg)) + } + if !f.DisableSorting { - sort.Strings(keys) + if f.SortingFunc == nil { + sort.Strings(keys) + fixedKeys = append(fixedKeys, keys...) + } else { + if !f.isColored() { + fixedKeys = append(fixedKeys, keys...) + f.SortingFunc(fixedKeys) + } else { + f.SortingFunc(keys) + } + } + } else { + fixedKeys = append(fixedKeys, keys...) } var b *bytes.Buffer @@ -122,7 +146,7 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { b = &bytes.Buffer{} } - f.Do(func() { f.init(entry) }) + f.terminalInitOnce.Do(func() { f.init(entry) }) timestampFormat := f.TimestampFormat if timestampFormat == "" { @@ -131,15 +155,19 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { if f.isColored() { f.printColored(b, entry, keys, timestampFormat) } else { - if !f.DisableTimestamp { - f.appendKeyValue(b, f.FieldMap.resolve(FieldKeyTime), entry.Time.Format(timestampFormat)) - } - f.appendKeyValue(b, f.FieldMap.resolve(FieldKeyLevel), entry.Level.String()) - if entry.Message != "" { - f.appendKeyValue(b, f.FieldMap.resolve(FieldKeyMsg), entry.Message) - } - for _, key := range keys { - f.appendKeyValue(b, key, entry.Data[key]) + for _, key := range fixedKeys { + var value interface{} + switch key { + case f.FieldMap.resolve(FieldKeyTime): + value = entry.Time.Format(timestampFormat) + case f.FieldMap.resolve(FieldKeyLevel): + value = entry.Level.String() + case f.FieldMap.resolve(FieldKeyMsg): + value = entry.Message + default: + value = entry.Data[key] + } + f.appendKeyValue(b, key, value) } } diff --git a/text_formatter_test.go b/text_formatter_test.go index b57ef7c..b0d3a91 100644 --- a/text_formatter_test.go +++ b/text_formatter_test.go @@ -5,11 +5,13 @@ import ( "errors" "fmt" "os" + "sort" "strings" "testing" "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestFormatting(t *testing.T) { @@ -446,5 +448,33 @@ func TestTextFormatterIsColored(t *testing.T) { } } -// TODO add tests for sorting etc., this requires a parser for the text -// formatter output. +func TestCustomSorting(t *testing.T) { + formatter := &TextFormatter{ + DisableColors: true, + SortingFunc: func(keys []string) { + sort.Slice(keys, func(i, j int) bool { + if keys[j] == "prefix" { + return false + } + if keys[i] == "prefix" { + return true + } + return strings.Compare(keys[i], keys[j]) == -1 + }) + }, + } + + entry := &Entry{ + Message: "Testing custom sort function", + Time: time.Now(), + Level: InfoLevel, + Data: Fields{ + "test": "testvalue", + "prefix": "the application prefix", + "blablabla": "blablabla", + }, + } + b, err := formatter.Format(entry) + require.NoError(t, err) + require.True(t, strings.HasPrefix(string(b), "prefix="), "format output is %q", string(b)) +} From a67f783a3814b8729bd2dac5780b5f78f8dbd64d Mon Sep 17 00:00:00 2001 From: David Bariod Date: Tue, 25 Sep 2018 21:35:18 +0200 Subject: [PATCH 77/92] Update changelog for v1.1.0 release --- CHANGELOG.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff40b2a..1702696 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ +# 1.1.0 +This new release introduces: + * several fixes: + * a fix for a race condition on entry formatting + * proper cleanup of previously used entries before putting them back in the pool + * the extra new line at the end of message in text formatter has been removed + * a new global public API to check if a level is activated: IsLevelEnabled + * the following methods have been added to the Logger object + * IsLevelEnabled + * SetFormatter + * SetOutput + * ReplaceHooks + * introduction of go module + * an indent configuration for the json formatter + * output colour support for windows + * the field sort function is now configurable for text formatter + * the CLICOLOR and CLICOLOR\_FORCE environment variable support in text formater + # 1.0.6 This new release introduces: From 7b467df6975c8092bbc1aea2184c13ee73b8ee8a Mon Sep 17 00:00:00 2001 From: David Bariod Date: Sun, 30 Sep 2018 22:51:02 +0200 Subject: [PATCH 78/92] Skip func type value in fields. We skip those unprintable fields and an error field instead of dropping the whole trace. Fixes #642 --- entry.go | 16 ++++++++++++++-- formatter.go | 15 ++++++++++++++- json_formatter.go | 10 +++------- logger_test.go | 42 ++++++++++++++++++++++++++++++++++++++++++ text_formatter.go | 7 ++++++- 5 files changed, 79 insertions(+), 11 deletions(-) create mode 100644 logger_test.go diff --git a/entry.go b/entry.go index 4efeddd..ca634a6 100644 --- a/entry.go +++ b/entry.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "os" + "reflect" "sync" "time" ) @@ -43,6 +44,9 @@ type Entry struct { // When formatter is called in entry.log(), a Buffer may be set to entry Buffer *bytes.Buffer + + // err may contain a field formatting error + err string } func NewEntry(logger *Logger) *Entry { @@ -80,10 +84,18 @@ func (entry *Entry) WithFields(fields Fields) *Entry { for k, v := range entry.Data { data[k] = v } + var field_err string for k, v := range fields { - data[k] = v + if t := reflect.TypeOf(v); t != nil && t.Kind() == reflect.Func { + field_err = fmt.Sprintf("can not add field %q", k) + if entry.err != "" { + field_err = entry.err + ", " + field_err + } + } else { + data[k] = v + } } - return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time} + return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, err: field_err} } // Overrides the time of the Entry. diff --git a/formatter.go b/formatter.go index 83c7494..be2f3fc 100644 --- a/formatter.go +++ b/formatter.go @@ -2,7 +2,14 @@ package logrus import "time" -const defaultTimestampFormat = time.RFC3339 +// Default key names for the default fields +const ( + defaultTimestampFormat = time.RFC3339 + FieldKeyMsg = "msg" + FieldKeyLevel = "level" + FieldKeyTime = "time" + FieldKeyLogrusError = "logrus_error" +) // The Formatter interface is used to implement a custom Formatter. It takes an // `Entry`. It exposes all the fields, including the default ones: @@ -48,4 +55,10 @@ func prefixFieldClashes(data Fields, fieldMap FieldMap) { data["fields."+levelKey] = l delete(data, levelKey) } + + logrusErrKey := fieldMap.resolve(FieldKeyLogrusError) + if l, ok := data[logrusErrKey]; ok { + data["fields."+logrusErrKey] = l + delete(data, logrusErrKey) + } } diff --git a/json_formatter.go b/json_formatter.go index d3dadef..ef8d074 100644 --- a/json_formatter.go +++ b/json_formatter.go @@ -11,13 +11,6 @@ type fieldKey string // FieldMap allows customization of the key names for default fields. type FieldMap map[fieldKey]string -// Default key names for the default fields -const ( - FieldKeyMsg = "msg" - FieldKeyLevel = "level" - FieldKeyTime = "time" -) - func (f FieldMap) resolve(key fieldKey) string { if k, ok := f[key]; ok { return k @@ -79,6 +72,9 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { timestampFormat = defaultTimestampFormat } + if entry.err != "" { + data[f.FieldMap.resolve(FieldKeyLogrusError)] = entry.err + } if !f.DisableTimestamp { data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat) } diff --git a/logger_test.go b/logger_test.go new file mode 100644 index 0000000..73ba450 --- /dev/null +++ b/logger_test.go @@ -0,0 +1,42 @@ +package logrus + +import ( + "bytes" + "encoding/json" + "fmt" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestFieldValueError(t *testing.T) { + buf := &bytes.Buffer{} + l := &Logger{ + Out: buf, + Formatter: new(JSONFormatter), + Hooks: make(LevelHooks), + Level: DebugLevel, + } + l.WithField("func", func() {}).Info("test") + fmt.Println(buf.String()) + var data map[string]interface{} + json.Unmarshal(buf.Bytes(), &data) + _, ok := data[FieldKeyLogrusError] + require.True(t, ok) +} + +func TestNoFieldValueError(t *testing.T) { + buf := &bytes.Buffer{} + l := &Logger{ + Out: buf, + Formatter: new(JSONFormatter), + Hooks: make(LevelHooks), + Level: DebugLevel, + } + l.WithField("str", "str").Info("test") + fmt.Println(buf.String()) + var data map[string]interface{} + json.Unmarshal(buf.Bytes(), &data) + _, ok := data[FieldKeyLogrusError] + require.False(t, ok) +} diff --git a/text_formatter.go b/text_formatter.go index 67fb686..d4663b8 100644 --- a/text_formatter.go +++ b/text_formatter.go @@ -114,7 +114,7 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { keys = append(keys, k) } - fixedKeys := make([]string, 0, 3+len(entry.Data)) + fixedKeys := make([]string, 0, 4+len(entry.Data)) if !f.DisableTimestamp { fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyTime)) } @@ -122,6 +122,9 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { if entry.Message != "" { fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyMsg)) } + if entry.err != "" { + fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLogrusError)) + } if !f.DisableSorting { if f.SortingFunc == nil { @@ -164,6 +167,8 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { value = entry.Level.String() case f.FieldMap.resolve(FieldKeyMsg): value = entry.Message + case f.FieldMap.resolve(FieldKeyLogrusError): + value = entry.err default: value = entry.Data[key] } From 2be620216affd84620a08ee082d6e074d1bb5ca4 Mon Sep 17 00:00:00 2001 From: Albert Salim Date: Sat, 6 Oct 2018 18:08:19 +0800 Subject: [PATCH 79/92] Add option to panic in `test.NewNullLogger` to allow testing of calls to `Fatal*` See #813 --- alt_exit.go | 2 ++ entry.go | 6 +++--- hooks/test/test.go | 14 +++++++++++++- hooks/test/test_test.go | 11 +++++++++++ logger.go | 9 ++++++--- 5 files changed, 35 insertions(+), 7 deletions(-) diff --git a/alt_exit.go b/alt_exit.go index 8af9063..f1bb44c 100644 --- a/alt_exit.go +++ b/alt_exit.go @@ -45,6 +45,8 @@ func runHandlers() { } } +type exitFunc func(int) + // Exit runs all the Logrus atexit handlers and then terminates the program using os.Exit(code) func Exit(code int) { runHandlers() diff --git a/entry.go b/entry.go index ca634a6..225bdb6 100644 --- a/entry.go +++ b/entry.go @@ -198,7 +198,7 @@ func (entry *Entry) Fatal(args ...interface{}) { if entry.Logger.IsLevelEnabled(FatalLevel) { entry.log(FatalLevel, fmt.Sprint(args...)) } - Exit(1) + entry.Logger.Exit(1) } func (entry *Entry) Panic(args ...interface{}) { @@ -246,7 +246,7 @@ func (entry *Entry) Fatalf(format string, args ...interface{}) { if entry.Logger.IsLevelEnabled(FatalLevel) { entry.Fatal(fmt.Sprintf(format, args...)) } - Exit(1) + entry.Logger.Exit(1) } func (entry *Entry) Panicf(format string, args ...interface{}) { @@ -293,7 +293,7 @@ func (entry *Entry) Fatalln(args ...interface{}) { if entry.Logger.IsLevelEnabled(FatalLevel) { entry.Fatal(entry.sprintlnn(args...)) } - Exit(1) + entry.Logger.Exit(1) } func (entry *Entry) Panicln(args ...interface{}) { diff --git a/hooks/test/test.go b/hooks/test/test.go index 234a17d..f84fe80 100644 --- a/hooks/test/test.go +++ b/hooks/test/test.go @@ -39,12 +39,24 @@ func NewLocal(logger *logrus.Logger) *Hook { } +type TestOption func(logger *logrus.Logger) + +func FatalPanics(logger *logrus.Logger) { + logger.Exit = func(code int) { + panic(code) + } +} + // NewNullLogger creates a discarding logger and installs the test hook. -func NewNullLogger() (*logrus.Logger, *Hook) { +func NewNullLogger(options ...TestOption) (*logrus.Logger, *Hook) { logger := logrus.New() logger.Out = ioutil.Discard + for _, option := range options { + option(logger) + } + return logger, NewLocal(logger) } diff --git a/hooks/test/test_test.go b/hooks/test/test_test.go index d6f6d30..692d36a 100644 --- a/hooks/test/test_test.go +++ b/hooks/test/test_test.go @@ -71,3 +71,14 @@ func TestLoggingWithHooksRace(t *testing.T) { entries := hook.AllEntries() assert.Equal(100, len(entries)) } + +func TestFatalWithPanic(t *testing.T) { + assert := assert.New(t) + + logger, hook := NewNullLogger(FatalPanics) + + assert.Nil(hook.LastEntry()) + assert.Equal(0, len(hook.Entries)) + + assert.Panics(func() { logger.Fatal("something went wrong") }) +} diff --git a/logger.go b/logger.go index b67bfcb..188c600 100644 --- a/logger.go +++ b/logger.go @@ -32,6 +32,8 @@ type Logger struct { mu MutexWrap // Reusable empty entry entryPool sync.Pool + // Function to exit the application, defaults to `Exit()` + Exit exitFunc } type MutexWrap struct { @@ -73,6 +75,7 @@ func New() *Logger { Formatter: new(TextFormatter), Hooks: make(LevelHooks), Level: InfoLevel, + Exit: Exit, } } @@ -173,7 +176,7 @@ func (logger *Logger) Fatalf(format string, args ...interface{}) { entry.Fatalf(format, args...) logger.releaseEntry(entry) } - Exit(1) + logger.Exit(1) } func (logger *Logger) Panicf(format string, args ...interface{}) { @@ -236,7 +239,7 @@ func (logger *Logger) Fatal(args ...interface{}) { entry.Fatal(args...) logger.releaseEntry(entry) } - Exit(1) + logger.Exit(1) } func (logger *Logger) Panic(args ...interface{}) { @@ -299,7 +302,7 @@ func (logger *Logger) Fatalln(args ...interface{}) { entry.Fatalln(args...) logger.releaseEntry(entry) } - Exit(1) + logger.Exit(1) } func (logger *Logger) Panicln(args ...interface{}) { From 3f90cee1e41a38ba27c831844c002952512997c0 Mon Sep 17 00:00:00 2001 From: David Bariod Date: Sat, 6 Oct 2018 15:21:56 +0200 Subject: [PATCH 80/92] Rationalize os specific build constraints --- terminal_appengine.go | 13 ------------- terminal_bsd.go | 17 ----------------- terminal_linux.go | 21 --------------------- terminal_notwindows.go | 8 ++++++++ 4 files changed, 8 insertions(+), 51 deletions(-) delete mode 100644 terminal_appengine.go delete mode 100644 terminal_bsd.go delete mode 100644 terminal_linux.go create mode 100644 terminal_notwindows.go diff --git a/terminal_appengine.go b/terminal_appengine.go deleted file mode 100644 index 72f679c..0000000 --- a/terminal_appengine.go +++ /dev/null @@ -1,13 +0,0 @@ -// Based on ssh/terminal: -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build appengine - -package logrus - -import "io" - -func initTerminal(w io.Writer) { -} diff --git a/terminal_bsd.go b/terminal_bsd.go deleted file mode 100644 index 62ca252..0000000 --- a/terminal_bsd.go +++ /dev/null @@ -1,17 +0,0 @@ -// +build darwin freebsd openbsd netbsd dragonfly -// +build !appengine,!js - -package logrus - -import ( - "io" - - "golang.org/x/sys/unix" -) - -const ioctlReadTermios = unix.TIOCGETA - -type Termios unix.Termios - -func initTerminal(w io.Writer) { -} diff --git a/terminal_linux.go b/terminal_linux.go deleted file mode 100644 index 18066f0..0000000 --- a/terminal_linux.go +++ /dev/null @@ -1,21 +0,0 @@ -// Based on ssh/terminal: -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !appengine,!js - -package logrus - -import ( - "io" - - "golang.org/x/sys/unix" -) - -const ioctlReadTermios = unix.TCGETS - -type Termios unix.Termios - -func initTerminal(w io.Writer) { -} diff --git a/terminal_notwindows.go b/terminal_notwindows.go new file mode 100644 index 0000000..3dbd237 --- /dev/null +++ b/terminal_notwindows.go @@ -0,0 +1,8 @@ +// +build !windows + +package logrus + +import "io" + +func initTerminal(w io.Writer) { +} From ad15b42461921f1fb3529b058c6786c6a45d5162 Mon Sep 17 00:00:00 2001 From: David Bariod Date: Mon, 8 Oct 2018 22:30:39 +0200 Subject: [PATCH 81/92] Update changelog for v1.1.1 release --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1702696..ff04718 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# 1.1.1 +This is a bug fix release. + * fix the build break on Solaris + * don't drop a whole trace in JSONFormatter when a field param is a function pointer which can not be serialized + # 1.1.0 This new release introduces: * several fixes: From 99bc300c8d60c2f531a4690533f63273e4fbaaf7 Mon Sep 17 00:00:00 2001 From: Albert Salim Date: Wed, 10 Oct 2018 21:54:15 +0800 Subject: [PATCH 82/92] Add a method Exit on Logger that calls `os.Exit` or alternate exit function. This keeps backward compatibility for static declaration of logger that does not specify `ExitFunc` field. --- alt_exit.go | 8 ++++++-- hooks/test/test.go | 14 +------------- hooks/test/test_test.go | 13 +++++++------ logger.go | 14 +++++++++++--- logrus.go | 2 +- 5 files changed, 26 insertions(+), 25 deletions(-) diff --git a/alt_exit.go b/alt_exit.go index f1bb44c..183db77 100644 --- a/alt_exit.go +++ b/alt_exit.go @@ -45,11 +45,15 @@ func runHandlers() { } } -type exitFunc func(int) - // Exit runs all the Logrus atexit handlers and then terminates the program using os.Exit(code) func Exit(code int) { runHandlers() + osExit(code) +} + +type exitFunc func(int) + +func osExit(code int) { os.Exit(code) } diff --git a/hooks/test/test.go b/hooks/test/test.go index f84fe80..234a17d 100644 --- a/hooks/test/test.go +++ b/hooks/test/test.go @@ -39,24 +39,12 @@ func NewLocal(logger *logrus.Logger) *Hook { } -type TestOption func(logger *logrus.Logger) - -func FatalPanics(logger *logrus.Logger) { - logger.Exit = func(code int) { - panic(code) - } -} - // NewNullLogger creates a discarding logger and installs the test hook. -func NewNullLogger(options ...TestOption) (*logrus.Logger, *Hook) { +func NewNullLogger() (*logrus.Logger, *Hook) { logger := logrus.New() logger.Out = ioutil.Discard - for _, option := range options { - option(logger) - } - return logger, NewLocal(logger) } diff --git a/hooks/test/test_test.go b/hooks/test/test_test.go index 692d36a..636bad5 100644 --- a/hooks/test/test_test.go +++ b/hooks/test/test_test.go @@ -72,13 +72,14 @@ func TestLoggingWithHooksRace(t *testing.T) { assert.Equal(100, len(entries)) } -func TestFatalWithPanic(t *testing.T) { +func TestFatalWithAlternateExit(t *testing.T) { assert := assert.New(t) - logger, hook := NewNullLogger(FatalPanics) + logger, hook := NewNullLogger() + logger.ExitFunc = func(code int) {} - assert.Nil(hook.LastEntry()) - assert.Equal(0, len(hook.Entries)) - - assert.Panics(func() { logger.Fatal("something went wrong") }) + logger.Fatal("something went very wrong") + assert.Equal(logrus.FatalLevel, hook.LastEntry().Level) + assert.Equal("something went very wrong", hook.LastEntry().Message) + assert.Equal(1, len(hook.Entries)) } diff --git a/logger.go b/logger.go index 188c600..364819e 100644 --- a/logger.go +++ b/logger.go @@ -32,8 +32,8 @@ type Logger struct { mu MutexWrap // Reusable empty entry entryPool sync.Pool - // Function to exit the application, defaults to `Exit()` - Exit exitFunc + // Function to exit the application, defaults to `osExit()` + ExitFunc exitFunc } type MutexWrap struct { @@ -75,7 +75,7 @@ func New() *Logger { Formatter: new(TextFormatter), Hooks: make(LevelHooks), Level: InfoLevel, - Exit: Exit, + ExitFunc: osExit, } } @@ -313,6 +313,14 @@ func (logger *Logger) Panicln(args ...interface{}) { } } +func (logger *Logger) Exit(code int) { + runHandlers() + if logger.ExitFunc == nil { + logger.ExitFunc = osExit + } + logger.ExitFunc(code) +} + //When file is opened with appending mode, it's safe to //write concurrently to a file (within 4k message on Linux). //In these cases user can choose to disable the lock. diff --git a/logrus.go b/logrus.go index fa0b9de..6fff506 100644 --- a/logrus.go +++ b/logrus.go @@ -69,7 +69,7 @@ const ( // PanicLevel level, highest level of severity. Logs and then calls panic with the // message passed to Debug, Info, ... PanicLevel Level = iota - // FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the + // FatalLevel level. Logs and then calls `logger.Exit(1)`. It will exit even if the // logging level is set to Panic. FatalLevel // ErrorLevel level. Logs. Used for errors that should definitely be noted. From 4346c76f26ec031258a1d8f5f08cfb829f74611e Mon Sep 17 00:00:00 2001 From: Albert Salim Date: Wed, 10 Oct 2018 21:57:58 +0800 Subject: [PATCH 83/92] Remove unnecessary wrapper function on `os.Exit` --- alt_exit.go | 6 ------ logger.go | 6 ++++-- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/alt_exit.go b/alt_exit.go index 183db77..8af9063 100644 --- a/alt_exit.go +++ b/alt_exit.go @@ -48,12 +48,6 @@ func runHandlers() { // Exit runs all the Logrus atexit handlers and then terminates the program using os.Exit(code) func Exit(code int) { runHandlers() - osExit(code) -} - -type exitFunc func(int) - -func osExit(code int) { os.Exit(code) } diff --git a/logger.go b/logger.go index 364819e..21f49ec 100644 --- a/logger.go +++ b/logger.go @@ -36,6 +36,8 @@ type Logger struct { ExitFunc exitFunc } +type exitFunc func(int) + type MutexWrap struct { lock sync.Mutex disabled bool @@ -75,7 +77,7 @@ func New() *Logger { Formatter: new(TextFormatter), Hooks: make(LevelHooks), Level: InfoLevel, - ExitFunc: osExit, + ExitFunc: os.Exit, } } @@ -316,7 +318,7 @@ func (logger *Logger) Panicln(args ...interface{}) { func (logger *Logger) Exit(code int) { runHandlers() if logger.ExitFunc == nil { - logger.ExitFunc = osExit + logger.ExitFunc = os.Exit } logger.ExitFunc(code) } From a13c5db57c07b6f81ed4ad333c219966151ec30a Mon Sep 17 00:00:00 2001 From: Albert Salim Date: Wed, 10 Oct 2018 21:59:03 +0800 Subject: [PATCH 84/92] Fix typo in comment --- logger.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logger.go b/logger.go index 21f49ec..1c934ed 100644 --- a/logger.go +++ b/logger.go @@ -32,7 +32,7 @@ type Logger struct { mu MutexWrap // Reusable empty entry entryPool sync.Pool - // Function to exit the application, defaults to `osExit()` + // Function to exit the application, defaults to `os.Exit()` ExitFunc exitFunc } From f2ab87f230e2c652a48c789c24add4e17dce84e9 Mon Sep 17 00:00:00 2001 From: David Bariod Date: Mon, 15 Oct 2018 21:20:03 +0200 Subject: [PATCH 85/92] Add an example for tracing global variable with hook --- example_global_hook_test.go | 37 +++++++++++++++++++++++++++++++++++++ go.mod | 1 + go.sum | 2 ++ 3 files changed, 40 insertions(+) create mode 100644 example_global_hook_test.go diff --git a/example_global_hook_test.go b/example_global_hook_test.go new file mode 100644 index 0000000..df1584c --- /dev/null +++ b/example_global_hook_test.go @@ -0,0 +1,37 @@ +package logrus_test + +import ( + "github.com/sirupsen/logrus" + "os" +) + +var ( + mystring string +) + +type GlobalHook struct { +} + +func (h *GlobalHook) Levels() []logrus.Level { + return logrus.AllLevels +} + +func (h *GlobalHook) Fire(e *logrus.Entry) error { + e.Data["mystring"] = mystring + return nil +} + +func Example() { + l := logrus.New() + l.Out = os.Stdout + l.Formatter = &logrus.TextFormatter{DisableTimestamp: true} + l.Formatter.(*logrus.TextFormatter).DisableTimestamp = true + l.AddHook(&GlobalHook{}) + mystring = "first value" + l.Info("first log") + mystring = "another value" + l.Info("second log") + // Output: + // level=info msg="first log" mystring="first value" + // level=info msg="second log" mystring="another value" +} diff --git a/go.mod b/go.mod index f4fed02..79f11b7 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/stretchr/objx v0.1.1 // indirect github.com/stretchr/testify v1.2.2 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 diff --git a/go.sum b/go.sum index 1f0d719..16cab75 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f26 github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I= From 9c7692ccff2dca67e6db9b6eaef21a2c37ad82e7 Mon Sep 17 00:00:00 2001 From: David Bariod Date: Mon, 15 Oct 2018 21:32:20 +0200 Subject: [PATCH 86/92] disable colors on hook example --- example_global_hook_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/example_global_hook_test.go b/example_global_hook_test.go index df1584c..c81e448 100644 --- a/example_global_hook_test.go +++ b/example_global_hook_test.go @@ -24,8 +24,7 @@ func (h *GlobalHook) Fire(e *logrus.Entry) error { func Example() { l := logrus.New() l.Out = os.Stdout - l.Formatter = &logrus.TextFormatter{DisableTimestamp: true} - l.Formatter.(*logrus.TextFormatter).DisableTimestamp = true + l.Formatter = &logrus.TextFormatter{DisableTimestamp: true, DisableColors: true} l.AddHook(&GlobalHook{}) mystring = "first value" l.Info("first log") From 4981d8161c238636b2ca8cf6b4e0d717716452ee Mon Sep 17 00:00:00 2001 From: drampull Date: Fri, 20 Oct 2017 08:40:54 -0400 Subject: [PATCH 87/92] Added TRACE level logging. --- .gitignore | 1 + entry.go | 18 ++++++++++++++++++ example_basic_test.go | 8 +++++++- exported.go | 15 +++++++++++++++ hook_test.go | 2 ++ hooks/syslog/syslog.go | 2 +- logger.go | 24 ++++++++++++++++++++++++ logrus.go | 10 ++++++++++ text_formatter.go | 2 +- writer.go | 2 ++ 10 files changed, 81 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 66be63a..6b7d7d1 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ logrus +vendor diff --git a/entry.go b/entry.go index 225bdb6..eb4ae5c 100644 --- a/entry.go +++ b/entry.go @@ -168,6 +168,12 @@ func (entry *Entry) Debug(args ...interface{}) { } } +func (entry *Entry) Trace(args ...interface{}) { + if entry.Logger.IsLevelEnabled(TraceLevel) { + entry.log(TraceLevel, fmt.Sprint(args...)) + } +} + func (entry *Entry) Print(args ...interface{}) { entry.Info(args...) } @@ -216,6 +222,12 @@ func (entry *Entry) Debugf(format string, args ...interface{}) { } } +func (entry *Entry) Tracef(format string, args ...interface{}) { + if entry.Logger.IsLevelEnabled(TraceLevel) { + entry.Trace(fmt.Sprintf(format, args...)) + } +} + func (entry *Entry) Infof(format string, args ...interface{}) { if entry.Logger.IsLevelEnabled(InfoLevel) { entry.Info(fmt.Sprintf(format, args...)) @@ -257,6 +269,12 @@ func (entry *Entry) Panicf(format string, args ...interface{}) { // Entry Println family functions +func (entry *Entry) Traceln(args ...interface{}) { + if entry.Logger.IsLevelEnabled(TraceLevel) { + entry.Trace(entry.sprintlnn(args...)) + } +} + func (entry *Entry) Debugln(args ...interface{}) { if entry.Logger.IsLevelEnabled(DebugLevel) { entry.Debug(entry.sprintlnn(args...)) diff --git a/example_basic_test.go b/example_basic_test.go index 5f3849b..9ff5655 100644 --- a/example_basic_test.go +++ b/example_basic_test.go @@ -12,7 +12,7 @@ func Example_basic() { log.Formatter = new(logrus.TextFormatter) //default log.Formatter.(*logrus.TextFormatter).DisableColors = true // remove colors log.Formatter.(*logrus.TextFormatter).DisableTimestamp = true // remove timestamp from test output - log.Level = logrus.DebugLevel + log.Level = logrus.TraceLevel log.Out = os.Stdout // file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY, 0666) @@ -37,6 +37,11 @@ func Example_basic() { } }() + log.WithFields(logrus.Fields{ + "animal": "walrus", + "number": 0, + }).Trace("Went to the beach") + log.WithFields(logrus.Fields{ "animal": "walrus", "number": 8, @@ -62,6 +67,7 @@ func Example_basic() { }).Panic("It's over 9000!") // Output: + // level=trace msg="Went to the beach" animal=walrus number=0 // level=debug msg="Started observing beach" animal=walrus number=8 // level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10 // level=warning msg="The group's number increased tremendously!" number=122 omg=true diff --git a/exported.go b/exported.go index fb2a7a1..fb261aa 100644 --- a/exported.go +++ b/exported.go @@ -77,6 +77,11 @@ func WithTime(t time.Time) *Entry { return std.WithTime(t) } +// Trace logs a message at level Trace on the standard logger. +func Trace(args ...interface{}) { + std.Trace(args...) +} + // Debug logs a message at level Debug on the standard logger. func Debug(args ...interface{}) { std.Debug(args...) @@ -117,6 +122,11 @@ func Fatal(args ...interface{}) { std.Fatal(args...) } +// Tracef logs a message at level Debug on the standard logger. +func Tracef(format string, args ...interface{}) { + std.Tracef(format, args...) +} + // Debugf logs a message at level Debug on the standard logger. func Debugf(format string, args ...interface{}) { std.Debugf(format, args...) @@ -157,6 +167,11 @@ func Fatalf(format string, args ...interface{}) { std.Fatalf(format, args...) } +// Traceln logs a message at level Debug on the standard logger. +func Traceln(args ...interface{}) { + std.Traceln(args...) +} + // Debugln logs a message at level Debug on the standard logger. func Debugln(args ...interface{}) { std.Debugln(args...) diff --git a/hook_test.go b/hook_test.go index 80b93b8..7196e99 100644 --- a/hook_test.go +++ b/hook_test.go @@ -21,6 +21,7 @@ func (hook *TestHook) Fire(entry *Entry) error { func (hook *TestHook) Levels() []Level { return []Level{ + TraceLevel, DebugLevel, InfoLevel, WarnLevel, @@ -53,6 +54,7 @@ func (hook *ModifyHook) Fire(entry *Entry) error { func (hook *ModifyHook) Levels() []Level { return []Level{ + TraceLevel, DebugLevel, InfoLevel, WarnLevel, diff --git a/hooks/syslog/syslog.go b/hooks/syslog/syslog.go index 329ce0d..02b8df3 100644 --- a/hooks/syslog/syslog.go +++ b/hooks/syslog/syslog.go @@ -43,7 +43,7 @@ func (hook *SyslogHook) Fire(entry *logrus.Entry) error { return hook.Writer.Warning(line) case logrus.InfoLevel: return hook.Writer.Info(line) - case logrus.DebugLevel: + case logrus.DebugLevel, logrus.TraceLevel: return hook.Writer.Debug(line) default: return nil diff --git a/logger.go b/logger.go index 1c934ed..52f1761 100644 --- a/logger.go +++ b/logger.go @@ -126,6 +126,14 @@ func (logger *Logger) WithTime(t time.Time) *Entry { return entry.WithTime(t) } +func (logger *Logger) Tracef(format string, args ...interface{}) { + if logger.IsLevelEnabled(TraceLevel) { + entry := logger.newEntry() + entry.Tracef(format, args...) + logger.releaseEntry(entry) + } +} + func (logger *Logger) Debugf(format string, args ...interface{}) { if logger.IsLevelEnabled(DebugLevel) { entry := logger.newEntry() @@ -189,6 +197,14 @@ func (logger *Logger) Panicf(format string, args ...interface{}) { } } +func (logger *Logger) Trace(args ...interface{}) { + if logger.IsLevelEnabled(TraceLevel) { + entry := logger.newEntry() + entry.Trace(args...) + logger.releaseEntry(entry) + } +} + func (logger *Logger) Debug(args ...interface{}) { if logger.IsLevelEnabled(DebugLevel) { entry := logger.newEntry() @@ -252,6 +268,14 @@ func (logger *Logger) Panic(args ...interface{}) { } } +func (logger *Logger) Traceln(args ...interface{}) { + if logger.IsLevelEnabled(TraceLevel) { + entry := logger.newEntry() + entry.Traceln(args...) + logger.releaseEntry(entry) + } +} + func (logger *Logger) Debugln(args ...interface{}) { if logger.IsLevelEnabled(DebugLevel) { entry := logger.newEntry() diff --git a/logrus.go b/logrus.go index 6fff506..601d5e0 100644 --- a/logrus.go +++ b/logrus.go @@ -15,6 +15,8 @@ type Level uint32 // Convert the Level to a string. E.g. PanicLevel becomes "panic". func (level Level) String() string { switch level { + case TraceLevel: + return "trace" case DebugLevel: return "debug" case InfoLevel: @@ -47,6 +49,8 @@ func ParseLevel(lvl string) (Level, error) { return InfoLevel, nil case "debug": return DebugLevel, nil + case "trace": + return TraceLevel, nil } var l Level @@ -61,6 +65,7 @@ var AllLevels = []Level{ WarnLevel, InfoLevel, DebugLevel, + TraceLevel, } // These are the different logging levels. You can set the logging level to log @@ -82,6 +87,8 @@ const ( InfoLevel // DebugLevel level. Usually only enabled when debugging. Very verbose logging. DebugLevel + // TraceLevel level. Usually only enabled when debugging. Very verbose logging. Usually reserved for message traces + TraceLevel ) // Won't compile if StdLogger can't be realized by a log.Logger @@ -114,6 +121,7 @@ type FieldLogger interface { WithFields(fields Fields) *Entry WithError(err error) *Entry + Tracef(format string, args ...interface{}) Debugf(format string, args ...interface{}) Infof(format string, args ...interface{}) Printf(format string, args ...interface{}) @@ -123,6 +131,7 @@ type FieldLogger interface { Fatalf(format string, args ...interface{}) Panicf(format string, args ...interface{}) + Trace(args ...interface{}) Debug(args ...interface{}) Info(args ...interface{}) Print(args ...interface{}) @@ -132,6 +141,7 @@ type FieldLogger interface { Fatal(args ...interface{}) Panic(args ...interface{}) + Traceln(args ...interface{}) Debugln(args ...interface{}) Infoln(args ...interface{}) Println(args ...interface{}) diff --git a/text_formatter.go b/text_formatter.go index d4663b8..74dffcf 100644 --- a/text_formatter.go +++ b/text_formatter.go @@ -183,7 +183,7 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, timestampFormat string) { var levelColor int switch entry.Level { - case DebugLevel: + case DebugLevel, TraceLevel: levelColor = gray case WarnLevel: levelColor = yellow diff --git a/writer.go b/writer.go index 7bdebed..9e1f751 100644 --- a/writer.go +++ b/writer.go @@ -24,6 +24,8 @@ func (entry *Entry) WriterLevel(level Level) *io.PipeWriter { var printFunc func(args ...interface{}) switch level { + case TraceLevel: + printFunc = entry.Trace case DebugLevel: printFunc = entry.Debug case InfoLevel: From c7a33dc5de7efe87c53ee9598ab7b73a508f0be7 Mon Sep 17 00:00:00 2001 From: Giedrius Dubinskas Date: Mon, 2 Oct 2017 19:38:29 +0300 Subject: [PATCH 88/92] Add Trace level logging --- exported.go | 4 ++-- logrus.go | 3 ++- logrus_test.go | 9 +++++++++ 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/exported.go b/exported.go index fb261aa..b9f1c9d 100644 --- a/exported.go +++ b/exported.go @@ -122,7 +122,7 @@ func Fatal(args ...interface{}) { std.Fatal(args...) } -// Tracef logs a message at level Debug on the standard logger. +// Tracef logs a message at level Trace on the standard logger. func Tracef(format string, args ...interface{}) { std.Tracef(format, args...) } @@ -167,7 +167,7 @@ func Fatalf(format string, args ...interface{}) { std.Fatalf(format, args...) } -// Traceln logs a message at level Debug on the standard logger. +// Traceln logs a message at level Trace on the standard logger. func Traceln(args ...interface{}) { std.Traceln(args...) } diff --git a/logrus.go b/logrus.go index 601d5e0..d657c41 100644 --- a/logrus.go +++ b/logrus.go @@ -87,7 +87,8 @@ const ( InfoLevel // DebugLevel level. Usually only enabled when debugging. Very verbose logging. DebugLevel - // TraceLevel level. Usually only enabled when debugging. Very verbose logging. Usually reserved for message traces + // TraceLevel level. Usually only enabled when debugging. Very verbose logging. + // Usually reserved for message traces. TraceLevel ) diff --git a/logrus_test.go b/logrus_test.go index 97d15d7..210feef 100644 --- a/logrus_test.go +++ b/logrus_test.go @@ -303,6 +303,7 @@ func TestDoubleLoggingDoesntPrefixPreviousFields(t *testing.T) { } func TestConvertLevelToString(t *testing.T) { + assert.Equal(t, "trace", TraceLevel.String()) assert.Equal(t, "debug", DebugLevel.String()) assert.Equal(t, "info", InfoLevel.String()) assert.Equal(t, "warning", WarnLevel.String()) @@ -368,6 +369,14 @@ func TestParseLevel(t *testing.T) { assert.Nil(t, err) assert.Equal(t, DebugLevel, l) + l, err = ParseLevel("trace") + assert.Nil(t, err) + assert.Equal(t, TraceLevel, l) + + l, err = ParseLevel("TRACE") + assert.Nil(t, err) + assert.Equal(t, TraceLevel, l) + l, err = ParseLevel("invalid") assert.Equal(t, "not a valid logrus Level: \"invalid\"", err.Error()) } From ef9d84e9b3d46ec3b1520d235295a78c586bdc11 Mon Sep 17 00:00:00 2001 From: Maxim Korolyov Date: Tue, 28 Aug 2018 18:13:29 +0300 Subject: [PATCH 89/92] Added trace log level. --- README.md | 3 ++- entry.go | 34 +++++++++++++++++----------------- logrus.go | 3 +-- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 072e99b..f088432 100644 --- a/README.md +++ b/README.md @@ -246,9 +246,10 @@ A list of currently known of service hook can be found in this wiki [page](https #### Level logging -Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic. +Logrus has seven logging levels: Trace, Debug, Info, Warning, Error, Fatal and Panic. ```go +log.Trace("Something very low level.") log.Debug("Useful debugging information.") log.Info("Something noteworthy happened!") log.Warn("You should probably take a look at this.") diff --git a/entry.go b/entry.go index eb4ae5c..a76be76 100644 --- a/entry.go +++ b/entry.go @@ -23,9 +23,9 @@ func init() { var ErrorKey = "error" // 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. +// the fields passed with WithField{,s}. It's finally logged when Trace, 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. type Entry struct { Logger *Logger @@ -35,11 +35,11 @@ type Entry struct { // Time at which the log entry was created Time time.Time - // Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic + // Level the log entry was logged at: Trace, Debug, Info, Warn, Error, Fatal or Panic // This field will be set on entry firing and the value will be equal to the one in Logger struct field. Level Level - // Message passed to Debug, Info, Warn, Error, Fatal or Panic + // Message passed to Trace, Debug, Info, Warn, Error, Fatal or Panic Message string // When formatter is called in entry.log(), a Buffer may be set to entry @@ -162,18 +162,18 @@ func (entry *Entry) write() { } } -func (entry *Entry) Debug(args ...interface{}) { - if entry.Logger.IsLevelEnabled(DebugLevel) { - entry.log(DebugLevel, fmt.Sprint(args...)) - } -} - func (entry *Entry) Trace(args ...interface{}) { if entry.Logger.IsLevelEnabled(TraceLevel) { entry.log(TraceLevel, fmt.Sprint(args...)) } } +func (entry *Entry) Debug(args ...interface{}) { + if entry.Logger.IsLevelEnabled(DebugLevel) { + entry.log(DebugLevel, fmt.Sprint(args...)) + } +} + func (entry *Entry) Print(args ...interface{}) { entry.Info(args...) } @@ -216,18 +216,18 @@ func (entry *Entry) Panic(args ...interface{}) { // Entry Printf family functions -func (entry *Entry) Debugf(format string, args ...interface{}) { - if entry.Logger.IsLevelEnabled(DebugLevel) { - entry.Debug(fmt.Sprintf(format, args...)) - } -} - func (entry *Entry) Tracef(format string, args ...interface{}) { if entry.Logger.IsLevelEnabled(TraceLevel) { entry.Trace(fmt.Sprintf(format, args...)) } } +func (entry *Entry) Debugf(format string, args ...interface{}) { + if entry.Logger.IsLevelEnabled(DebugLevel) { + entry.Debug(fmt.Sprintf(format, args...)) + } +} + func (entry *Entry) Infof(format string, args ...interface{}) { if entry.Logger.IsLevelEnabled(InfoLevel) { entry.Info(fmt.Sprintf(format, args...)) diff --git a/logrus.go b/logrus.go index d657c41..8834b5b 100644 --- a/logrus.go +++ b/logrus.go @@ -87,8 +87,7 @@ const ( InfoLevel // DebugLevel level. Usually only enabled when debugging. Very verbose logging. DebugLevel - // TraceLevel level. Usually only enabled when debugging. Very verbose logging. - // Usually reserved for message traces. + // TraceLevel level. Designates finer-grained informational events than the Debug. TraceLevel ) From b54cafe5cee93a35bf6b061e261e8265ea0a628c Mon Sep 17 00:00:00 2001 From: Loren Osborn Date: Thu, 18 Oct 2018 09:33:43 -0700 Subject: [PATCH 90/92] Addresses @stevvooe's backward compatibility concerns. --- logrus.go | 12 +++++++++--- logrus_test.go | 7 +++++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/logrus.go b/logrus.go index 8834b5b..03046b6 100644 --- a/logrus.go +++ b/logrus.go @@ -121,7 +121,6 @@ type FieldLogger interface { WithFields(fields Fields) *Entry WithError(err error) *Entry - Tracef(format string, args ...interface{}) Debugf(format string, args ...interface{}) Infof(format string, args ...interface{}) Printf(format string, args ...interface{}) @@ -131,7 +130,6 @@ type FieldLogger interface { Fatalf(format string, args ...interface{}) Panicf(format string, args ...interface{}) - Trace(args ...interface{}) Debug(args ...interface{}) Info(args ...interface{}) Print(args ...interface{}) @@ -141,7 +139,6 @@ type FieldLogger interface { Fatal(args ...interface{}) Panic(args ...interface{}) - Traceln(args ...interface{}) Debugln(args ...interface{}) Infoln(args ...interface{}) Println(args ...interface{}) @@ -158,3 +155,12 @@ type FieldLogger interface { // IsFatalEnabled() bool // IsPanicEnabled() bool } + +// Ext1FieldLogger (the first extension to FieldLogger) is superfluous, it is +// here for consistancy. Do not use. Use Logger or Entry instead. +type Ext1FieldLogger interface { + FieldLogger + Tracef(format string, args ...interface{}) + Trace(args ...interface{}) + Traceln(args ...interface{}) +} diff --git a/logrus_test.go b/logrus_test.go index 210feef..748f0ba 100644 --- a/logrus_test.go +++ b/logrus_test.go @@ -453,9 +453,12 @@ func TestReplaceHooks(t *testing.T) { } // Compile test -func TestLogrusInterface(t *testing.T) { +func TestLogrusInterfaces(t *testing.T) { var buffer bytes.Buffer - fn := func(l FieldLogger) { + // This verifies FieldLogger and Ext1FieldLogger work as designed. + // Please don't use them. Use Logger and Entry directly. + fn := func(xl Ext1FieldLogger) { + var l FieldLogger = xl b := l.WithField("key", "value") b.Debug("Test") } From ed3ffa01907342213754448cb455dcc26d8e0a6d Mon Sep 17 00:00:00 2001 From: Loren Osborn Date: Thu, 18 Oct 2018 22:35:59 -0700 Subject: [PATCH 91/92] PR#844: Added Trace to TestLogLevelEnabled() (requested by @dgsb) --- logrus_test.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/logrus_test.go b/logrus_test.go index 748f0ba..ccdf5cc 100644 --- a/logrus_test.go +++ b/logrus_test.go @@ -506,6 +506,7 @@ func TestLogLevelEnabled(t *testing.T) { assert.Equal(t, false, log.IsLevelEnabled(WarnLevel)) assert.Equal(t, false, log.IsLevelEnabled(InfoLevel)) assert.Equal(t, false, log.IsLevelEnabled(DebugLevel)) + assert.Equal(t, false, log.IsLevelEnabled(TraceLevel)) log.SetLevel(FatalLevel) assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) @@ -514,6 +515,7 @@ func TestLogLevelEnabled(t *testing.T) { assert.Equal(t, false, log.IsLevelEnabled(WarnLevel)) assert.Equal(t, false, log.IsLevelEnabled(InfoLevel)) assert.Equal(t, false, log.IsLevelEnabled(DebugLevel)) + assert.Equal(t, false, log.IsLevelEnabled(TraceLevel)) log.SetLevel(ErrorLevel) assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) @@ -522,6 +524,7 @@ func TestLogLevelEnabled(t *testing.T) { assert.Equal(t, false, log.IsLevelEnabled(WarnLevel)) assert.Equal(t, false, log.IsLevelEnabled(InfoLevel)) assert.Equal(t, false, log.IsLevelEnabled(DebugLevel)) + assert.Equal(t, false, log.IsLevelEnabled(TraceLevel)) log.SetLevel(WarnLevel) assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) @@ -530,6 +533,7 @@ func TestLogLevelEnabled(t *testing.T) { assert.Equal(t, true, log.IsLevelEnabled(WarnLevel)) assert.Equal(t, false, log.IsLevelEnabled(InfoLevel)) assert.Equal(t, false, log.IsLevelEnabled(DebugLevel)) + assert.Equal(t, false, log.IsLevelEnabled(TraceLevel)) log.SetLevel(InfoLevel) assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) @@ -538,6 +542,7 @@ func TestLogLevelEnabled(t *testing.T) { assert.Equal(t, true, log.IsLevelEnabled(WarnLevel)) assert.Equal(t, true, log.IsLevelEnabled(InfoLevel)) assert.Equal(t, false, log.IsLevelEnabled(DebugLevel)) + assert.Equal(t, false, log.IsLevelEnabled(TraceLevel)) log.SetLevel(DebugLevel) assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) @@ -546,4 +551,14 @@ func TestLogLevelEnabled(t *testing.T) { assert.Equal(t, true, log.IsLevelEnabled(WarnLevel)) assert.Equal(t, true, log.IsLevelEnabled(InfoLevel)) assert.Equal(t, true, log.IsLevelEnabled(DebugLevel)) + assert.Equal(t, false, log.IsLevelEnabled(TraceLevel)) + + log.SetLevel(TraceLevel) + assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) + assert.Equal(t, true, log.IsLevelEnabled(FatalLevel)) + assert.Equal(t, true, log.IsLevelEnabled(ErrorLevel)) + assert.Equal(t, true, log.IsLevelEnabled(WarnLevel)) + assert.Equal(t, true, log.IsLevelEnabled(InfoLevel)) + assert.Equal(t, true, log.IsLevelEnabled(DebugLevel)) + assert.Equal(t, true, log.IsLevelEnabled(TraceLevel)) } From bb98c6c5333eab6d403627978bbde01d60f176a7 Mon Sep 17 00:00:00 2001 From: David Bariod Date: Sun, 21 Oct 2018 11:53:14 +0200 Subject: [PATCH 92/92] Fix the version of windows coloring library dependency --- go.mod | 2 +- go.sum | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 79f11b7..94574cc 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module github.com/sirupsen/logrus require ( github.com/davecgh/go-spew v1.1.1 // indirect - github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe + github.com/konsorten/go-windows-terminal-sequences v1.0.1 github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/objx v0.1.1 // indirect github.com/stretchr/testify v1.2.2 diff --git a/go.sum b/go.sum index 16cab75..133d34a 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,7 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe h1:CHRGQ8V7OlCYtwaKPJi3iA7J+YdNKdo8j7nG5IgDhjs= github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=