feat: comprehensive debug logging across all controller modules
Add detailed [DEBUG] logging to every controller module when logging.level is set to "debug". Each module with stateful debug uses SetDebug(bool) wired from main.go. Covers stacks, backup, cloudflare, integrations, system, monitor, settings, scheduler, web handlers, storage, metrics, API, selfupdate, and assets. Also includes the app export/import (.fab bundles) feature from v0.32.0 and its debug page integration. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -62,6 +62,12 @@ func NewUpdater(cfg *config.SelfUpdateConfig, gitCfg *config.GitConfig, currentV
|
||||
}
|
||||
}
|
||||
|
||||
func (u *Updater) dbg(format string, args ...interface{}) {
|
||||
if u.debug {
|
||||
u.logger.Printf("[DEBUG] [selfupdate] "+format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
// SetBackupRunningCheck sets the callback to check if a backup is in progress.
|
||||
func (u *Updater) SetBackupRunningCheck(fn func() bool) {
|
||||
u.mu.Lock()
|
||||
@@ -140,10 +146,10 @@ func (u *Updater) CheckForUpdate() CheckResult {
|
||||
result.UpdateAvailable = true
|
||||
}
|
||||
|
||||
if u.debug {
|
||||
u.logger.Printf("[DEBUG] [SELFUPDATE] Version comparison: current=%s, latest=%s, cmp=%d, updateAvailable=%v",
|
||||
u.currentVer, latestStr, cmp, result.UpdateAvailable)
|
||||
}
|
||||
u.dbg("version comparison: current=%s (%d.%d.%d), latest=%s (%d.%d.%d), cmp=%d, updateAvailable=%v",
|
||||
u.currentVer, currentVer.Major, currentVer.Minor, currentVer.Patch,
|
||||
latestStr, latestVer.Major, latestVer.Minor, latestVer.Patch,
|
||||
cmp, result.UpdateAvailable)
|
||||
|
||||
u.mu.Lock()
|
||||
u.latestVersion = latestStr
|
||||
@@ -163,9 +169,7 @@ func (u *Updater) queryRegistry() (string, error) {
|
||||
// Gitea registry V2: GET /v2/<owner>/<repo>/tags/list
|
||||
url := fmt.Sprintf("https://gitea.dooplex.hu/v2/%s/tags/list", registryImagePath(u.cfg.Image))
|
||||
|
||||
if u.debug {
|
||||
u.logger.Printf("[DEBUG] [SELFUPDATE] Registry API URL: %s (user: %s)", url, u.gitCfg.Username)
|
||||
}
|
||||
u.dbg("queryRegistry: url=%s user=%s", url, u.gitCfg.Username)
|
||||
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
@@ -176,9 +180,11 @@ func (u *Updater) queryRegistry() (string, error) {
|
||||
client := &http.Client{Timeout: 15 * time.Second}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
u.dbg("queryRegistry: HTTP request failed: %v", err)
|
||||
return "", fmt.Errorf("HTTP request failed: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
u.dbg("queryRegistry: HTTP %d", resp.StatusCode)
|
||||
|
||||
if resp.StatusCode == 401 {
|
||||
return "", fmt.Errorf("authentication failed (401)")
|
||||
@@ -195,9 +201,7 @@ func (u *Updater) queryRegistry() (string, error) {
|
||||
return "", fmt.Errorf("decoding response: %w", err)
|
||||
}
|
||||
|
||||
if u.debug {
|
||||
u.logger.Printf("[DEBUG] [SELFUPDATE] Registry returned %d tags: %v", len(tagsResp.Tags), tagsResp.Tags)
|
||||
}
|
||||
u.dbg("queryRegistry: %d tags returned: %v", len(tagsResp.Tags), tagsResp.Tags)
|
||||
|
||||
// Find highest semver tag
|
||||
var highest *Version
|
||||
@@ -293,9 +297,11 @@ func (u *Updater) DryRun() *DryRunResult {
|
||||
// TriggerUpdate starts the self-update process. Returns error immediately if
|
||||
// preconditions fail. The actual update runs in a goroutine.
|
||||
func (u *Updater) TriggerUpdate(initiatedBy string) error {
|
||||
u.dbg("TriggerUpdate: initiatedBy=%s currentVer=%s", initiatedBy, u.currentVer)
|
||||
u.mu.Lock()
|
||||
if u.updateRunning {
|
||||
u.mu.Unlock()
|
||||
u.dbg("TriggerUpdate: rejected — update already running")
|
||||
return fmt.Errorf("Frissítés már folyamatban")
|
||||
}
|
||||
|
||||
@@ -334,6 +340,7 @@ func (u *Updater) TriggerUpdate(initiatedBy string) error {
|
||||
previousImage := fmt.Sprintf("%s:%s", u.cfg.Image, u.currentVer)
|
||||
|
||||
u.logger.Printf("[INFO] Starting self-update: %s → %s (initiated by: %s)", u.currentVer, targetVersion, initiatedBy)
|
||||
u.dbg("TriggerUpdate: target=%s image=%s previousImage=%s", targetVersion, targetImage, previousImage)
|
||||
|
||||
go u.performUpdate(targetVersion, targetImage, previousImage, initiatedBy)
|
||||
|
||||
@@ -348,6 +355,7 @@ func (u *Updater) performUpdate(targetVersion, targetImage, previousImage, initi
|
||||
u.mu.Unlock()
|
||||
}()
|
||||
|
||||
u.dbg("performUpdate: starting — target=%s image=%s", targetVersion, targetImage)
|
||||
// 1. Write pending state
|
||||
state := &UpdateState{
|
||||
Status: "pending",
|
||||
@@ -364,7 +372,9 @@ func (u *Updater) performUpdate(targetVersion, targetImage, previousImage, initi
|
||||
}
|
||||
|
||||
// 2. Docker pull
|
||||
u.dbg("performUpdate: step 2 — docker pull %s", targetImage)
|
||||
u.logger.Printf("[INFO] Pulling image: %s", targetImage)
|
||||
pullStart := time.Now()
|
||||
pullOut, pullErr := runCommand("docker", "pull", targetImage)
|
||||
if pullErr != nil {
|
||||
state.Status = "failed"
|
||||
@@ -375,8 +385,10 @@ func (u *Updater) performUpdate(targetVersion, targetImage, previousImage, initi
|
||||
return
|
||||
}
|
||||
u.logger.Printf("[INFO] Image pulled successfully: %s", targetImage)
|
||||
u.dbg("performUpdate: docker pull completed in %s", time.Since(pullStart).Round(time.Millisecond))
|
||||
|
||||
// 3. Update compose file (replace image tag)
|
||||
u.dbg("performUpdate: step 3 — updating compose file %s", u.composePath)
|
||||
if err := u.updateComposeFile(targetImage); err != nil {
|
||||
state.Status = "failed"
|
||||
state.Error = fmt.Sprintf("compose update failed: %v", err)
|
||||
@@ -388,6 +400,7 @@ func (u *Updater) performUpdate(targetVersion, targetImage, previousImage, initi
|
||||
u.logger.Printf("[INFO] Compose file updated with new image: %s", targetImage)
|
||||
|
||||
// 4. Docker compose up -d (this kills the current container)
|
||||
u.dbg("performUpdate: step 4 — docker compose up -d")
|
||||
u.logger.Printf("[INFO] Running docker compose up -d — container will restart")
|
||||
composeDir := strings.TrimSuffix(u.composePath, "/docker-compose.yml")
|
||||
upOut, upErr := runCommand("docker", "compose", "-f", u.composePath, "-p", "felhom-controller", "up", "-d")
|
||||
@@ -417,12 +430,12 @@ func (u *Updater) updateComposeFile(newImage string) error {
|
||||
// Replace image line: "image: gitea.dooplex.hu/admin/felhom-controller:..." → new image
|
||||
re := regexp.MustCompile(`(image:\s*)gitea\.dooplex\.hu/admin/felhom-controller:\S+`)
|
||||
|
||||
if u.debug {
|
||||
// Log old image line for debugging
|
||||
oldMatch := re.Find(data)
|
||||
if oldMatch != nil {
|
||||
u.logger.Printf("[DEBUG] [SELFUPDATE] Compose file edit: %q → %q", string(oldMatch), "image: "+newImage)
|
||||
}
|
||||
// Log old image line for debugging
|
||||
oldMatch := re.Find(data)
|
||||
if oldMatch != nil {
|
||||
u.dbg("updateComposeFile: %q → %q", string(oldMatch), "image: "+newImage)
|
||||
} else {
|
||||
u.dbg("updateComposeFile: no matching image line found in %s", u.composePath)
|
||||
}
|
||||
|
||||
newData := re.ReplaceAll(data, []byte("${1}"+newImage))
|
||||
@@ -447,6 +460,7 @@ func (u *Updater) updateComposeFile(newImage string) error {
|
||||
// Called once from main.go before the scheduler starts.
|
||||
// Returns the state if a pending update was detected, nil otherwise.
|
||||
func (u *Updater) VerifyStartup() *UpdateState {
|
||||
u.dbg("VerifyStartup: checking update state in %s", u.dataDir)
|
||||
state, err := LoadState(u.dataDir)
|
||||
if err != nil {
|
||||
u.logger.Printf("[WARN] Failed to load update state on startup: %v — clearing", err)
|
||||
@@ -454,8 +468,10 @@ func (u *Updater) VerifyStartup() *UpdateState {
|
||||
return nil
|
||||
}
|
||||
if state == nil || state.Status != "pending" {
|
||||
u.dbg("VerifyStartup: no pending update (state=%v)", state)
|
||||
return nil
|
||||
}
|
||||
u.dbg("VerifyStartup: pending update found — target=%s previous=%s", state.TargetVersion, state.PreviousVersion)
|
||||
|
||||
// Compare current version with target
|
||||
currentVer, curErr := ParseVersion(u.currentVer)
|
||||
|
||||
Reference in New Issue
Block a user