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:
@@ -23,6 +23,7 @@ type GeoSyncManager struct {
|
||||
domain string
|
||||
stacks StackLister
|
||||
logger *log.Logger
|
||||
debug bool
|
||||
|
||||
mu sync.Mutex
|
||||
running bool
|
||||
@@ -39,6 +40,11 @@ func NewGeoSyncManager(client *Client, sett *settings.Settings, domain string, s
|
||||
}
|
||||
}
|
||||
|
||||
// SetDebug enables or disables debug logging for the geo sync manager.
|
||||
func (g *GeoSyncManager) SetDebug(debug bool) {
|
||||
g.debug = debug
|
||||
}
|
||||
|
||||
// IsRunning returns true if a sync operation is in progress.
|
||||
func (g *GeoSyncManager) IsRunning() bool {
|
||||
g.mu.Lock()
|
||||
@@ -75,17 +81,28 @@ func (g *GeoSyncManager) Sync(ctx context.Context) error {
|
||||
// 1. Resolve zone ID (use cached value if available)
|
||||
zoneID := geo.ZoneID
|
||||
if zoneID == "" {
|
||||
if g.debug {
|
||||
g.logger.Printf("[DEBUG] [cloudflare] Zone ID not cached, resolving via API for domain %s", g.domain)
|
||||
}
|
||||
var err error
|
||||
zoneID, err = g.client.GetZoneID(ctx, g.domain)
|
||||
if err != nil {
|
||||
g.saveError(zoneID, "", err.Error())
|
||||
return fmt.Errorf("resolve zone: %w", err)
|
||||
}
|
||||
if g.debug {
|
||||
g.logger.Printf("[DEBUG] [cloudflare] Resolved zone ID: %s", zoneID)
|
||||
}
|
||||
} else if g.debug {
|
||||
g.logger.Printf("[DEBUG] [cloudflare] Using cached zone ID: %s", zoneID)
|
||||
}
|
||||
|
||||
// 2. Get or create the custom WAF ruleset
|
||||
rulesetID := geo.RulesetID
|
||||
if rulesetID == "" {
|
||||
if g.debug {
|
||||
g.logger.Printf("[DEBUG] [cloudflare] Ruleset ID not cached, looking up for zone %s", zoneID)
|
||||
}
|
||||
var err error
|
||||
rulesetID, err = g.client.GetCustomRulesetID(ctx, zoneID)
|
||||
if err != nil {
|
||||
@@ -93,12 +110,20 @@ func (g *GeoSyncManager) Sync(ctx context.Context) error {
|
||||
return fmt.Errorf("get ruleset: %w", err)
|
||||
}
|
||||
if rulesetID == "" {
|
||||
if g.debug {
|
||||
g.logger.Printf("[DEBUG] [cloudflare] No existing custom ruleset found, creating new one")
|
||||
}
|
||||
rulesetID, err = g.client.CreateCustomRuleset(ctx, zoneID)
|
||||
if err != nil {
|
||||
g.saveError(zoneID, "", err.Error())
|
||||
return fmt.Errorf("create ruleset: %w", err)
|
||||
}
|
||||
}
|
||||
if g.debug {
|
||||
g.logger.Printf("[DEBUG] [cloudflare] Using ruleset ID: %s", rulesetID)
|
||||
}
|
||||
} else if g.debug {
|
||||
g.logger.Printf("[DEBUG] [cloudflare] Using cached ruleset ID: %s", rulesetID)
|
||||
}
|
||||
|
||||
// 3. List existing felhom-managed rules
|
||||
@@ -107,9 +132,21 @@ func (g *GeoSyncManager) Sync(ctx context.Context) error {
|
||||
g.saveError(zoneID, rulesetID, err.Error())
|
||||
return fmt.Errorf("list existing rules: %w", err)
|
||||
}
|
||||
if g.debug {
|
||||
g.logger.Printf("[DEBUG] [cloudflare] Found %d existing felhom rules", len(existing))
|
||||
for _, r := range existing {
|
||||
g.logger.Printf("[DEBUG] [cloudflare] existing: %s (id=%s)", r.Description, r.ID)
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Build desired rules
|
||||
desired := g.buildDesiredRules(geo)
|
||||
if g.debug {
|
||||
g.logger.Printf("[DEBUG] [cloudflare] Built %d desired rules", len(desired))
|
||||
for _, d := range desired {
|
||||
g.logger.Printf("[DEBUG] [cloudflare] desired: %s", d.description)
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Diff and apply
|
||||
if err := g.applyDiff(ctx, zoneID, rulesetID, existing, desired); err != nil {
|
||||
@@ -134,24 +171,41 @@ func (g *GeoSyncManager) deleteAllRules(ctx context.Context, geo *settings.GeoRe
|
||||
}
|
||||
|
||||
if zoneID == "" || rulesetID == "" {
|
||||
if g.debug {
|
||||
g.logger.Printf("[DEBUG] [cloudflare] deleteAllRules: no cached zone/ruleset IDs, nothing to clean up")
|
||||
}
|
||||
// No cached IDs — nothing to clean up
|
||||
return nil
|
||||
}
|
||||
|
||||
if g.debug {
|
||||
g.logger.Printf("[DEBUG] [cloudflare] deleteAllRules: listing rules for zone=%s ruleset=%s", zoneID, rulesetID)
|
||||
}
|
||||
|
||||
existing, err := g.client.GetFelhomRules(ctx, zoneID, rulesetID)
|
||||
if err != nil {
|
||||
g.logger.Printf("[GEO] Warning: could not list rules for cleanup: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if g.debug {
|
||||
g.logger.Printf("[DEBUG] [cloudflare] deleteAllRules: found %d felhom rules to delete", len(existing))
|
||||
}
|
||||
|
||||
deleted := 0
|
||||
for _, r := range existing {
|
||||
if err := g.client.DeleteRule(ctx, zoneID, rulesetID, r.ID); err != nil {
|
||||
g.logger.Printf("[GEO] Warning: could not delete rule %s: %v", r.ID, err)
|
||||
} else {
|
||||
deleted++
|
||||
}
|
||||
}
|
||||
|
||||
if len(existing) > 0 {
|
||||
g.logger.Printf("[GEO] Deleted %d felhom-geo rules (feature disabled)", len(existing))
|
||||
if g.debug {
|
||||
g.logger.Printf("[DEBUG] [cloudflare] deleteAllRules: successfully deleted %d/%d rules", deleted, len(existing))
|
||||
}
|
||||
}
|
||||
|
||||
g.saveError(zoneID, rulesetID, "")
|
||||
@@ -169,6 +223,9 @@ func (g *GeoSyncManager) buildDesiredRules(geo *settings.GeoRestriction) []desir
|
||||
var rules []desiredRule
|
||||
|
||||
hostnames := g.stacks.GetDeployedHostnames()
|
||||
if g.debug {
|
||||
g.logger.Printf("[DEBUG] [cloudflare] buildDesiredRules: %d deployed hostnames from stacks", len(hostnames))
|
||||
}
|
||||
|
||||
// Collect app hostnames that have overrides (to exclude from global rule)
|
||||
var excludeHostnames []string
|
||||
@@ -177,6 +234,9 @@ func (g *GeoSyncManager) buildDesiredRules(geo *settings.GeoRestriction) []desir
|
||||
for appName, override := range geo.AppOverrides {
|
||||
hostname, ok := hostnames[appName]
|
||||
if !ok {
|
||||
if g.debug {
|
||||
g.logger.Printf("[DEBUG] [cloudflare] buildDesiredRules: skipping override for %q (not deployed)", appName)
|
||||
}
|
||||
continue // app not deployed, skip
|
||||
}
|
||||
overrideApps[appName] = true
|
||||
@@ -189,15 +249,24 @@ func (g *GeoSyncManager) buildDesiredRules(geo *settings.GeoRestriction) []desir
|
||||
})
|
||||
}
|
||||
|
||||
if g.debug && len(overrideApps) > 0 {
|
||||
g.logger.Printf("[DEBUG] [cloudflare] buildDesiredRules: %d app overrides active (deployed)", len(overrideApps))
|
||||
}
|
||||
|
||||
// Sort exclude hostnames for deterministic expression
|
||||
sort.Strings(excludeHostnames)
|
||||
|
||||
// Global rule (excludes apps with their own rules)
|
||||
globalExpr := BuildGlobalExpression(geo.AllowedCountries, excludeHostnames)
|
||||
rules = append(rules, desiredRule{
|
||||
description: globalRuleDesc,
|
||||
expression: BuildGlobalExpression(geo.AllowedCountries, excludeHostnames),
|
||||
expression: globalExpr,
|
||||
})
|
||||
|
||||
if g.debug {
|
||||
g.logger.Printf("[DEBUG] [cloudflare] buildDesiredRules: global rule expression: %s", globalExpr)
|
||||
}
|
||||
|
||||
return rules
|
||||
}
|
||||
|
||||
@@ -220,13 +289,21 @@ func (g *GeoSyncManager) applyDiff(ctx context.Context, zoneID, rulesetID string
|
||||
if ex, ok := existingByDesc[d.description]; ok {
|
||||
// Rule exists — check if expression changed
|
||||
if ex.Expression != d.expression {
|
||||
if g.debug {
|
||||
g.logger.Printf("[DEBUG] [cloudflare] applyDiff: updating rule %q (id=%s) — expression changed", d.description, ex.ID)
|
||||
}
|
||||
r := newBlockRule(d.description, d.expression)
|
||||
if err := g.client.UpdateRule(ctx, zoneID, rulesetID, ex.ID, r); err != nil {
|
||||
return fmt.Errorf("update rule %q: %w", d.description, err)
|
||||
}
|
||||
} else if g.debug {
|
||||
g.logger.Printf("[DEBUG] [cloudflare] applyDiff: rule %q unchanged, skipping", d.description)
|
||||
}
|
||||
} else {
|
||||
// New rule — create
|
||||
if g.debug {
|
||||
g.logger.Printf("[DEBUG] [cloudflare] applyDiff: creating new rule %q", d.description)
|
||||
}
|
||||
r := newBlockRule(d.description, d.expression)
|
||||
if _, err := g.client.CreateRule(ctx, zoneID, rulesetID, r); err != nil {
|
||||
return fmt.Errorf("create rule %q: %w", d.description, err)
|
||||
@@ -237,6 +314,9 @@ func (g *GeoSyncManager) applyDiff(ctx context.Context, zoneID, rulesetID string
|
||||
// Delete rules that are no longer desired
|
||||
for _, ex := range existing {
|
||||
if _, ok := desiredByDesc[ex.Description]; !ok {
|
||||
if g.debug {
|
||||
g.logger.Printf("[DEBUG] [cloudflare] applyDiff: deleting obsolete rule %q (id=%s)", ex.Description, ex.ID)
|
||||
}
|
||||
if err := g.client.DeleteRule(ctx, zoneID, rulesetID, ex.ID); err != nil {
|
||||
return fmt.Errorf("delete rule %q: %w", ex.Description, err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user