feat: update logging style & formatting

This commit is contained in:
2026-01-22 20:13:58 +02:00
parent 88c3e2be39
commit 0cbf174850
5 changed files with 85 additions and 43 deletions

View File

@@ -39,7 +39,7 @@ func (i *GroupInstaller) Validate() []ValidationError {
func (i *GroupInstaller) Install() error {
info := i.GetData()
name := *info.Name
logger.Debug("Installing group %s", name)
logger.Debug("Installing group %s", logger.H(name))
i.childResults = []summary.InstallResult{}
for _, step := range *i.Data.Steps {
installer, err := GetInstaller(i.Config, &step)
@@ -47,11 +47,11 @@ func (i *GroupInstaller) Install() error {
return err
}
if installer == nil {
logger.Warn("Installer type %s is not supported, skipping", step.Type)
logger.Warn("Installer type %s is not supported, skipping", logger.H(string(step.Type)))
} else {
result, err := RunInstaller(i.Config, installer)
if err != nil {
logger.Error("Failed to run installer for step %s: %v", *step.Name, err)
logger.Error("Failed to run installer for step %s: %v", logger.H(*step.Name), err)
return fmt.Errorf("failed to run installer for step %s: %w", *step.Name, err)
}
if result != nil {

View File

@@ -165,10 +165,10 @@ func RunInstaller(config *appconfig.AppConfig, installer IInstaller) (*summary.I
}
}
logger.Debug("Checking if %s (%s) should run on %s", name, info.Type, curOS)
logger.Debug("Checking if %s: %s should run on %s", logger.H(string(info.Type)), logger.H(name), curOS)
env := config.Environ()
if !installer.GetData().Platforms.GetShouldRunOnOS(curOS) {
logger.Debug("%s should not run on %s, skipping", name, curOS)
logger.Debug("%s should not run on %s, skipping", logger.H(name), curOS)
result.Action = summary.ActionSkipped
return result, nil
}
@@ -179,12 +179,12 @@ func RunInstaller(config *appconfig.AppConfig, installer IInstaller) (*summary.I
machineAliases = *config.MachineAliases
}
if !installer.GetData().Machines.GetShouldRunOnMachine(machineID, machineAliases) {
logger.Debug("%s should not run on machine %s, skipping", name, machineID)
logger.Debug("%s should not run on machine %s, skipping", logger.H(name), machineID)
result.Action = summary.ActionSkipped
return result, nil
}
if !FilterInstaller(installer, config.Filter) {
logger.Debug("%s is filtered, skipping", name)
logger.Debug("%s is filtered, skipping", logger.H(name))
result.Action = summary.ActionSkipped
return result, nil
}
@@ -196,42 +196,42 @@ func RunInstaller(config *appconfig.AppConfig, installer IInstaller) (*summary.I
}
if !enabled {
logger.Debug("%s is disabled, skipping", name)
logger.Debug("%s is disabled, skipping", logger.H(name))
result.Action = summary.ActionSkipped
return result, nil
}
logger.Debug("Checking %s: %s", info.Type, name)
logger.Debug("Checking %s: %s", logger.H(string(info.Type)), logger.H(name))
installed, err := installer.CheckIsInstalled()
if err != nil {
return nil, err
}
if installed {
logger.Debug("%s (%s) is already installed", name, info.Type)
logger.Debug("%s: %s is already installed", logger.H(string(info.Type)), logger.H(name))
if *config.CheckUpdates {
logger.Info("Checking updates for %s: %s", info.Type, name)
logger.Info("Checking updates for %s: %s", logger.H(string(info.Type)), logger.H(name))
needsUpdate, err := installer.CheckNeedsUpdate()
if err != nil {
return nil, err
}
if needsUpdate {
logger.Info("Updating %s", name)
logger.Info("Updating %s", logger.H(name))
if info.PreUpdate != nil {
logger.Debug("Running pre-update command for %s", name)
logger.Debug("Running pre-update command for %s", logger.H(name))
err := utils.RunCmdPassThrough(env, utils.GetOSShell(installer.GetData().EnvShell), utils.GetOSShellArgs(*info.PreUpdate)...)
if err != nil {
return nil, err
}
}
logger.Debug("Running update command for %s", name)
logger.Debug("Running update command for %s", logger.H(name))
err := installer.Update()
if err != nil {
logger.Error("Failed to update %s: %v", name, err)
logger.Error("Failed to update %s: %v", logger.H(name), err)
return nil, fmt.Errorf("failed to update %s: %w", name, err)
}
if info.PostUpdate != nil {
logger.Debug("Running post-update command for %s", name)
logger.Debug("Running post-update command for %s", logger.H(name))
err := utils.RunCmdPassThrough(env, utils.GetOSShell(installer.GetData().EnvShell), utils.GetOSShellArgs(*info.PostUpdate)...)
if err != nil {
return nil, err
@@ -239,28 +239,28 @@ func RunInstaller(config *appconfig.AppConfig, installer IInstaller) (*summary.I
}
result.Action = summary.ActionUpgraded
} else {
logger.Info("%s (%s) is up-to-date", name, info.Type)
logger.Info("%s: %s is up-to-date", logger.H(string(info.Type)), logger.H(name))
result.Action = summary.ActionUpToDate
}
} else {
result.Action = summary.ActionUpToDate
}
} else {
logger.Info("Installing %s: %s", installer.GetData().Type, name)
logger.Info("Installing %s: %s", logger.H(string(installer.GetData().Type)), logger.H(name))
if info.PreInstall != nil {
logger.Debug("Running pre-install command for %s (%s)", name, info.Type)
logger.Debug("Running pre-install command for %s: %s", logger.H(string(info.Type)), logger.H(name))
err := utils.RunCmdPassThrough(env, utils.GetOSShell(installer.GetData().EnvShell), utils.GetOSShellArgs(*info.PreInstall)...)
if err != nil {
return nil, err
}
}
logger.Debug("Running installer for %s (%s)", name, info.Type)
logger.Debug("Running installer for %s: %s", logger.H(string(info.Type)), logger.H(name))
err = installer.Install()
if err != nil {
return nil, err
}
if info.PostInstall != nil {
logger.Debug("Running post-install command for %s (%s)", name, info.Type)
logger.Debug("Running post-install command for %s: %s", logger.H(string(info.Type)), logger.H(name))
err := utils.RunCmdPassThrough(env, utils.GetOSShell(installer.GetData().EnvShell), utils.GetOSShellArgs(*info.PostInstall)...)
if err != nil {
return nil, err

View File

@@ -64,20 +64,20 @@ func (i *ManifestInstaller) Install() error {
info := i.GetData()
name := *info.Name
config := i.ManifestConfig
logger.Info("Installing manifest %s", name)
logger.Info("Installing manifest %s", logger.H(name))
i.childResults = []summary.InstallResult{}
for _, step := range config.Install {
logger.Debug("Checking step %s", *step.Name)
logger.Debug("Checking step %s", logger.H(*step.Name))
installer, err := GetInstaller(config, &step)
if err != nil {
return err
}
if installer == nil {
logger.Warn("Installer type %s is not supported, skipping", step.Type)
logger.Warn("Installer type %s is not supported, skipping", logger.H(string(step.Type)))
} else {
result, err := RunInstaller(config, installer)
if err != nil {
logger.Error("Failed to run installer for step %s: %v", *step.Name, err)
logger.Error("Failed to run installer for step %s: %v", logger.H(*step.Name), err)
return fmt.Errorf("failed to run installer for step %s: %w", *step.Name, err)
}
if result != nil {

View File

@@ -5,12 +5,39 @@ import (
"log"
"os"
"path/filepath"
"strings"
"github.com/chenasraf/sofmani/platform"
"github.com/davecgh/go-spew/spew"
"github.com/fatih/color"
)
// Highlight markers (using unlikely byte sequences)
const (
highlightStart = "\x00HS\x00"
highlightEnd = "\x00HE\x00"
)
// ANSI color codes
const (
ansiHighlight = "\033[1;96m" // Bright cyan for highlights
ansiBlueBold = "\033[1;34m"
ansiYellowBold = "\033[1;33m"
ansiRedBold = "\033[1;31m"
ansiGreenBold = "\033[1;32m"
ansiReset = "\033[0m"
)
// Highlight marks text to be displayed in white/bold in console output.
// Use this for installer names, types, and other important identifiers.
func Highlight(text string) string {
return highlightStart + text + highlightEnd
}
// H is a shorthand alias for Highlight.
func H(text string) string {
return Highlight(text)
}
// Logger provides logging functionality with support for file and console output.
type Logger struct {
fileLogger *log.Logger // fileLogger is the logger for writing to the log file.
@@ -115,49 +142,64 @@ func InitLogger(debug bool) *Logger {
return logger
}
// stripHighlightMarkers removes highlight markers from text (for file output).
func stripHighlightMarkers(text string) string {
text = strings.ReplaceAll(text, highlightStart, "")
text = strings.ReplaceAll(text, highlightEnd, "")
return text
}
// processHighlights converts highlight markers to ANSI codes for console output.
func processHighlights(text string, baseColorSeq string) string {
// Replace start marker with highlight color
text = strings.ReplaceAll(text, highlightStart, ansiHighlight)
// Replace end marker with reset + base color (to restore the log level color)
text = strings.ReplaceAll(text, highlightEnd, ansiReset+baseColorSeq)
return text
}
// log is an internal helper function for logging messages with a specific level and color.
func (l *Logger) log(level string, colorizer *color.Color, format string, args ...any) {
// Create timestamped message
// timestamp := time.Now().Format("2006-01-02 15:04:05")
func (l *Logger) log(level string, colorSeq string, format string, args ...any) {
message := fmt.Sprintf("[%s] %s", level, fmt.Sprintf(format, args...))
// Write to file
l.fileLogger.Println(message)
// Write to file (strip all highlight markers - file should have no colors)
fileMessage := stripHighlightMarkers(message)
l.fileLogger.Println(fileMessage)
if level == "DEBUG" && !l.debug {
return
}
// Write to console with color
if colorizer != nil {
l.consoleOut.Println(colorizer.Sprint(message))
if colorSeq != "" {
consoleMessage := processHighlights(message, colorSeq)
// Wrap entire message in base color and reset at end
l.consoleOut.Println(colorSeq + consoleMessage + ansiReset)
} else {
l.consoleOut.Println(message)
// No base color - just convert highlights to white
consoleMessage := processHighlights(message, "")
l.consoleOut.Println(consoleMessage)
}
}
// Info logs an informational message.
func Info(format string, args ...any) {
colorBlue := color.New(color.FgBlue).Add(color.Bold)
logger.log(" INFO", colorBlue, format, args...)
logger.log(" INFO", ansiBlueBold, format, args...)
}
// Warn logs a warning message.
func Warn(format string, args ...any) {
colorYellow := color.New(color.FgYellow).Add(color.Bold)
logger.log(" WARN", colorYellow, format, args...)
logger.log(" WARN", ansiYellowBold, format, args...)
}
// Error logs an error message.
func Error(format string, args ...any) {
colorRed := color.New(color.FgRed).Add(color.Bold)
logger.log("ERROR", colorRed, format, args...)
logger.log("ERROR", ansiRedBold, format, args...)
}
// Debug logs a debug message. Only printed if debug mode is enabled.
func Debug(format string, args ...any) {
colorGreen := color.New(color.FgGreen).Add(color.Bold)
logger.log("DEBUG", colorGreen, format, args...)
logger.log("DEBUG", ansiGreenBold, format, args...)
}
// Spew logs a detailed representation of a value using spew.Dump.

View File

@@ -197,7 +197,7 @@ func hasChildrenWithAction(children []InstallResult, action Action) bool {
// printResult prints a single result with the given indentation level.
func (s *Summary) printResult(r InstallResult, indent int) {
prefix := strings.Repeat(" ", indent)
logger.Info("%s- %s: %s", prefix, r.Type, r.Name)
logger.Info("%s- %s: %s", prefix, logger.H(r.Type), logger.H(r.Name))
for _, child := range r.Children {
s.printResult(child, indent+1)