From 1f6c7dd5f695f48037d12c6f4fc73c15cac1a136 Mon Sep 17 00:00:00 2001 From: Serge Smertin Date: Fri, 28 Apr 2023 20:04:40 +0200 Subject: [PATCH 1/3] Add readable console logger some fixes --- cmd/root/logger.go | 77 +++++++++++++++++++++++++++++++++++++++++----- libs/cmdio/io.go | 10 ++++++ 2 files changed, 79 insertions(+), 8 deletions(-) diff --git a/cmd/root/logger.go b/cmd/root/logger.go index 37a053370f..90429e7fc9 100644 --- a/cmd/root/logger.go +++ b/cmd/root/logger.go @@ -3,10 +3,13 @@ package root import ( "context" "fmt" + "io" "os" + "github.com/databricks/bricks/libs/cmdio" "github.com/databricks/cli/libs/flags" "github.com/databricks/cli/libs/log" + "github.com/fatih/color" "golang.org/x/exp/slog" ) @@ -16,6 +19,69 @@ const ( envLogFormat = "DATABRICKS_LOG_FORMAT" ) +type friendlyHandler struct { + slog.Handler + w io.Writer +} + +var ( + levelDebug = color.New(color.FgYellow).Sprint("DEBUG") + levelInfo = color.New(color.FgGreen).Sprint(" INFO") // space in front is not a typo + levelWarn = color.New(color.FgMagenta).Sprint(" WARN") // space in front is not a typo + levelError = color.New(color.FgRed).Sprint("ERROR") +) + +func (l *friendlyHandler) coloredLevel(rec slog.Record) string { + switch rec.Level { + case slog.LevelDebug: + return levelDebug + case slog.LevelInfo: + return levelInfo + case slog.LevelWarn: + return levelWarn + case log.LevelError: + return levelError + } + return "" +} + +func (l *friendlyHandler) Handle(ctx context.Context, rec slog.Record) error { + t := fmt.Sprintf("%02d:%02d", rec.Time.Hour(), rec.Time.Minute()) + attrs := "" + rec.Attrs(func(a slog.Attr) { + attrs += fmt.Sprintf(" %s%s%s", + color.CyanString(a.Key), + color.CyanString("="), + color.YellowString(a.Value.String())) + }) + msg := fmt.Sprintf("%s %s %s%s\n", + color.MagentaString(t), + l.coloredLevel(rec), + color.HiWhiteString(rec.Message), + attrs) + _, err := l.w.Write([]byte(msg)) + return err +} + +func makeLogHandler(opts slog.HandlerOptions) (slog.Handler, error) { + switch logOutput { + case flags.OutputJSON: + return opts.NewJSONHandler(logFile.Writer()), nil + case flags.OutputText: + w := logFile.Writer() + if cmdio.IsTTY(w) { + return &friendlyHandler{ + Handler: opts.NewTextHandler(w), + w: w, + }, nil + } + return opts.NewTextHandler(w), nil + + default: + return nil, fmt.Errorf("invalid log output mode: %s", logOutput) + } +} + func initializeLogger(ctx context.Context) (context.Context, error) { opts := slog.HandlerOptions{} opts.Level = logLevel.Level() @@ -31,14 +97,9 @@ func initializeLogger(ctx context.Context) (context.Context, error) { return nil, err } - var handler slog.Handler - switch logOutput { - case flags.OutputJSON: - handler = opts.NewJSONHandler(logFile.Writer()) - case flags.OutputText: - handler = opts.NewTextHandler(logFile.Writer()) - default: - return nil, fmt.Errorf("invalid log output: %s", logOutput) + handler, err := makeLogHandler(opts) + if err != nil { + return nil, err } slog.SetDefault(slog.New(handler)) diff --git a/libs/cmdio/io.go b/libs/cmdio/io.go index 223610b2c3..beaa85717f 100644 --- a/libs/cmdio/io.go +++ b/libs/cmdio/io.go @@ -46,6 +46,16 @@ func IsInteractive(ctx context.Context) bool { return c.interactive } +// IsTTY detects if io.Writer is a terminal. +func IsTTY(w io.Writer) bool { + f, ok := w.(*os.File) + if !ok { + return false + } + fd := f.Fd() + return isatty.IsTerminal(fd) || isatty.IsCygwinTerminal(fd) +} + // IsTTY detects if stdout is a terminal. It assumes that stderr is terminal as well func (c *cmdIO) IsTTY() bool { f, ok := c.out.(*os.File) From e8411e83a1630ee3dfcfb660f734faf6cb632b86 Mon Sep 17 00:00:00 2001 From: Serge Smertin Date: Tue, 23 May 2023 00:23:51 +0200 Subject: [PATCH 2/3] fix --- cmd/root/logger.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/root/logger.go b/cmd/root/logger.go index 90429e7fc9..7c6dbc0c3d 100644 --- a/cmd/root/logger.go +++ b/cmd/root/logger.go @@ -6,7 +6,7 @@ import ( "io" "os" - "github.com/databricks/bricks/libs/cmdio" + "github.com/databricks/cli/libs/cmdio" "github.com/databricks/cli/libs/flags" "github.com/databricks/cli/libs/log" "github.com/fatih/color" From a37064301a79b7ad1b694dc53600e0e775e96465 Mon Sep 17 00:00:00 2001 From: Serge Smertin Date: Thu, 1 Jun 2023 11:03:28 +0200 Subject: [PATCH 3/3] addressed review comments --- cmd/root/logger.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cmd/root/logger.go b/cmd/root/logger.go index 7c6dbc0c3d..1a815632f6 100644 --- a/cmd/root/logger.go +++ b/cmd/root/logger.go @@ -25,14 +25,17 @@ type friendlyHandler struct { } var ( + levelTrace = color.New(color.FgYellow).Sprint("TRACE") levelDebug = color.New(color.FgYellow).Sprint("DEBUG") - levelInfo = color.New(color.FgGreen).Sprint(" INFO") // space in front is not a typo - levelWarn = color.New(color.FgMagenta).Sprint(" WARN") // space in front is not a typo + levelInfo = color.New(color.FgGreen).Sprintf("%5s", "INFO") + levelWarn = color.New(color.FgMagenta).Sprintf("%5s", "WARN") levelError = color.New(color.FgRed).Sprint("ERROR") ) func (l *friendlyHandler) coloredLevel(rec slog.Record) string { switch rec.Level { + case log.LevelTrace: + return levelTrace case slog.LevelDebug: return levelDebug case slog.LevelInfo: