Skip to content

Commit

Permalink
fix: logrus pretty formatter (#14)
Browse files Browse the repository at this point in the history
Signed-off-by: Tronje Krop <[email protected]>
  • Loading branch information
Tronje Krop committed Oct 7, 2024
1 parent dd298ec commit f69dac2
Show file tree
Hide file tree
Showing 8 changed files with 236 additions and 223 deletions.
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.0.6
0.0.7
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ go 1.23.2

require (
github.com/golang/mock v1.6.0
github.com/mattn/go-tty v0.0.7
github.com/mitchellh/mapstructure v1.5.0
github.com/rs/zerolog v1.33.0
github.com/sirupsen/logrus v1.9.3
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-tty v0.0.7 h1:KJ486B6qI8+wBO7kQxYgmmEFDaFEE96JMBQ7h400N8Q=
github.com/mattn/go-tty v0.0.7/go.mod h1:f2i5ZOvXBU/tCABmLmOfzLz9azMo5wdAaElRNnJKr+k=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
Expand Down
22 changes: 12 additions & 10 deletions log/format/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,22 +94,26 @@ const (
var splitRegex = regexp.MustCompile(`[|,:;]`)

// Parse parses the color mode.
func (m ColorModeString) Parse() ColorMode {
func (m ColorModeString) Parse(colorized bool) ColorMode {
mode := ColorUnset
for _, m := range splitRegex.Split(string(m), -1) {
switch ColorModeString(m) {
case ColorModeOff:
mode = ColorOff
case ColorModeOn:
mode = ColorOn
case ColorModeAuto:
mode = ColorAuto
case ColorModeLevels:
mode |= ColorLevels
case ColorModeFields:
mode |= ColorFields
case ColorModeAuto:
fallthrough
default:
mode = ColorDefault
if colorized {
mode = ColorOn
} else {
mode = ColorOff
}
}
}
return mode
Expand All @@ -121,19 +125,17 @@ type ColorMode uint
// Color modes.
const (
// ColorDefault is the default color mode.
ColorDefault = ColorAuto
ColorDefault = ColorOn
// ColorUnset is the unset color mode (activates the default).
ColorUnset ColorMode = 0
// ColorOff disables coloring of logs for all outputs files.
ColorOff ColorMode = 1
// ColorOn enables coloring of logs for all outputs files.
ColorOn ColorMode = 2
// ColorAuto enables the automatic coloring for tty outputs files.
ColorAuto ColorMode = 4
ColorOn ColorMode = ColorFields | ColorLevels
// ColorLevels enables coloring for log levels entries only.
ColorLevels ColorMode = 8
ColorLevels ColorMode = 2
// ColorFields enables coloring for fields names only.
ColorFields ColorMode = 16
ColorFields ColorMode = 4
)

// CheckFlag checks if the given color mode flag is set.
Expand Down
92 changes: 29 additions & 63 deletions log/format/logrus.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,14 @@ package format

import (
"bytes"
"fmt"
"io"
"maps"
"os"
"slices"
"sort"
"strconv"
"sync"

log "github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)

// Pretty formats logs into a pretty format.
Expand All @@ -27,82 +25,34 @@ type Pretty struct {

// LevelNames is defining the names used for marking the different log
// levels.
levelNames []string
LevelNames []string
// LevelColors is defining the colors used for marking the different log
// levels.
levelColors []string

// initOnce is used to initialize the formatter only once.
initOnce sync.Once
}

// Init initializes the pretty formatter.
func (p *Pretty) Init(out io.Writer) *Pretty {
// Set public default fields.
if p.TimeFormat == "" {
p.TimeFormat = DefaultTimeFormat
}
if p.ColorMode == ColorUnset {
p.ColorMode = ColorDefault
}
if p.OrderMode == OrderOff {
p.OrderMode = OrderDefault
}

// Set default level names and colors.
if len(p.levelNames) == 0 {
p.levelNames = DefaultLevelNames
}
if len(p.levelColors) == 0 {
p.levelColors = DefaultLevelColors
}

if p.ColorMode&ColorAuto == ColorAuto {
if IsTerminal(out) {
p.ColorMode |= ColorOn
}
}
if p.ColorMode&ColorOn == ColorOn {
p.ColorMode |= ColorLevels | ColorFields
}
return p
LevelColors []string
}

// Format formats the log entry to a pretty format.
func (p *Pretty) Format(entry *log.Entry) ([]byte, error) {
p.initOnce.Do(func() { p.Init(entry.Logger.Out) })

buffer := NewBuffer(p, &bytes.Buffer{})
buffer.WriteString(entry.Time.Format(p.TimeFormat)).
WriteByte(' ').WriteLevel(entry.Level).WriteCaller(entry).
WriteByte(' ').WriteString(entry.Message)

for _, key := range p.getKeys(entry.Data) {
for _, key := range p.getSortedKeys(entry.Data) {
buffer.WriteByte(' ').WriteData(key, entry.Data[key])
}

return buffer.Bytes()
return buffer.WriteByte('\n').Bytes()
}

// getKeys returns the keys of the given data.
func (p *Pretty) getKeys(data log.Fields) []string {
// getSortedKeys returns the keys of the given data.
func (p *Pretty) getSortedKeys(data log.Fields) []string {
keys := slices.Collect(maps.Keys(data))
if p.OrderMode.CheckFlag(OrderOn) {
sort.Strings(keys)
}
return keys
}

// IsTerminal checks whether the given writer is a terminal.
func IsTerminal(writer io.Writer) bool {
if file, ok := writer.(*os.File); ok {
// #nosec G115 // is a safe conversion for files.
_, err := unix.IoctlGetTermios(int(file.Fd()), unix.TCGETS)
return err == nil
}
return false
}

// Buffer is the interface for writing bytes and strings.
type BufferWriter interface {
// WriteByte writes the given byte to the writer.
Expand Down Expand Up @@ -178,10 +128,10 @@ func (b *Buffer) WriteLevel(level log.Level) *Buffer {
}

if b.pretty.ColorMode.CheckFlag(ColorLevels) {
return b.WriteColored(b.pretty.levelColors[level],
b.pretty.levelNames[level])
return b.WriteColored(b.pretty.LevelColors[level],
b.pretty.LevelNames[level])
}
return b.WriteString(b.pretty.levelNames[level])
return b.WriteString(b.pretty.LevelNames[level])
}

// WriteField writes the given key with the given color to the buffer.
Expand All @@ -191,7 +141,7 @@ func (b *Buffer) WriteField(level log.Level, key string) *Buffer {
}

if b.pretty.ColorMode.CheckFlag(ColorFields) {
return b.WriteColored(b.pretty.levelColors[level], key)
return b.WriteColored(b.pretty.LevelColors[level], key)
}
return b.WriteString(key)
}
Expand All @@ -209,6 +159,22 @@ func (b *Buffer) WriteCaller(entry *log.Entry) *Buffer {
WriteString(caller.Function).WriteByte(']')
}

// WriteString writes the given value to the buffer.
func (b *Buffer) WriteValue(value any) *Buffer {
if b.err != nil {
return b
}

switch value := value.(type) {
case int, int8, int16, int32, int64,
uint, uint8, uint16, uint32, uint64,
float32, float64, complex64, complex128, bool:
return b.WriteString(fmt.Sprint(value))
default:
return b.WriteString(fmt.Sprintf("%q", value))
}
}

// WriteData writes the data to the buffer.
func (b *Buffer) WriteData(key string, value any) *Buffer {
if b.err != nil {
Expand All @@ -218,10 +184,10 @@ func (b *Buffer) WriteData(key string, value any) *Buffer {
switch key {
case log.ErrorKey:
return b.WriteField(log.ErrorLevel, key).
WriteByte('=').WriteString(value.(error).Error())
WriteByte('=').WriteValue(value)
default:
return b.WriteField(FieldLevel, key).
WriteByte('=').WriteString(value.(string))
WriteByte('=').WriteValue(value)
}
}

Expand Down
Loading

0 comments on commit f69dac2

Please sign in to comment.