-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
398 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# Test binary, build with `go test -c` | ||
*.test | ||
|
||
# Output of the go coverage tool, specifically when used with LiteIDE | ||
*.out | ||
|
||
vendor |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
language: go | ||
|
||
go: | ||
- "1.11.x" | ||
- "1.12.x" | ||
|
||
env: | ||
- GO111MODULE=on | ||
|
||
install: | ||
- make install | ||
|
||
script: | ||
- make test | ||
- make check-fmt | ||
|
||
after_success: | ||
- make report-coveralls |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# Changelog | ||
All notable changes to this project will be documented in this file. | ||
|
||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), | ||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). | ||
|
||
## [Unreleased] | ||
|
||
## [1.0.0] - 2019-08-09 | ||
### Changes | ||
- Initial version |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
.PHONY: test help fmt check-fmt install report-coveralls | ||
|
||
help: ## Show the help text | ||
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-20s\033[93m %s\n", $$1, $$2}' | ||
|
||
test: ## Run unit tests | ||
@go test -coverprofile=coverage.out -covermode=atomic -race ./... | ||
|
||
check-fmt: ## Check file forma | ||
@GOIMP=$$(for f in $$(find . -type f -name "*.go" ! -path "./.cache/*" ! -path "./vendor/*" ! -name "bindata.go") ; do \ | ||
goimports -l $$f ; \ | ||
done) && echo $$GOIMP && test -z "$$GOIMP" | ||
|
||
fmt: ## Format files | ||
@goimports -w $$(find . -name "*.go" -not -path "./vendor/*") | ||
|
||
install: ## Installs dependencies | ||
GOPATH=$$GOPATH && go get -u -v \ | ||
golang.org/x/tools/cmd/goimports | ||
|
||
report-coveralls: ## Reports generated coverage profile to coveralls.io. Intended to be used only from travis | ||
go get github.com/mattn/goveralls && goveralls -coverprofile=coverage.out -service=travis-ci |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# logrusiowriter | ||
## `io.Writer` implementation using logrus | ||
|
||
[![Travis CI build status](https://travis-ci.com/cabify/logrusiowriter.svg?branch=master)](https://travis-ci.com/cabify/logrusiowriter) | ||
[![Coverage Status](https://coveralls.io/repos/github/cabify/logrusiowriter/badge.svg)](https://coveralls.io/github/cabify/logrusiowriter) | ||
[![GoDoc](https://godoc.org/github.com/cabify/logrusiowriter?status.svg)](https://godoc.org/github.com/cabify/logrusiowriter) | ||
|
||
# Motivation | ||
|
||
Many golang libraries use the golang's `log` package to print their logs. This means that if your application | ||
uses logrus to print structured logging, those packages will print a format that is (probably) incompatible with yours, | ||
and you may end losing logs in your logs collector because they can't be parsed properly. | ||
|
||
# Solution | ||
|
||
Print the logs written using `log.Printf` through `logrus`, by setting `log.SetOutput` to an `io.Writer` implementation | ||
that uses `logrus` as output, i.e.: | ||
|
||
```go | ||
log.SetOutput(logrusiowriter.New()) | ||
``` | ||
|
||
See `example_*_test.go` files to find testable examples that serve as documentation. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package logrusiowriter | ||
|
||
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"` | ||
} | ||
|
||
// WithLogger configures the logger with the one provided | ||
func WithLogger(logger logrus.FieldLogger) Configurer { | ||
return func(w *writer) { | ||
w.logger = logger | ||
} | ||
} | ||
|
||
// WithLevel configures the level with the one provided | ||
func WithLevel(lvl logrus.Level) Configurer { | ||
return func(w *writer) { | ||
w.level = lvl | ||
} | ||
} | ||
|
||
// WithFields configures the fields with the ones provided | ||
func WithFields(fields logrus.Fields) Configurer { | ||
return func(w *writer) { | ||
w.fields = fields | ||
} | ||
} | ||
|
||
// WithConfig creates a configurer from the configuration provided as a struct | ||
// If it's unable to parse the Level provided as a string, it will invoke the OnLevelParseError function and set the | ||
// level returned by that function (a default value) | ||
func WithConfig(cfg Config) Configurer { | ||
return func(w *writer) { | ||
lvl, err := logrus.ParseLevel(cfg.Level) | ||
if err != nil { | ||
lvl = OnLevelParseError(err) | ||
} | ||
w.level = lvl | ||
w.fields = cfg.Fields | ||
} | ||
} | ||
|
||
// WithConfigInterface creates a configurer from the configuration provided as an interface | ||
func WithConfigInterface(cfg interface { | ||
Level() logrus.Level | ||
Fields() logrus.Fields | ||
Logger() logrus.FieldLogger | ||
}) Configurer { | ||
return func(w *writer) { | ||
w.logger = cfg.Logger() | ||
w.level = cfg.Level() | ||
w.fields = cfg.Fields() | ||
} | ||
} | ||
|
||
// OnLevelParseError will be invoked if logrus is unable to parse the string level provided in the configuration | ||
// The default behavior is to log it with logrus and return a default Info level, | ||
// you can change this to log in some other system or to panic | ||
// Changing this is not thread safe, so it might be a good idea to change it in a init() function | ||
var OnLevelParseError = func(err error) logrus.Level { | ||
logrus.Errorf("Can't parse level: %s", err) | ||
return logrus.InfoLevel | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package logrusiowriter | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/sirupsen/logrus" | ||
) | ||
|
||
func TestWithConfig(t *testing.T) { | ||
t.Run("can't parse level, configures info level by default", func(t *testing.T) { | ||
expectedLevel := logrus.InfoLevel | ||
|
||
cfg := Config{ | ||
Level: "none", | ||
Fields: logrus.Fields{}, | ||
} | ||
|
||
w := New(WithConfig(cfg)) | ||
|
||
configuredLevel := w.(*writer).level | ||
if configuredLevel != expectedLevel { | ||
t.Errorf("Configured level should be %s, but it was %s", expectedLevel, configuredLevel) | ||
} | ||
}) | ||
|
||
t.Run("custom OnLevelParseError", func(t *testing.T) { | ||
originalOnLevelParseError := OnLevelParseError | ||
defer func() { OnLevelParseError = originalOnLevelParseError }() | ||
|
||
expectedLevel := logrus.WarnLevel | ||
|
||
cfg := Config{ | ||
Level: "none", | ||
Fields: logrus.Fields{}, | ||
} | ||
|
||
var providedErr error | ||
OnLevelParseError = func(err error) logrus.Level { | ||
providedErr = err | ||
return expectedLevel | ||
} | ||
|
||
w := New(WithConfig(cfg)) | ||
|
||
configuredLevel := w.(*writer).level | ||
if configuredLevel != expectedLevel { | ||
t.Errorf("Configured level should be %s, but it was %s", expectedLevel, configuredLevel) | ||
} | ||
|
||
if providedErr == nil { | ||
t.Errorf("Error provided to OnLevelParseError should not be nil") | ||
} | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
package logrusiowriter_test | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/cabify/logrusiowriter" | ||
"github.com/sirupsen/logrus" | ||
) | ||
|
||
func ExampleWithConfig() { | ||
removeTimestampAndSetOutputToStdout(logrus.StandardLogger()) | ||
|
||
config := logrusiowriter.Config{ | ||
Level: "warning", | ||
Fields: map[string]interface{}{ | ||
"config": "struct", | ||
}, | ||
} | ||
|
||
writer := logrusiowriter.New( | ||
logrusiowriter.WithConfig(config), | ||
) | ||
|
||
_, _ = fmt.Fprint(writer, "Hello World!") | ||
// Output: | ||
// level=warning msg="Hello World!" config=struct | ||
} | ||
|
||
func ExampleWithFields() { | ||
removeTimestampAndSetOutputToStdout(logrus.StandardLogger()) | ||
|
||
writer := logrusiowriter.New( | ||
logrusiowriter.WithFields(logrus.Fields{ | ||
"config": "fields", | ||
"other": 288, | ||
}), | ||
) | ||
|
||
_, _ = fmt.Fprint(writer, "Hello World!") | ||
// Output: | ||
// level=info msg="Hello World!" config=fields other=288 | ||
} | ||
|
||
func ExampleWithLevel() { | ||
removeTimestampAndSetOutputToStdout(logrus.StandardLogger()) | ||
|
||
writer := logrusiowriter.New( | ||
logrusiowriter.WithLevel(logrus.ErrorLevel), | ||
) | ||
|
||
_, _ = fmt.Fprint(writer, "Hello World!") | ||
// Output: | ||
// level=error msg="Hello World!" | ||
} | ||
|
||
func ExampleWithLogger() { | ||
logger := logrus.New() | ||
removeTimestampAndSetOutputToStdout(logger) | ||
logger.SetLevel(logrus.TraceLevel) | ||
|
||
writer := logrusiowriter.New( | ||
logrusiowriter.WithLogger(logger), | ||
) | ||
|
||
_, _ = fmt.Fprint(writer, "Hello World!") | ||
// Output: | ||
// level=info msg="Hello World!" | ||
} | ||
|
||
func ExampleWithConfigInterface() { | ||
removeTimestampAndSetOutputToStdout(logrus.StandardLogger()) | ||
|
||
writer := logrusiowriter.New( | ||
logrusiowriter.WithConfigInterface(configProvider{}), | ||
) | ||
|
||
_, _ = fmt.Fprint(writer, "Hello World!") | ||
// Output: | ||
// level=trace msg="Hello World!" config=interface | ||
} | ||
|
||
type configProvider struct{} | ||
|
||
func (configProvider) Level() logrus.Level { return logrus.TraceLevel } | ||
|
||
func (configProvider) Fields() logrus.Fields { return logrus.Fields{"config": "interface"} } | ||
|
||
func (configProvider) Logger() logrus.FieldLogger { | ||
logger := logrus.New() | ||
removeTimestampAndSetOutputToStdout(logger) | ||
logger.SetLevel(logrus.TraceLevel) | ||
return logger | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package logrusiowriter_test | ||
|
||
import ( | ||
"log" | ||
|
||
"github.com/cabify/logrusiowriter" | ||
"github.com/sirupsen/logrus" | ||
) | ||
|
||
func ExampleNew() { | ||
removeTimestampAndSetOutputToStdout(logrus.StandardLogger()) | ||
|
||
log.SetOutput(logrusiowriter.New()) | ||
log.SetFlags(0) // no date on standard logger | ||
|
||
log.Printf("Standard log") | ||
|
||
// Output: | ||
// level=info msg="Standard log\n" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
module github.com/cabify/logrusiowriter | ||
|
||
go 1.12 | ||
|
||
require ( | ||
github.com/sirupsen/logrus v1.4.2 | ||
golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
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 v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= | ||
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/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= | ||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= | ||
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/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= | ||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa h1:KIDDMLT1O0Nr7TSxp8xM5tJcdn8tgyAONntO829og1M= | ||
golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package logrusiowriter_test | ||
|
||
import ( | ||
"os" | ||
|
||
"github.com/sirupsen/logrus" | ||
) | ||
|
||
var datelessFormatter = new(logrus.TextFormatter) | ||
|
||
func init() { | ||
datelessFormatter.DisableTimestamp = true | ||
} | ||
|
||
// removeTimestampAndSetOutputToStdout removes date from logrus logs, and redirects them to os.Stdout | ||
// this can't be done in init() because os.Stdout changes after calling init() in examples: | ||
// see: https://unexpected-go.com/os-stdout-changes-after-init-in-examples.html | ||
func removeTimestampAndSetOutputToStdout(logger *logrus.Logger) { | ||
logger.SetFormatter(datelessFormatter) | ||
logger.SetOutput(os.Stdout) | ||
} |
Oops, something went wrong.