Fixed logger to properly delete current line before overwriting

This commit is contained in:
bytedream 2022-02-28 17:26:03 +01:00
parent e785cb580b
commit 252762f410

View file

@ -1,19 +1,18 @@
package cmd package cmd
import ( import (
"context"
"fmt" "fmt"
"io" "io"
"log" "log"
"os" "os"
"runtime"
"strings" "strings"
"sync"
"time" "time"
) )
type progress struct { type progress struct {
status bool
message string message string
stop bool
} }
type logger struct { type logger struct {
@ -23,26 +22,21 @@ type logger struct {
devView bool devView bool
progressWG sync.Mutex
progress chan progress progress chan progress
done chan interface{}
} }
func newLogger(debug, info, err bool, color bool) *logger { func newLogger(debug, info, err bool) *logger {
debugLog, infoLog, errLog := log.New(io.Discard, "=> ", 0), log.New(io.Discard, "=> ", 0), log.New(io.Discard, "=> ", 0) debugLog, infoLog, errLog := log.New(io.Discard, "➞ ", 0), log.New(io.Discard, "➞ ", 0), log.New(io.Discard, "➞ ", 0)
debugColor, infoColor, errColor := "", "", ""
if color && runtime.GOOS != "windows" {
debugColor, infoColor, errColor = "\033[95m", "\033[96m", "\033[31m"
}
if debug { if debug {
debugLog.SetOutput(&loggerWriter{original: os.Stdout, color: debugColor}) debugLog.SetOutput(os.Stdout)
} }
if info { if info {
infoLog.SetOutput(&loggerWriter{original: os.Stdout, color: infoColor}) infoLog.SetOutput(os.Stdout)
} }
if err { if err {
errLog.SetOutput(&loggerWriter{original: os.Stdout, color: errColor}) errLog.SetOutput(os.Stderr)
} }
if debug { if debug {
@ -60,140 +54,111 @@ func newLogger(debug, info, err bool, color bool) *logger {
} }
} }
func (l *logger) IsDev() bool {
return l.devView
}
func (l *logger) IsQuiet() bool {
return l.DebugLog.Writer() == io.Discard && l.InfoLog.Writer() == io.Discard && l.ErrLog.Writer() == io.Discard
}
func (l *logger) Debug(format string, v ...interface{}) {
l.DebugLog.Printf(format, v...)
}
func (l *logger) Info(format string, v ...interface{}) {
l.InfoLog.Printf(format, v...)
}
func (l *logger) Err(format string, v ...interface{}) {
l.ErrLog.Printf(format, v...)
}
func (l *logger) Empty() { func (l *logger) Empty() {
if !l.devView && l.InfoLog.Writer() != io.Discard { if l.InfoLog.Writer() != io.Discard {
fmt.Println() fmt.Println("")
} }
} }
func (l *logger) StartProgress(message string) { func (l *logger) SetProgress(format string, v ...interface{}) {
if l.devView { if out.InfoLog.Writer() == io.Discard {
l.InfoLog.Println(message)
return return
} }
message := fmt.Sprintf(format, v...)
if l.progress != nil {
l.progress <- progress{
message: message,
stop: false,
}
return
}
l.progress = make(chan progress) l.progress = make(chan progress)
l.done = make(chan interface{})
go func() { go func() {
states := []string{"-", "\\", "|", "/"} states := []string{"-", "\\", "|", "/"}
var count int
for i := 0; ; i++ { for i := 0; ; i++ {
l.progressWG.Lock() ctx, cancel := context.WithTimeout(context.Background(), 35*time.Millisecond)
select { select {
case p := <-l.progress: case p := <-l.progress:
// clearing the last line cancel()
fmt.Printf("\r%s\r", strings.Repeat(" ", len(l.InfoLog.Prefix())+len(message)+2))
if p.status { if p.stop {
successTag := "✔" if !l.devView {
if runtime.GOOS == "windows" { fmt.Printf("\r" + strings.Repeat(" ", 2+len(message)))
successTag = "~" fmt.Printf("\r➞ %s\n", p.message)
}
l.InfoLog.Printf("%s %s", successTag, p.message)
} else { } else {
errorTag := "✘" l.Debug(message)
if runtime.GOOS == "windows" {
errorTag = "!"
}
l.ErrLog.Printf("%s %s", errorTag, p.message)
} }
l.progress = nil l.progress = nil
l.progressWG.Unlock()
return if count > 0 {
default: fmt.Printf("↳ %s\n", p.message)
if i%10 == 0 { }
fmt.Printf("\r%s%s %s", l.InfoLog.Prefix(), states[i/10%4], message)
l.done <- nil
return
} else {
if !l.devView {
fmt.Printf("\r↓ %s\n", message)
} else {
l.Debug(message)
}
l.progress = make(chan progress)
count++
if !l.devView {
fmt.Printf("\r" + strings.Repeat(" ", 2+len(message)))
fmt.Printf("\r➞ %s\n", p.message)
} else {
l.Debug(p.message)
}
message = p.message
}
case <-ctx.Done():
if !l.devView && i%10 == 0 {
fmt.Printf("\r%s %s", states[i/10%4], message)
} }
time.Sleep(35 * time.Millisecond)
l.progressWG.Unlock()
} }
} }
}() }()
} }
func (l *logger) StartProgressf(message string, a ...interface{}) { func (l *logger) StopProgress(format string, v ...interface{}) {
l.StartProgress(fmt.Sprintf(message, a...)) if out.InfoLog.Writer() == io.Discard {
}
func (l *logger) EndProgress(successful bool, message string) {
if l.devView {
if successful {
l.InfoLog.Print(message)
} else {
l.ErrLog.Print(message)
}
return return
} else if l.progress != nil { }
l.progress <- progress{ l.progress <- progress{
status: successful, message: fmt.Sprintf(format, v...),
message: message, stop: true,
}
} }
} <-l.done
func (l *logger) EndProgressf(successful bool, message string, a ...interface{}) {
l.EndProgress(successful, fmt.Sprintf(message, a...))
}
func (l *logger) Debugln(v ...interface{}) {
l.print(0, v...)
}
func (l *logger) Debugf(message string, a ...interface{}) {
l.print(0, fmt.Sprintf(message, a...))
}
func (l *logger) Infoln(v ...interface{}) {
l.print(1, v...)
}
func (l *logger) Infof(message string, a ...interface{}) {
l.print(1, fmt.Sprintf(message, a...))
}
func (l *logger) Errln(v ...interface{}) {
l.print(2, v...)
}
func (l *logger) Errf(message string, a ...interface{}) {
l.print(2, fmt.Sprintf(message, a...))
}
func (l *logger) Fatalln(v ...interface{}) {
l.print(2, v...)
os.Exit(1)
}
func (l *logger) Fatalf(message string, a ...interface{}) {
l.print(2, fmt.Sprintf(message, a...))
os.Exit(1)
}
func (l *logger) print(level int, v ...interface{}) {
if l.progress != nil {
l.progressWG.Lock()
defer l.progressWG.Unlock()
fmt.Print("\r")
}
switch level {
case 0:
l.DebugLog.Print(v...)
case 1:
l.InfoLog.Print(v...)
case 2:
l.ErrLog.Print(v...)
}
}
type loggerWriter struct {
io.Writer
original io.Writer
color string
}
func (lw *loggerWriter) Write(p []byte) (n int, err error) {
if lw.color != "" {
p = append([]byte(lw.color), p...)
p = append(p, []byte("\033[0m")...)
}
return lw.original.Write(p)
} }