lmittmann/tint

Suggestion: Option to use color emojis when no color is available

iamcalledrob opened this issue · 1 comments

I'm using this package (thank you!) to log in an environment that doesn't support color (Xcode), but where I still want to easily glance at the error types.

Currently I've hacked this functionality into place:

// Injects emojis when standard levels are not colored
type emojiLevelWriter struct {
	w io.Writer
}

func (e *emojiLevelWriter) Write(b []byte) (int, error) {
	s := string(b)
	s = strings.Replace(s, " DBG", " ⬜️ DBG", 1)
	s = strings.Replace(s, " INF", " 🟩 INF", 1)
	s = strings.Replace(s, " WRN", " 🟨 WRN", 1)
	s = strings.Replace(s, " ERR", " 🟪️ ERR", 1)
	_, err := e.w.Write([]byte(s))
	return len(s), err
}

// Usage
// (sidenote: github.com/jwalton/go-supportscolor more accurately detects color capabilities than isatty)
h := tint.NewHandler(&emojiLevelWriter{w}, &tint.Options{
	AddSource: false,
	Level:     level,
	NoColor:   !supportscolor.Stderr().SupportsColor,
}),

But it'd be nice if this was built-in functionality -- and it seems aligned with the spirit of this package.
I'd propose the Options struct having an Emoji property (default = false):

type Options struct {
	...

	// Disable color (Default: false)
	NoColor bool

	// Enable emoji with levels (Default: false)
	Emoji bool
}

Alternatively, exposing the level strings somewhere (e.g. as package vars) would also work.

Thoughts?

Hi @iamcalledrob. You can customize the level string using the ReplaceAttr Option:

logger := slog.New(tint.NewHandler(os.Stderr, &tint.Options{
    ReplaceAttr: func(groups []string, attr slog.Attr) slog.Attr {
        if len(groups) == 0 && attr.Key == slog.LevelKey {
            var lvl string
            // ... create the custom level string
            return slog.String(slog.LevelKey, lvl)
        }
        return attr
    },
}))