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:
2026-02-26 19:58:27 +01:00
parent 95c821deb2
commit 8e61cd7ec4
44 changed files with 326 additions and 44 deletions
+6
View File
@@ -88,6 +88,7 @@ func (s *Server) RequireAuth(next http.Handler) http.Handler {
s.logger.Printf("[DEBUG] [web] auth: rejected %s %s from %s (%s)", r.Method, r.URL.Path, r.RemoteAddr, reason)
}
if strings.HasPrefix(r.URL.Path, "/api/") {
s.logger.Printf("[WARN] [api] Unauthorized request to %s from %s", r.URL.Path, r.RemoteAddr)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusUnauthorized)
fmt.Fprint(w, `{"ok":false,"error":"authentication required"}`)
@@ -203,6 +204,7 @@ func (s *Server) handleLogout(w http.ResponseWriter, r *http.Request) {
delete(s.sessions, cookie.Value)
s.sessionsMu.Unlock()
}
s.logger.Printf("[INFO] [web] User logged out from %s", r.RemoteAddr)
http.SetCookie(w, &http.Cookie{Name: sessionCookieName, Value: "", Path: "/", MaxAge: -1})
http.Redirect(w, r, "/login", http.StatusFound)
}
@@ -257,6 +259,7 @@ func (s *Server) invalidateAllSessions() {
count := len(s.sessions)
s.sessions = make(map[string]*session)
s.sessionsMu.Unlock()
s.logger.Printf("[INFO] [web] All sessions invalidated (cleared %d)", count)
if s.isDebug() {
s.logger.Printf("[DEBUG] [web] invalidated all sessions (cleared %d)", count)
}
@@ -281,6 +284,9 @@ func (s *Server) cleanupSessions() {
}
remaining := len(s.sessions)
s.sessionsMu.Unlock()
if expired > 0 {
s.logger.Printf("[INFO] [web] Cleaned up %d expired sessions, %d remaining", expired, remaining)
}
if s.isDebug() && expired > 0 {
s.logger.Printf("[DEBUG] [web] session cleanup: expired=%d remaining=%d", expired, remaining)
}
@@ -109,6 +109,7 @@ func (s *Server) apiExportEstimate(w http.ResponseWriter, r *http.Request) {
est, err := s.appExporter.EstimateExport(stackName, drive)
if err != nil {
s.logger.Printf("[ERROR] [web] Export estimate failed for %s: %v", stackName, err)
s.logger.Printf("[DEBUG] [handler_export] apiExportEstimate error: %v", err)
jsonError(w, err.Error(), http.StatusInternalServerError)
return
@@ -162,6 +163,7 @@ func (s *Server) apiExportStart(w http.ResponseWriter, r *http.Request) {
StopApp: req.StopApp,
})
if err != nil {
s.logger.Printf("[ERROR] [web] Export start failed for %s: %v", req.StackName, err)
s.logger.Printf("[DEBUG] [handler_export] apiExportStart error: %v", err)
jsonError(w, err.Error(), http.StatusConflict)
return
@@ -306,6 +308,7 @@ func (s *Server) apiImportStart(w http.ResponseWriter, r *http.Request) {
Password: req.Password,
})
if err != nil {
s.logger.Printf("[ERROR] [web] Import start failed for %s: %v", req.Path, err)
s.logger.Printf("[DEBUG] [handler_export] apiImportStart error: %v", err)
jsonError(w, err.Error(), http.StatusConflict)
return
@@ -89,6 +89,7 @@ func (s *Server) apiRestoreAll(w http.ResponseWriter, r *http.Request) {
jsonError(w, "restore already in progress", http.StatusConflict)
return
}
s.logger.Printf("[INFO] [web] Restore-all initiated from %s", r.RemoteAddr)
go s.executeAllRestores()
jsonResponse(w, map[string]interface{}{
+2
View File
@@ -1568,6 +1568,7 @@ func (s *Server) settingsStorageDefaultHandler(w http.ResponseWriter, r *http.Re
http.Redirect(w, r, "/settings", http.StatusFound)
return
}
s.logger.Printf("[INFO] [web] Default storage path set to %s", path)
http.Redirect(w, r, "/settings?storage_msg=success&storage_detail="+url.QueryEscape("Alapértelmezett adattároló beállítva: "+path), http.StatusFound)
}
@@ -1585,6 +1586,7 @@ func (s *Server) settingsStorageSchedulableHandler(w http.ResponseWriter, r *htt
http.Redirect(w, r, "/settings", http.StatusFound)
return
}
s.logger.Printf("[INFO] [web] Storage schedulable updated: %s → %v", path, schedulable)
http.Redirect(w, r, "/settings?storage_msg=success&storage_detail="+url.QueryEscape("Adattároló állapot módosítva: "+path), http.StatusFound)
}
+1
View File
@@ -345,6 +345,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
s.debugPageHandler(w, r)
default:
s.logger.Printf("[WARN] [web] 404 Not Found: %s %s", r.Method, path)
http.NotFound(w, r)
}
}
@@ -1222,6 +1222,7 @@ func (s *Server) storageDisconnectHandler(w http.ResponseWriter, r *http.Request
return
}
s.logger.Printf("[INFO] [web] Disk disconnect completed: %s (stopped %d stacks)", req.Path, len(stoppedStacks))
if s.isDebug() {
s.logger.Printf("[DEBUG] [web] storageDisconnect: path=%s success, stopped %d stacks", req.Path, len(stoppedStacks))
}
@@ -1264,6 +1265,7 @@ func (s *Server) storageReconnectHandler(w http.ResponseWriter, r *http.Request)
return
}
s.logger.Printf("[INFO] [web] Disk reconnect completed: %s", req.Path)
if s.isDebug() {
s.logger.Printf("[DEBUG] [web] storageReconnect: path=%s success, previously stopped stacks=%v", req.Path, stoppedStacks)
}
@@ -1309,6 +1311,7 @@ func (s *Server) storageRestartAppsHandler(w http.ResponseWriter, r *http.Reques
}
started, failed := s.storageWatchdog.RestartStoppedApps(req.Path)
s.logger.Printf("[INFO] [web] Restart apps for %s: started=%d failed=%d", req.Path, len(started), len(failed))
if s.isDebug() {
s.logger.Printf("[DEBUG] [web] storageRestartApps: path=%s started=%v failed=%v", req.Path, started, failed)
}