mirror of https://github.com/sirupsen/logrus.git
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
8b0b8a88f2
61
.travis.yml
61
.travis.yml
|
@ -1,52 +1,25 @@
|
||||||
language: go
|
language: go
|
||||||
go_import_path: github.com/sirupsen/logrus
|
go_import_path: github.com/sirupsen/logrus
|
||||||
|
git:
|
||||||
|
depth: 1
|
||||||
env:
|
env:
|
||||||
- GOMAXPROCS=4 GORACE=halt_on_error=1
|
- GO111MODULE=on
|
||||||
|
- GO111MODULE=off
|
||||||
|
go: [ 1.11.x, 1.12.x ]
|
||||||
|
os: [ linux, osx ]
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
exclude:
|
||||||
- go: 1.10.x
|
- go: 1.12.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 ./...
|
|
||||||
- go: 1.11.x
|
|
||||||
env: GO111MODULE=on
|
|
||||||
install:
|
|
||||||
- go mod download
|
|
||||||
script:
|
|
||||||
- go test -race -v ./...
|
|
||||||
- go: 1.11.x
|
|
||||||
env: GO111MODULE=off
|
env: GO111MODULE=off
|
||||||
|
- go: 1.11.x
|
||||||
|
os: osx
|
||||||
install:
|
install:
|
||||||
- go get github.com/stretchr/testify/assert
|
- ./travis/install.sh
|
||||||
- go get golang.org/x/crypto/ssh/terminal
|
- if [[ "$GO111MODULE" == "on" ]]; then go mod download; fi
|
||||||
- go get golang.org/x/sys/unix
|
- if [[ "$GO111MODULE" == "off" ]]; then go get github.com/stretchr/testify/assert golang.org/x/sys/unix github.com/konsorten/go-windows-terminal-sequences; fi
|
||||||
- go get golang.org/x/sys/windows
|
|
||||||
script:
|
script:
|
||||||
|
- ./travis/cross_build.sh
|
||||||
|
- export GOMAXPROCS=4
|
||||||
|
- export GORACE=halt_on_error=1
|
||||||
- go test -race -v ./...
|
- go test -race -v ./...
|
||||||
- go: 1.10.x
|
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then go test -race -v -tags appengine ./... ; fi
|
||||||
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 ./...
|
|
||||||
|
|
10
CHANGELOG.md
10
CHANGELOG.md
|
@ -1,3 +1,13 @@
|
||||||
|
# 1.4.2
|
||||||
|
* Fixes build break for plan9, nacl, solaris
|
||||||
|
# 1.4.1
|
||||||
|
This new release introduces:
|
||||||
|
* Enhance TextFormatter to not print caller information when they are empty (#944)
|
||||||
|
* Remove dependency on golang.org/x/crypto (#932, #943)
|
||||||
|
|
||||||
|
Fixes:
|
||||||
|
* Fix Entry.WithContext method to return a copy of the initial entry (#941)
|
||||||
|
|
||||||
# 1.4.0
|
# 1.4.0
|
||||||
This new release introduces:
|
This new release introduces:
|
||||||
* Add `DeferExitHandler`, similar to `RegisterExitHandler` but prepending the handler to the list of handlers (semantically like `defer`) (#848).
|
* Add `DeferExitHandler`, similar to `RegisterExitHandler` but prepending the handler to the list of handlers (semantically like `defer`) (#848).
|
||||||
|
|
|
@ -15,11 +15,6 @@ comments](https://github.com/sirupsen/logrus/issues/553#issuecomment-306591437).
|
||||||
For an in-depth explanation of the casing issue, see [this
|
For an in-depth explanation of the casing issue, see [this
|
||||||
comment](https://github.com/sirupsen/logrus/issues/570#issuecomment-313933276).
|
comment](https://github.com/sirupsen/logrus/issues/570#issuecomment-313933276).
|
||||||
|
|
||||||
**Are you interested in assisting in maintaining Logrus?** Currently I have a
|
|
||||||
lot of obligations, and I am unable to provide Logrus with the maintainership it
|
|
||||||
needs. If you'd like to help, please reach out to me at `simon at author's
|
|
||||||
username dot com`.
|
|
||||||
|
|
||||||
Nicely color-coded in development (when a TTY is attached, otherwise just
|
Nicely color-coded in development (when a TTY is attached, otherwise just
|
||||||
plain text):
|
plain text):
|
||||||
|
|
||||||
|
@ -187,7 +182,7 @@ func main() {
|
||||||
log.Out = os.Stdout
|
log.Out = os.Stdout
|
||||||
|
|
||||||
// You could set this to any `io.Writer` such as a file
|
// You could set this to any `io.Writer` such as a file
|
||||||
// file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY, 0666)
|
// file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
||||||
// if err == nil {
|
// if err == nil {
|
||||||
// log.Out = file
|
// log.Out = file
|
||||||
// } else {
|
// } else {
|
||||||
|
@ -354,6 +349,7 @@ The built-in logging formatters are:
|
||||||
[github.com/mattn/go-colorable](https://github.com/mattn/go-colorable).
|
[github.com/mattn/go-colorable](https://github.com/mattn/go-colorable).
|
||||||
* When colors are enabled, levels are truncated to 4 characters by default. To disable
|
* When colors are enabled, levels are truncated to 4 characters by default. To disable
|
||||||
truncation set the `DisableLevelTruncation` field to `true`.
|
truncation set the `DisableLevelTruncation` field to `true`.
|
||||||
|
* When outputting to a TTY, it's often helpful to visually scan down a column where all the levels are the same width. Setting the `PadLevelText` field to `true` enables this behavior, by adding padding to the level text.
|
||||||
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#TextFormatter).
|
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#TextFormatter).
|
||||||
* `logrus.JSONFormatter`. Logs fields as JSON.
|
* `logrus.JSONFormatter`. Logs fields as JSON.
|
||||||
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#JSONFormatter).
|
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#JSONFormatter).
|
||||||
|
|
3
entry.go
3
entry.go
|
@ -108,8 +108,7 @@ func (entry *Entry) WithError(err error) *Entry {
|
||||||
|
|
||||||
// Add a context to the Entry.
|
// Add a context to the Entry.
|
||||||
func (entry *Entry) WithContext(ctx context.Context) *Entry {
|
func (entry *Entry) WithContext(ctx context.Context) *Entry {
|
||||||
entry.Context = ctx
|
return &Entry{Logger: entry.Logger, Data: entry.Data, Time: entry.Time, err: entry.err, Context: ctx}
|
||||||
return entry
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a single field to the Entry.
|
// Add a single field to the Entry.
|
||||||
|
|
3
go.mod
3
go.mod
|
@ -6,6 +6,5 @@ require (
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/stretchr/objx v0.1.1 // indirect
|
github.com/stretchr/objx v0.1.1 // indirect
|
||||||
github.com/stretchr/testify v1.2.2
|
github.com/stretchr/testify v1.2.2
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33
|
|
||||||
)
|
)
|
||||||
|
|
5
go.sum
5
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/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 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 v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
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/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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
@ -9,7 +10,7 @@ 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/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 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
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/sys v0.0.0-20180905080454-ebe1bf3edb33 h1:I6FyU15t786LL7oL/hn43zqTuEGr4PN7F4XJ1p4E3Y8=
|
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/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
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=
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
// +build !appengine,!js,!windows,aix
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import "io"
|
|
||||||
|
|
||||||
func checkIfTerminal(w io.Writer) bool {
|
|
||||||
return false
|
|
||||||
}
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
// +build darwin dragonfly freebsd netbsd openbsd
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import "golang.org/x/sys/unix"
|
||||||
|
|
||||||
|
const ioctlReadTermios = unix.TIOCGETA
|
||||||
|
|
||||||
|
func isTerminal(fd int) bool {
|
||||||
|
_, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// +build js
|
// +build js nacl plan9
|
||||||
|
|
||||||
package logrus
|
package logrus
|
||||||
|
|
|
@ -1,18 +1,16 @@
|
||||||
// +build !appengine,!js,!windows,!aix
|
// +build !appengine,!js,!windows,!nacl,!plan9
|
||||||
|
|
||||||
package logrus
|
package logrus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"golang.org/x/crypto/ssh/terminal"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func checkIfTerminal(w io.Writer) bool {
|
func checkIfTerminal(w io.Writer) bool {
|
||||||
switch v := w.(type) {
|
switch v := w.(type) {
|
||||||
case *os.File:
|
case *os.File:
|
||||||
return terminal.IsTerminal(int(v.Fd()))
|
return isTerminal(int(v.Fd()))
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||||
|
func isTerminal(fd int) bool {
|
||||||
|
_, err := unix.IoctlGetTermio(fd, unix.TCGETA)
|
||||||
|
return err == nil
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
// +build linux aix
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import "golang.org/x/sys/unix"
|
||||||
|
|
||||||
|
const ioctlReadTermios = unix.TCGETS
|
||||||
|
|
||||||
|
func isTerminal(fd int) bool {
|
||||||
|
_, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
|
@ -6,15 +6,29 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
sequences "github.com/konsorten/go-windows-terminal-sequences"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func initTerminal(w io.Writer) {
|
||||||
|
switch v := w.(type) {
|
||||||
|
case *os.File:
|
||||||
|
sequences.EnableVirtualTerminalProcessing(syscall.Handle(v.Fd()), true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func checkIfTerminal(w io.Writer) bool {
|
func checkIfTerminal(w io.Writer) bool {
|
||||||
|
var ret bool
|
||||||
switch v := w.(type) {
|
switch v := w.(type) {
|
||||||
case *os.File:
|
case *os.File:
|
||||||
var mode uint32
|
var mode uint32
|
||||||
err := syscall.GetConsoleMode(syscall.Handle(v.Fd()), &mode)
|
err := syscall.GetConsoleMode(syscall.Handle(v.Fd()), &mode)
|
||||||
return err == nil
|
ret = (err == nil)
|
||||||
default:
|
default:
|
||||||
return false
|
ret = false
|
||||||
}
|
}
|
||||||
|
if ret {
|
||||||
|
initTerminal(w)
|
||||||
|
}
|
||||||
|
return ret
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
// +build !windows
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import "io"
|
|
||||||
|
|
||||||
func initTerminal(w io.Writer) {
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
// +build !appengine,!js,windows
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
sequences "github.com/konsorten/go-windows-terminal-sequences"
|
|
||||||
)
|
|
||||||
|
|
||||||
func initTerminal(w io.Writer) {
|
|
||||||
switch v := w.(type) {
|
|
||||||
case *os.File:
|
|
||||||
sequences.EnableVirtualTerminalProcessing(syscall.Handle(v.Fd()), true)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,9 +6,11 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
"unicode/utf8"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -57,6 +59,10 @@ type TextFormatter struct {
|
||||||
// Disables the truncation of the level text to 4 characters.
|
// Disables the truncation of the level text to 4 characters.
|
||||||
DisableLevelTruncation bool
|
DisableLevelTruncation bool
|
||||||
|
|
||||||
|
// PadLevelText Adds padding the level text so that all the levels output at the same length
|
||||||
|
// PadLevelText is a superset of the DisableLevelTruncation option
|
||||||
|
PadLevelText bool
|
||||||
|
|
||||||
// QuoteEmptyFields will wrap empty fields in quotes if true
|
// QuoteEmptyFields will wrap empty fields in quotes if true
|
||||||
QuoteEmptyFields bool
|
QuoteEmptyFields bool
|
||||||
|
|
||||||
|
@ -73,20 +79,26 @@ type TextFormatter struct {
|
||||||
FieldMap FieldMap
|
FieldMap FieldMap
|
||||||
|
|
||||||
// CallerPrettyfier can be set by the user to modify the content
|
// CallerPrettyfier can be set by the user to modify the content
|
||||||
// of the function and file keys in the json data when ReportCaller is
|
// of the function and file keys in the data when ReportCaller is
|
||||||
// activated. If any of the returned value is the empty string the
|
// activated. If any of the returned value is the empty string the
|
||||||
// corresponding key will be removed from json fields.
|
// corresponding key will be removed from fields.
|
||||||
CallerPrettyfier func(*runtime.Frame) (function string, file string)
|
CallerPrettyfier func(*runtime.Frame) (function string, file string)
|
||||||
|
|
||||||
terminalInitOnce sync.Once
|
terminalInitOnce sync.Once
|
||||||
|
|
||||||
|
// The max length of the level text, generated dynamically on init
|
||||||
|
levelTextMaxLength int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *TextFormatter) init(entry *Entry) {
|
func (f *TextFormatter) init(entry *Entry) {
|
||||||
if entry.Logger != nil {
|
if entry.Logger != nil {
|
||||||
f.isTerminal = checkIfTerminal(entry.Logger.Out)
|
f.isTerminal = checkIfTerminal(entry.Logger.Out)
|
||||||
|
}
|
||||||
if f.isTerminal {
|
// Get the max length of the level text
|
||||||
initTerminal(entry.Logger.Out)
|
for _, level := range AllLevels {
|
||||||
|
levelTextLength := utf8.RuneCount([]byte(level.String()))
|
||||||
|
if levelTextLength > f.levelTextMaxLength {
|
||||||
|
f.levelTextMaxLength = levelTextLength
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,14 +145,19 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLogrusError))
|
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLogrusError))
|
||||||
}
|
}
|
||||||
if entry.HasCaller() {
|
if entry.HasCaller() {
|
||||||
fixedKeys = append(fixedKeys,
|
|
||||||
f.FieldMap.resolve(FieldKeyFunc), f.FieldMap.resolve(FieldKeyFile))
|
|
||||||
if f.CallerPrettyfier != nil {
|
if f.CallerPrettyfier != nil {
|
||||||
funcVal, fileVal = f.CallerPrettyfier(entry.Caller)
|
funcVal, fileVal = f.CallerPrettyfier(entry.Caller)
|
||||||
} else {
|
} else {
|
||||||
funcVal = entry.Caller.Function
|
funcVal = entry.Caller.Function
|
||||||
fileVal = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
|
fileVal = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if funcVal != "" {
|
||||||
|
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyFunc))
|
||||||
|
}
|
||||||
|
if fileVal != "" {
|
||||||
|
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyFile))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !f.DisableSorting {
|
if !f.DisableSorting {
|
||||||
|
@ -216,16 +233,24 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin
|
||||||
}
|
}
|
||||||
|
|
||||||
levelText := strings.ToUpper(entry.Level.String())
|
levelText := strings.ToUpper(entry.Level.String())
|
||||||
if !f.DisableLevelTruncation {
|
if !f.DisableLevelTruncation && !f.PadLevelText {
|
||||||
levelText = levelText[0:4]
|
levelText = levelText[0:4]
|
||||||
}
|
}
|
||||||
|
if f.PadLevelText {
|
||||||
|
// Generates the format string used in the next line, for example "%-6s" or "%-7s".
|
||||||
|
// Based on the max level text length.
|
||||||
|
formatString := "%-" + strconv.Itoa(f.levelTextMaxLength) + "s"
|
||||||
|
// Formats the level text by appending spaces up to the max length, for example:
|
||||||
|
// - "INFO "
|
||||||
|
// - "WARNING"
|
||||||
|
levelText = fmt.Sprintf(formatString, levelText)
|
||||||
|
}
|
||||||
|
|
||||||
// Remove a single newline if it already exists in the message to keep
|
// 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
|
// the behavior of logrus text_formatter the same as the stdlib log package
|
||||||
entry.Message = strings.TrimSuffix(entry.Message, "\n")
|
entry.Message = strings.TrimSuffix(entry.Message, "\n")
|
||||||
|
|
||||||
caller := ""
|
caller := ""
|
||||||
|
|
||||||
if entry.HasCaller() {
|
if entry.HasCaller() {
|
||||||
funcVal := fmt.Sprintf("%s()", entry.Caller.Function)
|
funcVal := fmt.Sprintf("%s()", entry.Caller.Function)
|
||||||
fileVal := fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
|
fileVal := fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
|
||||||
|
@ -233,8 +258,15 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin
|
||||||
if f.CallerPrettyfier != nil {
|
if f.CallerPrettyfier != nil {
|
||||||
funcVal, fileVal = f.CallerPrettyfier(entry.Caller)
|
funcVal, fileVal = f.CallerPrettyfier(entry.Caller)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if fileVal == "" {
|
||||||
|
caller = funcVal
|
||||||
|
} else if funcVal == "" {
|
||||||
|
caller = fileVal
|
||||||
|
} else {
|
||||||
caller = fileVal + " " + funcVal
|
caller = fileVal + " " + funcVal
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if f.DisableTimestamp {
|
if f.DisableTimestamp {
|
||||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m%s %-44s ", levelColor, levelText, caller, entry.Message)
|
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m%s %-44s ", levelColor, levelText, caller, entry.Message)
|
||||||
|
|
|
@ -172,6 +172,97 @@ func TestDisableLevelTruncation(t *testing.T) {
|
||||||
checkDisableTruncation(false, InfoLevel)
|
checkDisableTruncation(false, InfoLevel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPadLevelText(t *testing.T) {
|
||||||
|
// A note for future maintainers / committers:
|
||||||
|
//
|
||||||
|
// This test denormalizes the level text as a part of its assertions.
|
||||||
|
// Because of that, its not really a "unit test" of the PadLevelText functionality.
|
||||||
|
// So! Many apologies to the potential future person who has to rewrite this test
|
||||||
|
// when they are changing some completely unrelated functionality.
|
||||||
|
params := []struct {
|
||||||
|
name string
|
||||||
|
level Level
|
||||||
|
paddedLevelText string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "PanicLevel",
|
||||||
|
level: PanicLevel,
|
||||||
|
paddedLevelText: "PANIC ", // 2 extra spaces
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "FatalLevel",
|
||||||
|
level: FatalLevel,
|
||||||
|
paddedLevelText: "FATAL ", // 2 extra spaces
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ErrorLevel",
|
||||||
|
level: ErrorLevel,
|
||||||
|
paddedLevelText: "ERROR ", // 2 extra spaces
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "WarnLevel",
|
||||||
|
level: WarnLevel,
|
||||||
|
// WARNING is already the max length, so we don't need to assert a paddedLevelText
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "DebugLevel",
|
||||||
|
level: DebugLevel,
|
||||||
|
paddedLevelText: "DEBUG ", // 2 extra spaces
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "TraceLevel",
|
||||||
|
level: TraceLevel,
|
||||||
|
paddedLevelText: "TRACE ", // 2 extra spaces
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "InfoLevel",
|
||||||
|
level: InfoLevel,
|
||||||
|
paddedLevelText: "INFO ", // 3 extra spaces
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// We create a "default" TextFormatter to do a control test.
|
||||||
|
// We also create a TextFormatter with PadLevelText, which is the parameter we want to do our most relevant assertions against.
|
||||||
|
tfDefault := TextFormatter{}
|
||||||
|
tfWithPadding := TextFormatter{PadLevelText: true}
|
||||||
|
|
||||||
|
for _, val := range params {
|
||||||
|
t.Run(val.name, func(t *testing.T) {
|
||||||
|
// TextFormatter writes into these bytes.Buffers, and we make assertions about their contents later
|
||||||
|
var bytesDefault bytes.Buffer
|
||||||
|
var bytesWithPadding bytes.Buffer
|
||||||
|
|
||||||
|
// The TextFormatter instance and the bytes.Buffer instance are different here
|
||||||
|
// all the other arguments are the same. We also initialize them so that they
|
||||||
|
// fill in the value of levelTextMaxLength.
|
||||||
|
tfDefault.init(&Entry{})
|
||||||
|
tfDefault.printColored(&bytesDefault, &Entry{Level: val.level}, []string{}, nil, "")
|
||||||
|
tfWithPadding.init(&Entry{})
|
||||||
|
tfWithPadding.printColored(&bytesWithPadding, &Entry{Level: val.level}, []string{}, nil, "")
|
||||||
|
|
||||||
|
// turn the bytes back into a string so that we can actually work with the data
|
||||||
|
logLineDefault := (&bytesDefault).String()
|
||||||
|
logLineWithPadding := (&bytesWithPadding).String()
|
||||||
|
|
||||||
|
// Control: the level text should not be padded by default
|
||||||
|
if val.paddedLevelText != "" && strings.Contains(logLineDefault, val.paddedLevelText) {
|
||||||
|
t.Errorf("log line %q should not contain the padded level text %q by default", logLineDefault, val.paddedLevelText)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assertion: the level text should still contain the string representation of the level
|
||||||
|
if !strings.Contains(strings.ToLower(logLineWithPadding), val.level.String()) {
|
||||||
|
t.Errorf("log line %q should contain the level text %q when padding is enabled", logLineWithPadding, val.level.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assertion: the level text should be in its padded form now
|
||||||
|
if val.paddedLevelText != "" && !strings.Contains(logLineWithPadding, val.paddedLevelText) {
|
||||||
|
t.Errorf("log line %q should contain the padded level text %q when padding is enabled", logLineWithPadding, val.paddedLevelText)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestDisableTimestampWithColoredOutput(t *testing.T) {
|
func TestDisableTimestampWithColoredOutput(t *testing.T) {
|
||||||
tf := &TextFormatter{DisableTimestamp: true, ForceColors: true}
|
tf := &TextFormatter{DisableTimestamp: true, ForceColors: true}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [[ "$TRAVIS_GO_VERSION" =~ ^1.\12\. ]] && [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
|
||||||
|
/tmp/gox/gox -build-lib -all
|
||||||
|
fi
|
|
@ -0,0 +1,11 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [[ "$TRAVIS_GO_VERSION" =~ ^1.\12\. ]] && [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
|
||||||
|
git clone https://github.com/dgsb/gox.git /tmp/gox
|
||||||
|
pushd /tmp/gox
|
||||||
|
git checkout new_master
|
||||||
|
go build ./
|
||||||
|
popd
|
||||||
|
fi
|
Loading…
Reference in New Issue