feat: comprehensive INFO/WARN/ERROR logging across all controller modules
Add structured operational logging at INFO, WARN, and ERROR levels to every controller module. Standardize custom prefixes ([GEO], [SCHED], [SYNC]) to use [INFO/WARN/ERROR] [module] format. Fix misleveled logs (WARN->ERROR for data loss scenarios, WARN->INFO for routine operations). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@@ -557,6 +558,7 @@ func ParseComposeHDDMounts(composePath, hddPath string) []string {
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("[INFO] [stacks] ParseComposeHDDMounts: found %d HDD mounts for %s", len(mounts), composePath)
|
||||
return mounts
|
||||
}
|
||||
|
||||
|
||||
@@ -375,6 +375,7 @@ func (m *Manager) runComposeDeploy(name, stackDir string, env map[string]string,
|
||||
|
||||
// UpdateStackConfig updates non-locked fields for a deployed stack.
|
||||
func (m *Manager) UpdateStackConfig(name string, values map[string]string) error {
|
||||
m.logger.Printf("[INFO] [stacks] Updating config for stack %s", name)
|
||||
if m.isDebug() {
|
||||
m.logger.Printf("[DEBUG] [stacks] UpdateStackConfig called: name=%q, %d values to update", name, len(values))
|
||||
}
|
||||
@@ -457,6 +458,7 @@ func (m *Manager) GetDeployFields(name string) (*Metadata, *AppConfig, error) {
|
||||
// UpdateOptionalConfig updates optional env vars in app.yaml and restarts the stack if deployed.
|
||||
// Only updates env vars that are listed in the metadata's optional_config sections.
|
||||
func (m *Manager) UpdateOptionalConfig(stackName string, values map[string]string) error {
|
||||
m.logger.Printf("[INFO] [stacks] Updating optional config for stack %s", stackName)
|
||||
if m.isDebug() {
|
||||
m.logger.Printf("[DEBUG] [stacks] UpdateOptionalConfig called: stack=%q, %d values provided", stackName, len(values))
|
||||
}
|
||||
@@ -588,6 +590,7 @@ func LoadAppConfig(stackDir string) *AppConfig {
|
||||
}
|
||||
cfg := &AppConfig{}
|
||||
if err := yaml.Unmarshal(data, cfg); err != nil {
|
||||
log.Printf("[WARN] [stacks] LoadAppConfig: %v", err)
|
||||
log.Printf("[DEBUG] [stacks] LoadAppConfig: failed to parse %s: %v", path, err)
|
||||
return nil
|
||||
}
|
||||
@@ -626,6 +629,7 @@ func SaveAppConfig(stackDir string, cfg *AppConfig, encKey []byte, sensitiveVars
|
||||
|
||||
data, err := yaml.Marshal(saveCfg)
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] [stacks] SaveAppConfig: failed to marshal config for %s: %v", stackDir, err)
|
||||
return fmt.Errorf("marshaling app config: %w", err)
|
||||
}
|
||||
path := filepath.Join(stackDir, "app.yaml")
|
||||
@@ -635,12 +639,15 @@ func SaveAppConfig(stackDir string, cfg *AppConfig, encKey []byte, sensitiveVars
|
||||
// Atomic write: write to .tmp then rename (H04 fix)
|
||||
tmpPath := path + ".tmp"
|
||||
if err := os.WriteFile(tmpPath, []byte(content), 0600); err != nil {
|
||||
log.Printf("[ERROR] [stacks] SaveAppConfig: failed to save %s: %v", path, err)
|
||||
return fmt.Errorf("writing %s: %w", tmpPath, err)
|
||||
}
|
||||
if err := os.Rename(tmpPath, path); err != nil {
|
||||
_ = os.Remove(tmpPath)
|
||||
log.Printf("[ERROR] [stacks] SaveAppConfig: failed to save %s: %v", path, err)
|
||||
return fmt.Errorf("renaming %s to %s: %w", tmpPath, path, err)
|
||||
}
|
||||
log.Printf("[INFO] [stacks] SaveAppConfig: saved config for %s", filepath.Base(stackDir))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -724,11 +731,13 @@ func (m *Manager) InjectMissingFields(stackNames []string) {
|
||||
m.logger.Printf("[DEBUG] [stacks] InjectMissingFields: checking %d stacks", len(stackNames))
|
||||
}
|
||||
|
||||
count := 0
|
||||
for _, name := range stackNames {
|
||||
stack, ok := m.GetStack(name)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
count++
|
||||
|
||||
stackDir := filepath.Dir(stack.ComposePath)
|
||||
meta := LoadMetadata(stackDir)
|
||||
@@ -804,6 +813,7 @@ func (m *Manager) InjectMissingFields(stackNames []string) {
|
||||
m.logger.Printf("[SYNC] Stack %s: injected missing fields: %s", name, strings.Join(injected, ", "))
|
||||
}
|
||||
}
|
||||
m.logger.Printf("[INFO] [stacks] InjectMissingFields: processed %d stacks", count)
|
||||
}
|
||||
|
||||
func containsStr(slice []string, s string) bool {
|
||||
|
||||
@@ -126,9 +126,9 @@ func (m *Manager) RunHealthProbes() error {
|
||||
|
||||
// Summary log
|
||||
if failCount > 0 {
|
||||
m.logger.Printf("[INFO] Health probes: %d ok, %d unhealthy (of %d probed)", okCount, failCount, len(targets))
|
||||
} else if m.isDebug() {
|
||||
m.logger.Printf("[DEBUG] Health probes: %d ok (of %d probed)", okCount, len(targets))
|
||||
m.logger.Printf("[WARN] Health probes: %d ok, %d unhealthy (of %d probed)", okCount, failCount, len(targets))
|
||||
} else {
|
||||
m.logger.Printf("[INFO] Health probes: %d ok (of %d probed)", okCount, len(targets))
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -184,6 +184,8 @@ func (m *Manager) MigrateEncryption() {
|
||||
}
|
||||
if migrated > 0 {
|
||||
m.logger.Printf("[INFO] Encrypted sensitive values in %d app.yaml file(s)", migrated)
|
||||
} else {
|
||||
m.logger.Printf("[INFO] [stacks] Encryption migration: no stacks needed migration")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,6 +328,7 @@ func (m *Manager) ScanStacks() error {
|
||||
}
|
||||
m.logger.Printf("[INFO] Scanned stacks: %d found (%d deployed, %d available)",
|
||||
len(m.stacks), deployedCount, len(m.stacks)-deployedCount)
|
||||
m.logger.Printf("[INFO] [stacks] ScanStacks complete: %d stacks found", len(m.stacks))
|
||||
return m.refreshStatusLocked()
|
||||
}
|
||||
|
||||
@@ -370,6 +373,8 @@ func (m *Manager) refreshStatusLocked() error {
|
||||
m.logger.Printf("[DEBUG] [stacks] refreshStatusLocked: docker ps returned %d containers across %d projects", totalContainers, len(projectContainers))
|
||||
}
|
||||
|
||||
m.logger.Printf("[INFO] [stacks] Status refresh: %d containers across %d stacks", totalContainers, len(m.stacks))
|
||||
|
||||
for name, stack := range m.stacks {
|
||||
containers, exists := projectContainers[name]
|
||||
if !exists {
|
||||
@@ -759,6 +764,7 @@ func (m *Manager) GetLogs(name string, lines int) (string, error) {
|
||||
lines = 1000
|
||||
}
|
||||
|
||||
m.logger.Printf("[INFO] [stacks] Fetching logs for stack %s (tail=%d)", name, lines)
|
||||
m.logger.Printf("[DEBUG] Fetching logs for %s (tail %d)", name, lines)
|
||||
|
||||
dir := filepath.Dir(stack.ComposePath)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package stacks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@@ -126,7 +126,7 @@ func LoadMetadata(stackDir string) Metadata {
|
||||
}
|
||||
|
||||
if err := yaml.Unmarshal(data, &meta); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "[ERROR] Failed to parse .felhom.yml in %s: %v\n", stackDir, err)
|
||||
log.Printf("[ERROR] [stacks] Failed to parse .felhom.yml in %s: %v", stackDir, err)
|
||||
dirName := filepath.Base(stackDir)
|
||||
meta.DisplayName = toTitleCase(strings.ReplaceAll(dirName, "-", " "))
|
||||
meta.Slug = dirName
|
||||
|
||||
Reference in New Issue
Block a user