95c821deb2
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>
121 lines
2.7 KiB
Go
121 lines
2.7 KiB
Go
package monitor
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"gitea.dooplex.hu/admin/felhom-controller/internal/config"
|
|
)
|
|
|
|
// Pinger sends health check pings to a Healthchecks.io-compatible server.
|
|
type Pinger struct {
|
|
baseURL string
|
|
httpClient *http.Client
|
|
logger *log.Logger
|
|
enabled bool
|
|
debug bool
|
|
}
|
|
|
|
// NewPinger creates a new Pinger from monitoring config.
|
|
func NewPinger(cfg *config.MonitoringConfig, logger *log.Logger) *Pinger {
|
|
return &Pinger{
|
|
baseURL: strings.TrimRight(cfg.HealthchecksBase, "/"),
|
|
httpClient: &http.Client{
|
|
Timeout: 10 * time.Second,
|
|
},
|
|
logger: logger,
|
|
enabled: cfg.Enabled,
|
|
}
|
|
}
|
|
|
|
// SetDebug enables or disables debug logging for the pinger.
|
|
func (p *Pinger) SetDebug(debug bool) {
|
|
p.debug = debug
|
|
}
|
|
|
|
// Ping sends a success signal with optional diagnostic body.
|
|
func (p *Pinger) Ping(uuid string, body string) error {
|
|
if p.debug {
|
|
p.logger.Printf("[DEBUG] [pinger] Ping uuid=%s body_len=%d", uuid, len(body))
|
|
}
|
|
return p.send(uuid, "", body)
|
|
}
|
|
|
|
// Fail sends a failure signal with diagnostic body.
|
|
func (p *Pinger) Fail(uuid string, body string) error {
|
|
if p.debug {
|
|
p.logger.Printf("[DEBUG] [pinger] Fail uuid=%s body=%q", uuid, body)
|
|
}
|
|
return p.send(uuid, "/fail", body)
|
|
}
|
|
|
|
// Start sends a "job started" signal (for duration tracking).
|
|
func (p *Pinger) Start(uuid string) error {
|
|
if p.debug {
|
|
p.logger.Printf("[DEBUG] [pinger] Start uuid=%s", uuid)
|
|
}
|
|
return p.send(uuid, "/start", "")
|
|
}
|
|
|
|
func (p *Pinger) send(uuid, suffix, body string) error {
|
|
if !p.enabled {
|
|
return nil
|
|
}
|
|
|
|
if uuid == "" || strings.HasPrefix(uuid, "CHANGEME") {
|
|
return nil
|
|
}
|
|
|
|
url := fmt.Sprintf("%s/ping/%s%s", p.baseURL, uuid, suffix)
|
|
if p.debug {
|
|
p.logger.Printf("[DEBUG] [pinger] send url=%s", url)
|
|
}
|
|
|
|
var lastErr error
|
|
for attempt := 0; attempt < 3; attempt++ {
|
|
if attempt > 0 {
|
|
if p.debug {
|
|
p.logger.Printf("[DEBUG] [pinger] retry attempt=%d uuid=%s", attempt+1, uuid)
|
|
}
|
|
time.Sleep(2 * time.Second)
|
|
}
|
|
|
|
var bodyReader io.Reader
|
|
if body != "" {
|
|
bodyReader = strings.NewReader(body)
|
|
}
|
|
|
|
req, err := http.NewRequest(http.MethodPost, url, bodyReader)
|
|
if err != nil {
|
|
lastErr = err
|
|
continue
|
|
}
|
|
|
|
resp, err := p.httpClient.Do(req)
|
|
if err != nil {
|
|
lastErr = err
|
|
continue
|
|
}
|
|
resp.Body.Close()
|
|
|
|
if p.debug {
|
|
p.logger.Printf("[DEBUG] [pinger] response status=%d uuid=%s", resp.StatusCode, uuid)
|
|
}
|
|
|
|
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
|
|
if p.debug {
|
|
p.logger.Printf("[DEBUG] [pinger] success uuid=%s", uuid)
|
|
}
|
|
return nil
|
|
}
|
|
lastErr = fmt.Errorf("HTTP %d", resp.StatusCode)
|
|
}
|
|
|
|
p.logger.Printf("[WARN] Health ping failed after 3 attempts (%s): %v", uuid, lastErr)
|
|
return nil // Never let ping failures affect the caller
|
|
}
|