Skip to content

Commit

Permalink
Merge pull request #2 from cabify/colega/trailing-newline-trimming
Browse files Browse the repository at this point in the history
Trim trailing newline characters by default
  • Loading branch information
colega authored Aug 12, 2019
2 parents 896f8de + 44b8e7b commit 247d2cb
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 10 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [1.1.0] - 2019-08-12
### Added
- Trailing newline character `\n` trimming enabled by default

## [1.0.0] - 2019-08-09
### Changes
- Initial version
13 changes: 11 additions & 2 deletions configs.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,17 @@ import "github.com/sirupsen/logrus"
// Config holds the configuration to be used with WithConfig() configurer
// This struct is useful to embed into configuration structs parsed with libraries like envconfig
type Config struct {
Level string `default:"info"`
Fields logrus.Fields `default:"logger:stdlib"`
Level string `default:"info"`
Fields logrus.Fields `default:"logger:stdlib"`
TrailingNewLineTrimming bool `default:"true"`
}

// WithTrailingNewLineTrimming configures trailing newline trimming. This is true by default, because
// log.Print adds a newline in the end of its messages, which does not make sense inside of a logrus log
func WithTrailingNewLineTrimming(trim bool) Configurer {
return func(w *writer) {
w.trailingNewLineTrimming = trim
}
}

// WithLogger configures the logger with the one provided
Expand Down
70 changes: 70 additions & 0 deletions configs_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package logrusiowriter

import (
"bytes"
"testing"

"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -51,4 +52,73 @@ func TestWithConfig(t *testing.T) {
t.Errorf("Error provided to OnLevelParseError should not be nil")
}
})

t.Run("trimming", func(t *testing.T) {
const newLineAppendedByLogrus = "\n"
for _, tc := range []struct {
desc string
trimming bool
input string
expected string
}{
{
desc: "zerolength with trimming",
trimming: true,
input: "",
expected: "level=info" + newLineAppendedByLogrus,
},
{
desc: "zerolength without trimming",
trimming: false,
input: "",
expected: "level=info" + newLineAppendedByLogrus,
},
{
desc: "only newline with trimming",
trimming: true,
input: "\n",
expected: "level=info" + newLineAppendedByLogrus,
},
{
desc: "only newline without trimming",
trimming: false,
input: "\n",
expected: `level=info msg="\n"` + newLineAppendedByLogrus,
},
{
desc: "with trailing newline and trimming",
trimming: true,
input: "message\n",
expected: "level=info msg=message" + newLineAppendedByLogrus,
},
{
desc: "with trailing newline and no trimming",
trimming: false,
input: "message\n",
expected: `level=info msg="message\n"` + newLineAppendedByLogrus,
},
{
desc: "no newline with trimming",
trimming: true,
input: "message",
expected: "level=info msg=message" + newLineAppendedByLogrus,
},
} {
t.Run(tc.desc, func(t *testing.T) {
buf := &bytes.Buffer{}

bufLogger := logrus.New()
bufLogger.SetOutput(buf)
bufLogger.Formatter.(*logrus.TextFormatter).DisableTimestamp = true

writer := New(WithLogger(bufLogger), WithTrailingNewLineTrimming(tc.trimming))

_, _ = writer.Write([]byte(tc.input))

if buf.String() != tc.expected {
t.Errorf("Unexpected output\nExpected: '%s'\nGot: '%s'", tc.expected, buf.String())
}
})
}
})
}
12 changes: 12 additions & 0 deletions example_configs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,18 @@ func ExampleWithConfigInterface() {
// level=trace msg="Hello World!" config=interface
}

func ExampleWithNewLineTrimming() {
removeTimestampAndSetOutputToStdout(logrus.StandardLogger())

writer := logrusiowriter.New(
logrusiowriter.WithTrailingNewLineTrimming(true),
)

_, _ = fmt.Fprint(writer, "Hello World!\n")
// Output:
// level=info msg="Hello World!"
}

type configProvider struct{}

func (configProvider) Level() logrus.Level { return logrus.TraceLevel }
Expand Down
2 changes: 1 addition & 1 deletion example_writer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ func ExampleNew() {
log.Printf("Standard log")

// Output:
// level=info msg="Standard log\n"
// level=info msg="Standard log"
}
20 changes: 13 additions & 7 deletions writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ import (
// If no Configurers provided, the writer will log with Info level and no fields using the logrus.StandardLogger
func New(cfg ...Configurer) io.Writer {
w := &writer{
logger: logrus.StandardLogger(),
level: logrus.InfoLevel,
fields: make(map[string]interface{}),
logger: logrus.StandardLogger(),
level: logrus.InfoLevel,
fields: make(map[string]interface{}),
trailingNewLineTrimming: true,
}
for _, c := range cfg {
c(w)
Expand All @@ -27,13 +28,18 @@ type Configurer func(*writer)

// writer implements io.Writer
type writer struct {
logger logrus.FieldLogger
level logrus.Level
fields map[string]interface{}
logger logrus.FieldLogger
level logrus.Level
fields map[string]interface{}
trailingNewLineTrimming bool
}

// Write will write with the logger, level and fields set in the writer
func (w *writer) Write(bytes []byte) (int, error) {
l := len(bytes)
if w.trailingNewLineTrimming && l > 0 && bytes[l-1] == '\n' {
bytes = bytes[:l-1]
}
w.logger.WithFields(w.fields).Log(w.level, string(bytes))
return len(bytes), nil
return l, nil
}

0 comments on commit 247d2cb

Please sign in to comment.