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:
@@ -20,6 +20,10 @@ func (m *Manager) OnStackStop(_ context.Context, stackName string) {
|
||||
all[k] = v
|
||||
}
|
||||
|
||||
if m.isDebug() {
|
||||
m.logger.Printf("[DEBUG] [integrations] OnStackStop: stack=%s integrationsFound=%d", stackName, len(all))
|
||||
}
|
||||
|
||||
for key, state := range all {
|
||||
if !state.Enabled || state.Status == "disabled" {
|
||||
continue
|
||||
@@ -41,6 +45,9 @@ func (m *Manager) OnStackStop(_ context.Context, stackName string) {
|
||||
continue
|
||||
}
|
||||
|
||||
if m.isDebug() {
|
||||
m.logger.Printf("[DEBUG] [integrations] OnStackStop: revoking %s", key)
|
||||
}
|
||||
if err := handler.Revoke(ac); err != nil {
|
||||
m.logger.Printf("[WARN] Integration revoke on stop failed for %s: %v", key, err)
|
||||
}
|
||||
@@ -59,6 +66,9 @@ func (m *Manager) OnStackStop(_ context.Context, stackName string) {
|
||||
// Re-applies integrations that were previously enabled but are not currently active.
|
||||
// Waits briefly for the stack manager to refresh container state.
|
||||
func (m *Manager) OnStackStart(_ context.Context, stackName string) {
|
||||
if m.isDebug() {
|
||||
m.logger.Printf("[DEBUG] [integrations] OnStackStart: stack=%s, waiting 5s for state refresh", stackName)
|
||||
}
|
||||
// Brief delay so the stack manager's periodic status refresh
|
||||
// picks up the new container state (runs every 30s).
|
||||
time.Sleep(5 * time.Second)
|
||||
@@ -72,6 +82,10 @@ func (m *Manager) OnStackStart(_ context.Context, stackName string) {
|
||||
all[k] = v
|
||||
}
|
||||
|
||||
if m.isDebug() {
|
||||
m.logger.Printf("[DEBUG] [integrations] OnStackStart: stack=%s integrationsFound=%d", stackName, len(all))
|
||||
}
|
||||
|
||||
for key, state := range all {
|
||||
if !state.Enabled || state.Status == "active" {
|
||||
continue
|
||||
@@ -86,11 +100,17 @@ func (m *Manager) OnStackStart(_ context.Context, stackName string) {
|
||||
// StateStarting = container running but healthcheck hasn't passed yet — still connectable.
|
||||
provStack, pOk := m.stacks.GetStack(provider)
|
||||
if !pOk || !provStack.Deployed || !isStackUp(provStack.State) {
|
||||
if m.isDebug() {
|
||||
m.logger.Printf("[DEBUG] [integrations] OnStackStart: skipping %s — provider %s not up (found=%v deployed=%v state=%v)", key, provider, pOk, pOk && provStack.Deployed, func() stacks.ContainerState { if pOk { return provStack.State }; return "" }())
|
||||
}
|
||||
continue
|
||||
}
|
||||
if target != "filebrowser" {
|
||||
tgtStack, tOk := m.stacks.GetStack(target)
|
||||
if !tOk || !tgtStack.Deployed || !isStackUp(tgtStack.State) {
|
||||
if m.isDebug() {
|
||||
m.logger.Printf("[DEBUG] [integrations] OnStackStart: skipping %s — target %s not up (found=%v deployed=%v state=%v)", key, target, tOk, tOk && tgtStack.Deployed, func() stacks.ContainerState { if tOk { return tgtStack.State }; return "" }())
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
@@ -100,6 +120,10 @@ func (m *Manager) OnStackStart(_ context.Context, stackName string) {
|
||||
continue
|
||||
}
|
||||
|
||||
if m.isDebug() {
|
||||
m.logger.Printf("[DEBUG] [integrations] OnStackStart: re-applying %s (currentStatus=%s)", key, state.Status)
|
||||
}
|
||||
|
||||
ac, err := m.buildApplyContext(provider, target)
|
||||
if err != nil {
|
||||
m.logger.Printf("[WARN] Cannot re-apply integration %s on start: %v", key, err)
|
||||
@@ -138,6 +162,10 @@ func (m *Manager) OnStackRemove(_ context.Context, stackName string) {
|
||||
all[k] = v
|
||||
}
|
||||
|
||||
if m.isDebug() {
|
||||
m.logger.Printf("[DEBUG] [integrations] OnStackRemove: stack=%s integrationsFound=%d", stackName, len(all))
|
||||
}
|
||||
|
||||
for key, state := range all {
|
||||
provider, target, ok := ParseIntegrationKey(key)
|
||||
if !ok {
|
||||
@@ -145,6 +173,9 @@ func (m *Manager) OnStackRemove(_ context.Context, stackName string) {
|
||||
}
|
||||
|
||||
if state.Enabled {
|
||||
if m.isDebug() {
|
||||
m.logger.Printf("[DEBUG] [integrations] OnStackRemove: revoking enabled integration %s", key)
|
||||
}
|
||||
handler, hOk := m.handlers[key]
|
||||
if hOk {
|
||||
ac, _ := m.buildApplyContext(provider, target)
|
||||
|
||||
@@ -31,6 +31,7 @@ type Manager struct {
|
||||
|
||||
handlers map[string]Handler // key: "provider:target" -> Handler
|
||||
mu sync.Mutex // serialize apply/revoke operations
|
||||
debug bool
|
||||
}
|
||||
|
||||
// NewManager creates an integration manager and registers built-in handlers.
|
||||
@@ -47,9 +48,28 @@ func NewManager(sett *settings.Settings, sp StackProvider, domain, stacksDir str
|
||||
// Register built-in handlers
|
||||
m.RegisterHandler("onlyoffice:filebrowser", &OnlyOfficeFileBrowserHandler{})
|
||||
m.RegisterHandler("onlyoffice:nextcloud", &OnlyOfficeNextcloudHandler{})
|
||||
|
||||
if m.isDebug() {
|
||||
keys := make([]string, 0, len(m.handlers))
|
||||
for k := range m.handlers {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
m.logger.Printf("[DEBUG] [integrations] NewManager: registered handlers: %v", keys)
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// SetDebug enables or disables debug logging.
|
||||
func (m *Manager) SetDebug(debug bool) {
|
||||
m.debug = debug
|
||||
}
|
||||
|
||||
// isDebug returns whether debug logging is enabled.
|
||||
func (m *Manager) isDebug() bool {
|
||||
return m.debug
|
||||
}
|
||||
|
||||
// RegisterHandler registers a handler for a provider:target integration key.
|
||||
func (m *Manager) RegisterHandler(key string, h Handler) {
|
||||
m.handlers[key] = h
|
||||
@@ -61,6 +81,10 @@ func (m *Manager) Toggle(ctx context.Context, provider, target string, enable bo
|
||||
defer m.mu.Unlock()
|
||||
|
||||
key := IntegrationKey(provider, target)
|
||||
if m.isDebug() {
|
||||
m.logger.Printf("[DEBUG] [integrations] Toggle: key=%s provider=%s target=%s enable=%v", key, provider, target, enable)
|
||||
}
|
||||
|
||||
handler, ok := m.handlers[key]
|
||||
if !ok {
|
||||
return settings.IntegrationState{}, fmt.Errorf("nincs kezelő a(z) %s integrációhoz", key)
|
||||
@@ -75,6 +99,9 @@ func (m *Manager) Toggle(ctx context.Context, provider, target string, enable bo
|
||||
if enable {
|
||||
// Validate: provider must be deployed and running
|
||||
provStack, pOk := m.stacks.GetStack(provider)
|
||||
if m.isDebug() {
|
||||
m.logger.Printf("[DEBUG] [integrations] Toggle: provider %s found=%v deployed=%v state=%v", provider, pOk, pOk && provStack.Deployed, func() stacks.ContainerState { if pOk { return provStack.State }; return "" }())
|
||||
}
|
||||
if !pOk || !provStack.Deployed {
|
||||
return state, fmt.Errorf("a szolgáltató alkalmazás (%s) nincs telepítve", provider)
|
||||
}
|
||||
@@ -85,6 +112,9 @@ func (m *Manager) Toggle(ctx context.Context, provider, target string, enable bo
|
||||
// Validate: target must be deployed and running (filebrowser is infra, always present)
|
||||
if target != "filebrowser" {
|
||||
tgtStack, tOk := m.stacks.GetStack(target)
|
||||
if m.isDebug() {
|
||||
m.logger.Printf("[DEBUG] [integrations] Toggle: target %s found=%v deployed=%v state=%v", target, tOk, tOk && tgtStack.Deployed, func() stacks.ContainerState { if tOk { return tgtStack.State }; return "" }())
|
||||
}
|
||||
if !tOk || !tgtStack.Deployed {
|
||||
return state, fmt.Errorf("a célalkalmazás (%s) nincs telepítve", target)
|
||||
}
|
||||
@@ -93,7 +123,11 @@ func (m *Manager) Toggle(ctx context.Context, provider, target string, enable bo
|
||||
}
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
if err := handler.Apply(ac); err != nil {
|
||||
if m.isDebug() {
|
||||
m.logger.Printf("[DEBUG] [integrations] Toggle: Apply failed for %s in %v: %v", key, time.Since(start), err)
|
||||
}
|
||||
state.Enabled = true
|
||||
state.Status = "error"
|
||||
state.LastError = err.Error()
|
||||
@@ -101,15 +135,22 @@ func (m *Manager) Toggle(ctx context.Context, provider, target string, enable bo
|
||||
_ = m.sett.SetIntegrationState(key, state)
|
||||
return state, fmt.Errorf("integráció alkalmazása sikertelen: %w", err)
|
||||
}
|
||||
if m.isDebug() {
|
||||
m.logger.Printf("[DEBUG] [integrations] Toggle: Apply succeeded for %s in %v", key, time.Since(start))
|
||||
}
|
||||
state.Enabled = true
|
||||
state.Status = "active"
|
||||
state.EnabledAt = time.Now().UTC().Format(time.RFC3339)
|
||||
m.logger.Printf("[INFO] Integration %s enabled", key)
|
||||
} else {
|
||||
start := time.Now()
|
||||
if err := handler.Revoke(ac); err != nil {
|
||||
m.logger.Printf("[WARN] Integration revoke failed for %s: %v", key, err)
|
||||
state.LastError = err.Error()
|
||||
}
|
||||
if m.isDebug() {
|
||||
m.logger.Printf("[DEBUG] [integrations] Toggle: Revoke for %s completed in %v", key, time.Since(start))
|
||||
}
|
||||
state.Enabled = false
|
||||
state.Status = "disabled"
|
||||
m.logger.Printf("[INFO] Integration %s disabled", key)
|
||||
@@ -128,6 +169,10 @@ func (m *Manager) ListForProvider(providerSlug string) []StatusInfo {
|
||||
return nil
|
||||
}
|
||||
|
||||
if m.isDebug() {
|
||||
m.logger.Printf("[DEBUG] [integrations] ListForProvider: provider=%s integrationDefs=%d", providerSlug, len(provStack.Meta.Integrations))
|
||||
}
|
||||
|
||||
var result []StatusInfo
|
||||
for _, idef := range provStack.Meta.Integrations {
|
||||
key := IntegrationKey(providerSlug, idef.Target)
|
||||
@@ -171,6 +216,11 @@ func (m *Manager) buildApplyContext(provider, target string) (*ApplyContext, err
|
||||
// Load decrypted env from provider's app.yaml
|
||||
provEnv := m.loadDecryptedEnv(provStack)
|
||||
|
||||
if m.isDebug() {
|
||||
envKeyCount := len(provEnv)
|
||||
m.logger.Printf("[DEBUG] [integrations] buildApplyContext: provider=%s target=%s domain=%s envKeys=%d", provider, target, m.domain, envKeyCount)
|
||||
}
|
||||
|
||||
provMeta := provStack.Meta
|
||||
return &ApplyContext{
|
||||
ProviderName: provider,
|
||||
@@ -192,6 +242,9 @@ func (m *Manager) ReapplyConfigForTarget(targetName string) {
|
||||
defer m.mu.Unlock()
|
||||
|
||||
all := m.sett.GetIntegrationsForTarget(targetName)
|
||||
if m.isDebug() {
|
||||
m.logger.Printf("[DEBUG] [integrations] ReapplyConfigForTarget: target=%s integrations=%d", targetName, len(all))
|
||||
}
|
||||
for key, state := range all {
|
||||
if !state.Enabled || state.Status == "disabled" {
|
||||
continue
|
||||
@@ -207,6 +260,10 @@ func (m *Manager) ReapplyConfigForTarget(targetName string) {
|
||||
continue
|
||||
}
|
||||
|
||||
if m.isDebug() {
|
||||
m.logger.Printf("[DEBUG] [integrations] ReapplyConfigForTarget: reapplying %s (status=%s)", key, state.Status)
|
||||
}
|
||||
|
||||
ac, err := m.buildApplyContext(provider, target)
|
||||
if err != nil {
|
||||
m.logger.Printf("[WARN] Cannot build context for integration %s reapply: %v", key, err)
|
||||
@@ -218,12 +275,18 @@ func (m *Manager) ReapplyConfigForTarget(targetName string) {
|
||||
|
||||
if err := handler.Apply(ac); err != nil {
|
||||
m.logger.Printf("[WARN] Integration config reapply failed for %s: %v", key, err)
|
||||
if m.isDebug() {
|
||||
m.logger.Printf("[DEBUG] [integrations] ReapplyConfigForTarget: %s failed: %v", key, err)
|
||||
}
|
||||
state.Status = "error"
|
||||
state.LastError = err.Error()
|
||||
_ = m.sett.SetIntegrationState(key, state)
|
||||
continue
|
||||
}
|
||||
|
||||
if m.isDebug() {
|
||||
m.logger.Printf("[DEBUG] [integrations] ReapplyConfigForTarget: %s succeeded", key)
|
||||
}
|
||||
state.Status = "active"
|
||||
state.LastError = ""
|
||||
_ = m.sett.SetIntegrationState(key, state)
|
||||
@@ -241,5 +304,8 @@ func (m *Manager) loadDecryptedEnv(s *stacks.Stack) map[string]string {
|
||||
if m.encKey != nil {
|
||||
cfg.Env = crypto.DecryptMap(m.encKey, cfg.Env)
|
||||
}
|
||||
if m.isDebug() {
|
||||
m.logger.Printf("[DEBUG] [integrations] loadDecryptedEnv: stack=%s envKeys=%d", s.Name, len(cfg.Env))
|
||||
}
|
||||
return cfg.Env
|
||||
}
|
||||
|
||||
@@ -25,6 +25,10 @@ func (h *OnlyOfficeFileBrowserHandler) Apply(ac *ApplyContext) error {
|
||||
}
|
||||
|
||||
configPath := filepath.Join(ac.StacksDir, "filebrowser", "config.yaml")
|
||||
officeURL := fmt.Sprintf("https://%s.%s", subdomain, ac.Domain)
|
||||
|
||||
ac.Logger.Printf("[DEBUG] [integrations] OnlyOfficeFileBrowser.Apply: jwtSecretPresent=%v subdomain=%s configPath=%s officeURL=%s", jwtSecret != "", subdomain, configPath, officeURL)
|
||||
|
||||
configData, err := os.ReadFile(configPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("FileBrowser config olvasási hiba: %w", err)
|
||||
@@ -33,7 +37,6 @@ func (h *OnlyOfficeFileBrowserHandler) Apply(ac *ApplyContext) error {
|
||||
// Remove any existing integrations section, then append the new one
|
||||
configStr := removeIntegrationsSection(string(configData))
|
||||
|
||||
officeURL := fmt.Sprintf("https://%s.%s", subdomain, ac.Domain)
|
||||
internalURL := "http://onlyoffice:80"
|
||||
|
||||
integrationsBlock := fmt.Sprintf("integrations:\n office:\n url: %q\n internalUrl: %q\n secret: %q\n viewOnly: false\n",
|
||||
@@ -57,6 +60,8 @@ func (h *OnlyOfficeFileBrowserHandler) Apply(ac *ApplyContext) error {
|
||||
|
||||
func (h *OnlyOfficeFileBrowserHandler) Revoke(ac *ApplyContext) error {
|
||||
configPath := filepath.Join(ac.StacksDir, "filebrowser", "config.yaml")
|
||||
ac.Logger.Printf("[DEBUG] [integrations] OnlyOfficeFileBrowser.Revoke: configPath=%s", configPath)
|
||||
|
||||
configData, err := os.ReadFile(configPath)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
@@ -66,7 +71,9 @@ func (h *OnlyOfficeFileBrowserHandler) Revoke(ac *ApplyContext) error {
|
||||
}
|
||||
|
||||
cleaned := removeIntegrationsSection(string(configData))
|
||||
if cleaned == string(configData) {
|
||||
hadIntegrations := cleaned != string(configData)
|
||||
ac.Logger.Printf("[DEBUG] [integrations] OnlyOfficeFileBrowser.Revoke: integrationsSectionFound=%v", hadIntegrations)
|
||||
if !hadIntegrations {
|
||||
return nil // no integrations section, nothing to remove
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user