From bd29a9c5bb8846671b1b22e7cd4b9826cb140dc3 Mon Sep 17 00:00:00 2001 From: Callum Styan Date: Fri, 22 Dec 2017 11:38:13 -0800 Subject: [PATCH 1/3] Add color logging capabilities for promlog Cherry-pick color logging functionality from #113. Signed-off-by: SuperQ --- promlog/log.go | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/promlog/log.go b/promlog/log.go index 35e95c893..0751b396d 100644 --- a/promlog/log.go +++ b/promlog/log.go @@ -24,6 +24,7 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" + "github.com/go-kit/log/term" ) var ( @@ -60,6 +61,25 @@ func (l *AllowedLevel) UnmarshalYAML(unmarshal func(interface{}) error) error { return nil } +func colorFn(keyvals ...interface{}) term.FgBgColor { + for i := 1; i < len(keyvals); i += 2 { + if keyvals[i] != "level" { + continue + } + switch keyvals[i+1] { + case "debug": + return term.FgBgColor{Fg: term.Blue} + case "warn": + return term.FgBgColor{Fg: term.Yellow} + case "error": + return term.FgBgColor{Fg: term.Red} + default: + return term.FgBgColor{} + } + } + return term.FgBgColor{} +} + func (l *AllowedLevel) String() string { return l.s } @@ -112,10 +132,13 @@ type Config struct { // with a timestamp. The output always goes to stderr. func New(config *Config) log.Logger { var l log.Logger + syncWriter := log.NewSyncWriter(os.Stderr) if config.Format != nil && config.Format.s == "json" { - l = log.NewJSONLogger(log.NewSyncWriter(os.Stderr)) + l = log.NewJSONLogger(syncWriter) } else { - l = log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr)) + // Returns a new logger with color logging capabilites if we're in a terminal, otherwise we + // just get a standard go-kit logger. + l = term.NewLogger(syncWriter, log.NewLogfmtLogger, colorFn) } if config.Level != nil { From 458340bc1c8feb6ff88e3f05a357d25597cc1ad1 Mon Sep 17 00:00:00 2001 From: SuperQ Date: Sat, 25 Feb 2023 12:57:58 +0100 Subject: [PATCH 2/3] Add config / flag for color. Signed-off-by: SuperQ --- promlog/flag/flag.go | 10 ++++++++ promlog/log.go | 57 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 62 insertions(+), 5 deletions(-) diff --git a/promlog/flag/flag.go b/promlog/flag/flag.go index ec55008b8..9a0c831ec 100644 --- a/promlog/flag/flag.go +++ b/promlog/flag/flag.go @@ -18,6 +18,12 @@ import ( kingpin "gopkg.in/alecthomas/kingpin.v2" ) +// ColorFlagName is the canonical flag name to enable color logging. +const ColorFlagName = "log.color" + +// ColorFlagHelp is the help description for the log.color flag. +const ColorFlagHelp = "Enable colors in the console log. Use --no-log.color to disable." + // LevelFlagName is the canonical flag name to configure the allowed log level // within Prometheus projects. const LevelFlagName = "log.level" @@ -35,6 +41,10 @@ const FormatFlagHelp = "Output format of log messages. One of: [logfmt, json]" // AddFlags adds the flags used by this package to the Kingpin application. // To use the default Kingpin application, call AddFlags(kingpin.CommandLine) func AddFlags(a *kingpin.Application, config *promlog.Config) { + config.Color = &promlog.Color{} + a.Flag(ColorFlagName, ColorFlagHelp). + Default("true").SetValue(config.Color) + config.Level = &promlog.AllowedLevel{} a.Flag(LevelFlagName, LevelFlagHelp). Default("info").SetValue(config.Level) diff --git a/promlog/log.go b/promlog/log.go index 0751b396d..7eeef6855 100644 --- a/promlog/log.go +++ b/promlog/log.go @@ -19,6 +19,7 @@ package promlog import ( "fmt" "os" + "strconv" "sync" "time" @@ -37,6 +38,33 @@ var ( ) ) +// Color is a settable boolean for controlling color output. +type Color struct { + s string + enabled bool +} + +func (c *Color) Set(s string) error { + switch s { + case "true": + c.enabled = true + case "false": + c.enabled = false + default: + return fmt.Errorf("unrecognized boolean %q", s) + } + c.s = s + return nil +} + +func (c *Color) Enabled() bool { + return c.enabled +} + +func (c *Color) String() string { + return strconv.FormatBool(c.enabled) +} + // AllowedLevel is a settable identifier for the minimum level a log entry // must be have. type AllowedLevel struct { @@ -124,6 +152,7 @@ func (f *AllowedFormat) Set(s string) error { // Config is a struct containing configurable settings for the logger type Config struct { + Color *Color Level *AllowedLevel Format *AllowedFormat } @@ -131,14 +160,21 @@ type Config struct { // New returns a new leveled oklog logger. Each logged line will be annotated // with a timestamp. The output always goes to stderr. func New(config *Config) log.Logger { + if config.Color == nil { + config.Color = &Color{s: "true", enabled: true} + } var l log.Logger syncWriter := log.NewSyncWriter(os.Stderr) if config.Format != nil && config.Format.s == "json" { l = log.NewJSONLogger(syncWriter) } else { - // Returns a new logger with color logging capabilites if we're in a terminal, otherwise we - // just get a standard go-kit logger. - l = term.NewLogger(syncWriter, log.NewLogfmtLogger, colorFn) + if config.Color.Enabled() { + // Returns a new logger with color logging capabilites if we're in a terminal, otherwise we + // just get a standard go-kit logger. + l = term.NewLogger(syncWriter, log.NewLogfmtLogger, colorFn) + } else { + l = log.NewJSONLogger(syncWriter) + } } if config.Level != nil { @@ -154,11 +190,22 @@ func New(config *Config) log.Logger { // with a timestamp. The output always goes to stderr. Some properties can be // changed, like the level. func NewDynamic(config *Config) *logger { + if config.Color == nil { + config.Color = &Color{s: "true", enabled: true} + } var l log.Logger + syncWriter := log.NewSyncWriter(os.Stderr) + if config.Format != nil && config.Format.s == "json" { - l = log.NewJSONLogger(log.NewSyncWriter(os.Stderr)) + l = log.NewJSONLogger(syncWriter) } else { - l = log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr)) + if config.Color.Enabled() { + // Returns a new logger with color logging capabilites if we're in a terminal, otherwise we + // just get a standard go-kit logger. + l = term.NewLogger(syncWriter, log.NewLogfmtLogger, colorFn) + } else { + l = log.NewJSONLogger(syncWriter) + } } lo := &logger{ From 9a047ac721ffd8db9ee3c19b51fb73701e21bf65 Mon Sep 17 00:00:00 2001 From: SuperQ Date: Sat, 25 Feb 2023 16:09:16 +0100 Subject: [PATCH 3/3] Green for info. Signed-off-by: SuperQ --- promlog/log.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/promlog/log.go b/promlog/log.go index 7eeef6855..54f2395d0 100644 --- a/promlog/log.go +++ b/promlog/log.go @@ -95,6 +95,8 @@ func colorFn(keyvals ...interface{}) term.FgBgColor { continue } switch keyvals[i+1] { + case "info": + return term.FgBgColor{Fg: term.Green} case "debug": return term.FgBgColor{Fg: term.Blue} case "warn":