chore: update build and tui assets

This commit is contained in:
2025-10-24 15:43:27 +00:00
parent 9b3c3f2b1b
commit 4e281cff01
31 changed files with 2456 additions and 571 deletions

View File

@ -3,10 +3,11 @@ package logger
import (
"fmt"
"io"
"log/slog"
"os"
"strings"
"time"
"github.com/sirupsen/logrus"
)
// Logger defines the interface for logging
@ -16,7 +17,7 @@ type Logger interface {
Warn(msg string, args ...any)
Error(msg string, args ...any)
Time(msg string, args ...any)
// Progress logging for operations
StartOperation(name string) OperationLogger
}
@ -28,10 +29,10 @@ type OperationLogger interface {
Fail(msg string, args ...any)
}
// logger implements Logger interface using slog
// logger implements Logger interface using logrus
type logger struct {
slog *slog.Logger
level slog.Level
logrus *logrus.Logger
level logrus.Level
format string
}
@ -44,58 +45,57 @@ type operationLogger struct {
// New creates a new logger
func New(level, format string) Logger {
var slogLevel slog.Level
var logLevel logrus.Level
switch strings.ToLower(level) {
case "debug":
slogLevel = slog.LevelDebug
logLevel = logrus.DebugLevel
case "info":
slogLevel = slog.LevelInfo
logLevel = logrus.InfoLevel
case "warn", "warning":
slogLevel = slog.LevelWarn
logLevel = logrus.WarnLevel
case "error":
slogLevel = slog.LevelError
logLevel = logrus.ErrorLevel
default:
slogLevel = slog.LevelInfo
logLevel = logrus.InfoLevel
}
var handler slog.Handler
opts := &slog.HandlerOptions{
Level: slogLevel,
}
l := logrus.New()
l.SetLevel(logLevel)
l.SetOutput(os.Stdout)
switch strings.ToLower(format) {
case "json":
handler = slog.NewJSONHandler(os.Stdout, opts)
l.SetFormatter(&logrus.JSONFormatter{})
default:
handler = slog.NewTextHandler(os.Stdout, opts)
l.SetFormatter(&logrus.TextFormatter{FullTimestamp: true})
}
return &logger{
slog: slog.New(handler),
level: slogLevel,
logrus: l,
level: logLevel,
format: format,
}
}
func (l *logger) Debug(msg string, args ...any) {
l.slog.Debug(msg, args...)
l.logWithFields(logrus.DebugLevel, msg, args...)
}
func (l *logger) Info(msg string, args ...any) {
l.slog.Info(msg, args...)
l.logWithFields(logrus.InfoLevel, msg, args...)
}
func (l *logger) Warn(msg string, args ...any) {
l.slog.Warn(msg, args...)
l.logWithFields(logrus.WarnLevel, msg, args...)
}
func (l *logger) Error(msg string, args ...any) {
l.slog.Error(msg, args...)
l.logWithFields(logrus.ErrorLevel, msg, args...)
}
func (l *logger) Time(msg string, args ...any) {
// Time logs are always at info level with special formatting
l.slog.Info("[TIME] "+msg, args...)
l.logWithFields(logrus.InfoLevel, "[TIME] "+msg, args...)
}
func (l *logger) StartOperation(name string) OperationLogger {
@ -108,22 +108,63 @@ func (l *logger) StartOperation(name string) OperationLogger {
func (ol *operationLogger) Update(msg string, args ...any) {
elapsed := time.Since(ol.startTime)
ol.parent.Info(fmt.Sprintf("[%s] %s", ol.name, msg),
ol.parent.Info(fmt.Sprintf("[%s] %s", ol.name, msg),
append(args, "elapsed", elapsed.String())...)
}
func (ol *operationLogger) Complete(msg string, args ...any) {
elapsed := time.Since(ol.startTime)
ol.parent.Info(fmt.Sprintf("[%s] COMPLETED: %s", ol.name, msg),
ol.parent.Info(fmt.Sprintf("[%s] COMPLETED: %s", ol.name, msg),
append(args, "duration", formatDuration(elapsed))...)
}
func (ol *operationLogger) Fail(msg string, args ...any) {
elapsed := time.Since(ol.startTime)
ol.parent.Error(fmt.Sprintf("[%s] FAILED: %s", ol.name, msg),
ol.parent.Error(fmt.Sprintf("[%s] FAILED: %s", ol.name, msg),
append(args, "duration", formatDuration(elapsed))...)
}
// logWithFields forwards log messages with structured fields to logrus
func (l *logger) logWithFields(level logrus.Level, msg string, args ...any) {
if l == nil || l.logrus == nil {
return
}
fields := fieldsFromArgs(args...)
entry := l.logrus.WithFields(fields)
switch level {
case logrus.DebugLevel:
entry.Debug(msg)
case logrus.WarnLevel:
entry.Warn(msg)
case logrus.ErrorLevel:
entry.Error(msg)
default:
entry.Info(msg)
}
}
// fieldsFromArgs converts variadic key/value pairs into logrus fields
func fieldsFromArgs(args ...any) logrus.Fields {
fields := logrus.Fields{}
for i := 0; i < len(args); {
if i+1 < len(args) {
if key, ok := args[i].(string); ok {
fields[key] = args[i+1]
i += 2
continue
}
}
fields[fmt.Sprintf("arg%d", i)] = args[i]
i++
}
return fields
}
// formatDuration formats duration in human-readable format
func formatDuration(d time.Duration) string {
if d < time.Minute {
@ -142,18 +183,18 @@ func formatDuration(d time.Duration) string {
// FileLogger creates a logger that writes to both stdout and a file
func FileLogger(level, format, filename string) (Logger, error) {
var slogLevel slog.Level
var logLevel logrus.Level
switch strings.ToLower(level) {
case "debug":
slogLevel = slog.LevelDebug
logLevel = logrus.DebugLevel
case "info":
slogLevel = slog.LevelInfo
logLevel = logrus.InfoLevel
case "warn", "warning":
slogLevel = slog.LevelWarn
logLevel = logrus.WarnLevel
case "error":
slogLevel = slog.LevelError
logLevel = logrus.ErrorLevel
default:
slogLevel = slog.LevelInfo
logLevel = logrus.InfoLevel
}
// Open log file
@ -165,21 +206,20 @@ func FileLogger(level, format, filename string) (Logger, error) {
// Create multi-writer (stdout + file)
multiWriter := io.MultiWriter(os.Stdout, file)
var handler slog.Handler
opts := &slog.HandlerOptions{
Level: slogLevel,
}
l := logrus.New()
l.SetLevel(logLevel)
l.SetOutput(multiWriter)
switch strings.ToLower(format) {
case "json":
handler = slog.NewJSONHandler(multiWriter, opts)
l.SetFormatter(&logrus.JSONFormatter{})
default:
handler = slog.NewTextHandler(multiWriter, opts)
l.SetFormatter(&logrus.TextFormatter{FullTimestamp: true})
}
return &logger{
slog: slog.New(handler),
level: slogLevel,
logrus: l,
level: logLevel,
format: format,
}, nil
}
}