mirror of https://github.com/databricks/cli.git
Add readable console logger (#370)
## Changes Add a readable colored console logger that is active only for TTYs: <img width="764" alt="image" src="https://user-images.githubusercontent.com/259697/235221427-ca482b32-9f88-4adb-ada3-8c4f35f50f06.png"> ## Tests Run `go run main.go clusters list --log-level debug --profile demo`
This commit is contained in:
parent
d44d8ff2dc
commit
24ebfdf31e
|
@ -3,10 +3,13 @@ package root
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/databricks/cli/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,72 @@ const (
|
|||
envLogFormat = "DATABRICKS_LOG_FORMAT"
|
||||
)
|
||||
|
||||
type friendlyHandler struct {
|
||||
slog.Handler
|
||||
w io.Writer
|
||||
}
|
||||
|
||||
var (
|
||||
levelTrace = color.New(color.FgYellow).Sprint("TRACE")
|
||||
levelDebug = color.New(color.FgYellow).Sprint("DEBUG")
|
||||
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:
|
||||
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 +100,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))
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue