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:
2026-02-26 18:14:43 +01:00
parent f6caea8067
commit 95c821deb2
54 changed files with 5015 additions and 82 deletions
+29
View File
@@ -10,12 +10,16 @@ import (
"sort"
"strings"
"syscall"
"time"
)
// GetInfo reads system memory, disk, CPU, load, and temperature info.
// hddPath is the mount path for external HDD; if empty, HDD info is skipped.
// cpuCollector provides the latest CPU usage sample; may be nil.
func GetInfo(hddPath string, cpuCollector *CPUCollector) SystemInfo {
start := time.Now()
debugf("[DEBUG] [system] GetInfo starting (hddPath=%q, hasCPUCollector=%v)", hddPath, cpuCollector != nil)
info := SystemInfo{}
// --- Memory from /proc/meminfo ---
@@ -41,6 +45,15 @@ func GetInfo(hddPath string, cpuCollector *CPUCollector) SystemInfo {
info.CPUPercent = cpuCollector.CPUPercent()
}
debugf("[DEBUG] [system] GetInfo done in %s — mem=%dMB/%dMB (%.1f%%), rootDisk=%.1fGB/%.1fGB (%.1f%%), load=%.2f/%.2f/%.2f, temp=%.1f°C (%s), cpu=%.1f%%",
time.Since(start).Round(time.Millisecond),
info.UsedMemMB, info.TotalMemMB, info.MemPercent,
info.DiskUsedGB, info.DiskTotalGB, info.DiskPercent,
info.LoadAvg1, info.LoadAvg5, info.LoadAvg15,
info.TemperatureCelsius, info.TemperatureSource,
info.CPUPercent,
)
return info
}
@@ -67,6 +80,7 @@ func GetMemoryMB() (totalMB, usedMB int, err error) {
func readMemInfo(info *SystemInfo) {
f, err := os.Open("/proc/meminfo")
if err != nil {
debugf("[DEBUG] [system] readMemInfo: failed to open /proc/meminfo: %v", err)
return
}
defer f.Close()
@@ -91,6 +105,10 @@ func readMemInfo(info *SystemInfo) {
info.AvailMemMB = availKB / 1024
info.UsedMemMB = info.TotalMemMB - info.AvailMemMB
info.MemPercent = float64(info.UsedMemMB) / float64(info.TotalMemMB) * 100
debugf("[DEBUG] [system] readMemInfo: totalKB=%d availKB=%d → total=%dMB avail=%dMB used=%dMB (%.1f%%)",
totalKB, availKB, info.TotalMemMB, info.AvailMemMB, info.UsedMemMB, info.MemPercent)
} else {
debugf("[DEBUG] [system] readMemInfo: could not parse MemTotal from /proc/meminfo")
}
}
@@ -116,6 +134,7 @@ func parseMemLine(line string) uint64 {
func readDiskUsage(path string, totalGB, usedGB, availGB *float64, percent *float64) {
var stat syscall.Statfs_t
if err := syscall.Statfs(path, &stat); err != nil {
debugf("[DEBUG] [system] readDiskUsage: statfs(%q) failed: %v", path, err)
return
}
@@ -131,15 +150,20 @@ func readDiskUsage(path string, totalGB, usedGB, availGB *float64, percent *floa
if total > 0 {
*percent = float64(used) / float64(total) * 100
}
debugf("[DEBUG] [system] readDiskUsage: path=%q bsize=%d total=%.1fGB used=%.1fGB avail=%.1fGB (%.1f%%)",
path, bsize, *totalGB, *usedGB, *availGB, *percent)
}
// readLoadAvg reads 1/5/15 minute load averages from /proc/loadavg.
func readLoadAvg(info *SystemInfo) {
data, err := os.ReadFile("/proc/loadavg")
if err != nil {
debugf("[DEBUG] [system] readLoadAvg: failed to read /proc/loadavg: %v", err)
return
}
fmt.Sscanf(string(data), "%f %f %f", &info.LoadAvg1, &info.LoadAvg5, &info.LoadAvg15)
debugf("[DEBUG] [system] readLoadAvg: raw=%q → 1m=%.2f 5m=%.2f 15m=%.2f",
strings.TrimSpace(string(data)), info.LoadAvg1, info.LoadAvg5, info.LoadAvg15)
}
// readTemperature reads CPU/SoC temperature from thermal zones.
@@ -149,6 +173,7 @@ func readTemperature(info *SystemInfo) {
for _, prefix := range prefixes {
if readThermalZones(prefix, info) {
debugf("[DEBUG] [system] readTemperature: found via thermal_zone at %s — %.1f°C (%s)", prefix, info.TemperatureCelsius, info.TemperatureSource)
return
}
}
@@ -156,9 +181,12 @@ func readTemperature(info *SystemInfo) {
// Fallback: try hwmon
for _, prefix := range prefixes {
if readHwmon(prefix, info) {
debugf("[DEBUG] [system] readTemperature: found via hwmon at %s — %.1f°C (%s)", prefix, info.TemperatureCelsius, info.TemperatureSource)
return
}
}
debugf("[DEBUG] [system] readTemperature: no temperature source found")
}
func readThermalZones(sysPrefix string, info *SystemInfo) bool {
@@ -169,6 +197,7 @@ func readThermalZones(sysPrefix string, info *SystemInfo) bool {
}
sort.Strings(matches)
debugf("[DEBUG] [system] readThermalZones: %s — found %d zones", sysPrefix, len(matches))
var maxTemp float64
var maxSource string