Skip to content

Commit

Permalink
fix tests after refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
aybabtme authored and Antoine Grondin committed Sep 15, 2022
1 parent 2ba4ea1 commit 130ca65
Show file tree
Hide file tree
Showing 17 changed files with 529 additions and 496 deletions.
27 changes: 6 additions & 21 deletions cmd/humanlog/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ import (
"os/signal"

"github.com/aybabtme/rgbterm"
"github.com/fatih/color"
"github.com/humanlogio/humanlog"
"github.com/humanlogio/humanlog/internal/pkg/config"
"github.com/humanlogio/humanlog/internal/pkg/sink"
"github.com/humanlogio/humanlog/internal/pkg/sink/stdiosink"
"github.com/mattn/go-colorable"
"github.com/urfave/cli"
)
Expand Down Expand Up @@ -82,7 +81,7 @@ func newApp() *cli.App {
colorFlag := cli.StringFlag{
Name: "color",
Usage: "specify color mode: auto, on/force, off",
Value: *config.DefaultConfig.ColorFlag,
Value: stdiosink.DefaultStdioOpts.ColorFlag,
}

lightBg := cli.BoolFlag{
Expand All @@ -93,7 +92,7 @@ func newApp() *cli.App {
timeFormat := cli.StringFlag{
Name: "time-format",
Usage: "output time format, see https://golang.org/pkg/time/ for details",
Value: sink.DefaultStdioOpts.TimeFormat,
Value: stdiosink.DefaultStdioOpts.TimeFormat,
}

ignoreInterrupts := cli.BoolFlag{
Expand Down Expand Up @@ -178,7 +177,7 @@ func newApp() *cli.App {
cfg.TimeFormat = ptr(c.String(timeFormat.Name))
}
if c.IsSet(colorFlag.Name) {
cfg.ColorFlag = ptr(c.String(colorFlag.Name))
cfg.ColorMode = ptr(c.String(colorFlag.Name))
}
if c.IsSet(skipFlag.Name) {
cfg.Skip = ptr([]string(skip))
Expand Down Expand Up @@ -207,31 +206,17 @@ func newApp() *cli.App {
signal.Ignore(os.Interrupt)
}

colorMode, err := config.GrokColorMode(*cfg.ColorFlag)
if err != nil {
return fmt.Errorf("invalid --color=%q: %v", *cfg.ColorFlag, err)
}
switch colorMode {
case config.ColorModeOff:
color.NoColor = true
case config.ColorModeOn:
color.NoColor = false
default:
// 'Auto' default is applied as a global variable initializer function, so nothing
// to do here.
}

if len(*cfg.Skip) > 0 && len(*cfg.Keep) > 0 {
fatalf(c, "can only use one of %q and %q", skipFlag.Name, keepFlag.Name)
}

sinkOpts, errs := sink.StdioOptsFrom(*cfg)
sinkOpts, errs := stdiosink.StdioOptsFrom(*cfg)
if len(errs) > 0 {
for _, err := range errs {
log.Printf("config error: %v", err)
}
}
sink := sink.NewStdio(colorable.NewColorableStdout(), sinkOpts)
sink := stdiosink.NewStdio(colorable.NewColorableStdout(), sinkOpts)
handlerOpts := humanlog.HandlerOptionsFrom(*cfg)

log.Print("reading stdin...")
Expand Down
6 changes: 3 additions & 3 deletions e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"testing"

"github.com/humanlogio/humanlog/internal/pkg/config"
"github.com/humanlogio/humanlog/internal/pkg/sink"
"github.com/humanlogio/humanlog/internal/pkg/sink/stdiosink"
)

func TestHarness(t *testing.T) {
Expand Down Expand Up @@ -42,11 +42,11 @@ func TestHarness(t *testing.T) {
t.Fatalf("unmarshaling config: %v", err)
}
gotw := bytes.NewBuffer(nil)
sinkOpts, errs := sink.StdioOptsFrom(cfg)
sinkOpts, errs := stdiosink.StdioOptsFrom(cfg)
if len(errs) > 1 {
t.Fatalf("errs=%v", errs)
}
s := sink.NewStdio(gotw, sinkOpts)
s := stdiosink.NewStdio(gotw, sinkOpts)
err = Scanner(bytes.NewReader(input), s, HandlerOptionsFrom(cfg))
if err != nil {
t.Fatalf("scanning input: %v", err)
Expand Down
8 changes: 4 additions & 4 deletions internal/pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ var DefaultConfig = Config{
SkipUnchanged: ptr(true),
Truncates: ptr(true),
LightBg: ptr(false),
ColorFlag: ptr("auto"),
ColorMode: ptr("auto"),
TruncateLength: ptr(15),
TimeFormat: ptr(time.Stamp),
Interrupt: ptr(false),
Expand Down Expand Up @@ -94,7 +94,7 @@ type Config struct {
SkipUnchanged *bool `json:"skip-unchanged"`
Truncates *bool `json:"truncates"`
LightBg *bool `json:"light-bg"`
ColorFlag *string `json:"color-mode"`
ColorMode *string `json:"color-mode"`
TruncateLength *int `json:"truncate-length"`
TimeFormat *string `json:"time-format"`
Palette *TextPalette `json:"palette"`
Expand Down Expand Up @@ -130,8 +130,8 @@ func (cfg Config) populateEmpty(other *Config) *Config {
if out.LightBg == nil && other.LightBg != nil {
out.LightBg = other.LightBg
}
if out.ColorFlag == nil && other.ColorFlag != nil {
out.ColorFlag = other.ColorFlag
if out.ColorMode == nil && other.ColorMode != nil {
out.ColorMode = other.ColorMode
}
if out.TruncateLength == nil && other.TruncateLength != nil {
out.TruncateLength = other.TruncateLength
Expand Down
254 changes: 1 addition & 253 deletions internal/pkg/sink/stdio.go → internal/pkg/sink/stdiosink/colors.go
Original file line number Diff line number Diff line change
@@ -1,240 +1,12 @@
package sink
package stdiosink

import (
"bytes"
"fmt"
"io"
"sort"
"strings"
"text/tabwriter"
"time"

"github.com/fatih/color"
"github.com/humanlogio/humanlog/internal/pkg/config"
"github.com/humanlogio/humanlog/internal/pkg/model"
)

var (
eol = [...]byte{'\n'}
)

type Stdio struct {
w io.Writer
opts StdioOpts

lastEvent *model.Event
lastKVs map[string]string
}

type StdioOpts struct {
Skip map[string]struct{}
Keep map[string]struct{}
SkipUnchanged bool
SortLongest bool
TimeFormat string
Truncates bool
TruncateLength int

LightBg bool
Palette Palette
}

var DefaultStdioOpts = StdioOpts{
SkipUnchanged: true,
SortLongest: true,
Truncates: true,
LightBg: false,
TruncateLength: 15,
TimeFormat: time.Stamp,

Palette: DefaultPalette,
}

func StdioOptsFrom(cfg config.Config) (StdioOpts, []error) {
var errs []error
opts := DefaultStdioOpts
if cfg.Skip != nil {
opts.Skip = sliceToSet(cfg.Skip)
}
if cfg.Keep != nil {
opts.Keep = sliceToSet(cfg.Keep)
}
if cfg.SortLongest != nil {
opts.SortLongest = *cfg.SortLongest
}
if cfg.SkipUnchanged != nil {
opts.SkipUnchanged = *cfg.SkipUnchanged
}
if cfg.Truncates != nil {
opts.Truncates = *cfg.Truncates
}
if cfg.LightBg != nil {
opts.LightBg = *cfg.LightBg
}
if cfg.TruncateLength != nil {
opts.TruncateLength = *cfg.TruncateLength
}
if cfg.TimeFormat != nil {
opts.TimeFormat = *cfg.TimeFormat
}
if cfg.Palette != nil {
pl, err := PaletteFrom(*cfg.Palette)
if err != nil {
errs = append(errs, fmt.Errorf("invalid palette, using default one: %v", err))
} else {
opts.Palette = *pl
}
}
return opts, errs
}

var _ Sink = (*Stdio)(nil)

func NewStdio(w io.Writer, opts StdioOpts) *Stdio {
return &Stdio{
w: w,
opts: opts,
}
}

func (std *Stdio) Receive(ev *model.Event) error {
if ev.Structured == nil {
if _, err := std.w.Write(ev.Raw); err != nil {
return err
}
return nil
}
data := ev.Structured

buf := bytes.NewBuffer(nil)
out := tabwriter.NewWriter(buf, 0, 1, 0, '\t', 0)

var (
msgColor *color.Color
msgAbsentColor *color.Color
)
if std.opts.LightBg {
msgColor = std.opts.Palette.MsgLightBgColor
msgAbsentColor = std.opts.Palette.MsgAbsentLightBgColor
} else {
msgColor = std.opts.Palette.MsgDarkBgColor
msgAbsentColor = std.opts.Palette.MsgAbsentDarkBgColor
}
var msg string
if data.Msg == "" {
msg = msgAbsentColor.Sprint("<no msg>")
} else {
msg = msgColor.Sprint(data.Msg)
}

lvl := strings.ToUpper(data.Level)[:imin(4, len(data.Level))]
var level string
switch data.Level {
case "debug":
level = std.opts.Palette.DebugLevelColor.Sprint(lvl)
case "info":
level = std.opts.Palette.InfoLevelColor.Sprint(lvl)
case "warn", "warning":
level = std.opts.Palette.WarnLevelColor.Sprint(lvl)
case "error":
level = std.opts.Palette.ErrorLevelColor.Sprint(lvl)
case "fatal", "panic":
level = std.opts.Palette.FatalLevelColor.Sprint(lvl)
default:
level = std.opts.Palette.UnknownLevelColor.Sprint(lvl)
}

var timeColor *color.Color
if std.opts.LightBg {
timeColor = std.opts.Palette.TimeLightBgColor
} else {
timeColor = std.opts.Palette.TimeDarkBgColor
}

_, _ = fmt.Fprintf(out, "%s |%s| %s\t %s",
timeColor.Sprint(data.Time.Format(std.opts.TimeFormat)),
level,
msg,
strings.Join(std.joinKVs(data, "="), "\t "),
)

if err := out.Flush(); err != nil {
return err
}

buf.Write(eol[:])

if _, err := buf.WriteTo(std.w); err != nil {
return err
}

kvs := make(map[string]string, len(data.KVs))
for _, kv := range data.KVs {
kvs[kv.Key] = kv.Value
}
std.lastEvent = ev
std.lastKVs = kvs
return nil
}

func (std *Stdio) joinKVs(data *model.Structured, sep string) []string {

kv := make([]string, 0, len(data.KVs))
for _, pair := range data.KVs {
k, v := pair.Key, pair.Value
if !std.opts.shouldShowKey(k) {
continue
}

if std.opts.SkipUnchanged {
if lastV, ok := std.lastKVs[k]; ok && lastV == v && !std.opts.shouldShowUnchanged(k) {
continue
}
}
kstr := std.opts.Palette.KeyColor.Sprint(k)

var vstr string
if std.opts.Truncates && len(v) > std.opts.TruncateLength {
vstr = v[:std.opts.TruncateLength] + "..."
} else {
vstr = v
}
vstr = std.opts.Palette.ValColor.Sprint(vstr)
kv = append(kv, kstr+sep+vstr)
}

sort.Strings(kv)

if std.opts.SortLongest {
sort.Stable(byLongest(kv))
}

return kv
}

func (opts *StdioOpts) shouldShowKey(key string) bool {
if len(opts.Keep) != 0 {
if _, keep := opts.Keep[key]; keep {
return true
}
}
if len(opts.Skip) != 0 {
if _, skip := opts.Skip[key]; skip {
return false
}
}
return true
}

func (opts *StdioOpts) shouldShowUnchanged(key string) bool {
if len(opts.Keep) != 0 {
if _, keep := opts.Keep[key]; keep {
return true
}
}
return false
}

var DefaultPalette = Palette{
KeyColor: color.New(color.FgGreen),
ValColor: color.New(color.FgHiWhite),
Expand Down Expand Up @@ -383,27 +155,3 @@ var colorAttributeIndex = map[string]color.Attribute{
"bg_hi_cyan": color.BgHiCyan,
"bg_hi_white": color.BgHiWhite,
}

type byLongest []string

func (s byLongest) Len() int { return len(s) }
func (s byLongest) Less(i, j int) bool { return len(s[i]) < len(s[j]) }
func (s byLongest) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

func imin(a, b int) int {
if a < b {
return a
}
return b
}

func sliceToSet(arr *[]string) map[string]struct{} {
if arr == nil {
return nil
}
out := make(map[string]struct{})
for _, key := range *arr {
out[key] = struct{}{}
}
return out
}
Loading

0 comments on commit 130ca65

Please sign in to comment.