diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index a86ab6d..745d5ff 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -87,8 +87,19 @@ Environment variables take precedence over `system.json`. | Variable | Description | Default | |----------|-------------|---------| | `FRONTEND_PORT` | Public listening port | `7655` | -| `LOG_LEVEL` | Log verbosity (`debug`, `info`, `warn`, `error`) | `info` | +| `LOG_LEVEL` | Log verbosity (see below) | `info` | | `LOG_FORMAT` | Log output format (`auto`, `json`, `console`) | `auto` | + +#### Log Levels + +| Level | Description | +|-------|-------------| +| `error` | Only errors and critical issues | +| `warn` | Errors + warnings (recommended for minimal logging) | +| `info` | Standard operational messages (startup, connections, alerts) | +| `debug` | Verbose output including per-guest/storage polling details | + +> **Tip**: If your syslog is being flooded with Pulse messages, set `LOG_LEVEL=warn` to significantly reduce log volume while still capturing important events. | `PULSE_PUBLIC_URL` | Public URL for notifications/OIDC | `""` | | `ALLOWED_ORIGINS` | CORS allowed domains | `""` (Same origin) | | `DISCOVERY_ENABLED` | Auto-discover nodes | `false` | diff --git a/docs/DOCKER.md b/docs/DOCKER.md index 9151ae2..54c8294 100644 --- a/docs/DOCKER.md +++ b/docs/DOCKER.md @@ -57,7 +57,9 @@ Pulse is configured via environment variables. | `API_TOKENS` | Comma-separated API tokens | *(unset)* | | `DISCOVERY_SUBNET` | Custom CIDR to scan | *(auto)* | | `ALLOWED_ORIGINS` | CORS allowed domains | *(none)* | -| `LOG_LEVEL` | Log verbosity | `info` | +| `LOG_LEVEL` | Log verbosity (`debug`, `info`, `warn`, `error`) | `info` | + +> **Tip**: Set `LOG_LEVEL=warn` to reduce log volume while still capturing important events.
Advanced: Resource Limits & Healthcheck diff --git a/internal/alerts/alerts.go b/internal/alerts/alerts.go index e623a74..b5de396 100644 --- a/internal/alerts/alerts.go +++ b/internal/alerts/alerts.go @@ -2057,7 +2057,7 @@ func (m *Manager) CheckGuest(guest interface{}, instanceName string) { // Debug logging for high memory VMs if memUsage > 85 { - log.Info(). + log.Debug(). Str("vm", name). Float64("memUsage", memUsage). Str("status", status). @@ -2100,7 +2100,7 @@ func (m *Manager) CheckGuest(guest interface{}, instanceName string) { monitorOnly := settings.MonitorOnly if monitorOnly || m.guestHasMonitorOnlyAlerts(guestID) { - log.Info(). + log.Debug(). Str("guest", name). Bool("monitorOnly", monitorOnly). Msg("Pulse monitor-only status applied") @@ -2185,7 +2185,7 @@ func (m *Manager) CheckGuest(guest interface{}, instanceName string) { } // Check each metric - log.Info(). + log.Debug(). Str("guest", name). Float64("cpu", cpu). Float64("memory", memUsage). @@ -4341,7 +4341,7 @@ func (m *Manager) CheckStorage(storage models.Storage) { // Check usage if storage has valid data (even if not currently active on this node) // In clusters, storage may show as inactive on nodes where it's not currently mounted // but we still want to alert on high usage - log.Info(). + log.Debug(). Str("storage", storage.Name). Str("id", storage.ID). Float64("usage", storage.Usage). @@ -8140,7 +8140,7 @@ func (m *Manager) SaveActiveAlerts() error { return fmt.Errorf("failed to rename active alerts file: %w", err) } - log.Info().Int("count", len(alerts)).Msg("Saved active alerts to disk") + log.Debug().Int("count", len(alerts)).Msg("Saved active alerts to disk") return nil } @@ -8316,7 +8316,7 @@ func (m *Manager) CleanupAlertsForNodes(existingNodes map[string]bool) { m.mu.Lock() defer m.mu.Unlock() - log.Info(). + log.Debug(). Int("totalAlerts", len(m.activeAlerts)). Int("existingNodes", len(existingNodes)). Interface("nodes", existingNodes). @@ -8349,7 +8349,7 @@ func (m *Manager) CleanupAlertsForNodes(existingNodes map[string]bool) { } if removedCount > 0 { - log.Info().Int("removed", removedCount).Int("remaining", len(m.activeAlerts)).Msg("Cleaned up alerts for non-existent nodes") + log.Debug().Int("removed", removedCount).Int("remaining", len(m.activeAlerts)).Msg("Cleaned up alerts for non-existent nodes") // Save the cleaned up state go func() { defer func() { diff --git a/internal/monitoring/monitor.go b/internal/monitoring/monitor.go index 63a1888..6f79513 100644 --- a/internal/monitoring/monitor.go +++ b/internal/monitoring/monitor.go @@ -2219,7 +2219,7 @@ func (m *Monitor) ApplyHostReport(report agentshost.Report, tokenRecord *config. linkedNodeID, linkedVMID, linkedContainerID := m.findLinkedProxmoxEntity(hostname) if linkedNodeID != "" { host.LinkedNodeID = linkedNodeID - log.Info(). + log.Debug(). Str("hostId", identifier). Str("hostname", hostname). Str("linkedNodeId", linkedNodeID). @@ -2227,7 +2227,7 @@ func (m *Monitor) ApplyHostReport(report agentshost.Report, tokenRecord *config. } if linkedVMID != "" { host.LinkedVMID = linkedVMID - log.Info(). + log.Debug(). Str("hostId", identifier). Str("hostname", hostname). Str("linkedVmId", linkedVMID). @@ -2235,7 +2235,7 @@ func (m *Monitor) ApplyHostReport(report agentshost.Report, tokenRecord *config. } if linkedContainerID != "" { host.LinkedContainerID = linkedContainerID - log.Info(). + log.Debug(). Str("hostId", identifier). Str("hostname", hostname). Str("linkedContainerId", linkedContainerID). @@ -5837,7 +5837,7 @@ func (m *Monitor) pollPVEInstance(ctx context.Context, instanceName string, clie // When the instance is part of a cluster, the cluster name is used for guest IDs to prevent duplicates // when multiple cluster nodes are configured as separate PVE instances. func (m *Monitor) pollVMsAndContainersEfficient(ctx context.Context, instanceName string, clusterName string, isCluster bool, client PVEClientInterface, nodeEffectiveStatus map[string]string) bool { - log.Info(). + log.Debug(). Str("instance", instanceName). Str("clusterName", clusterName). Bool("isCluster", isCluster). @@ -6189,7 +6189,7 @@ func (m *Monitor) pollVMsAndContainersEfficient(ctx context.Context, instanceNam } if len(includedFS) > 0 { - log.Info(). + log.Debug(). Str("instance", instanceName). Str("vm", res.Name). Int("vmid", res.VMID). @@ -6223,7 +6223,7 @@ func (m *Monitor) pollVMsAndContainersEfficient(ctx context.Context, instanceNam diskFree = totalBytes - usedBytes diskUsage = safePercentage(float64(usedBytes), float64(totalBytes)) - log.Info(). + log.Debug(). Str("instance", instanceName). Str("vm", res.Name). Int("vmid", res.VMID). @@ -6596,7 +6596,7 @@ func (m *Monitor) pollVMsAndContainersEfficient(ctx context.Context, instanceNam nodesWithResources[res.Node] = true } - log.Info(). + log.Debug(). Str("instance", instanceName). Int("nodesInResources", len(nodesWithResources)). Int("totalVMsFromResources", len(allVMs)). @@ -6719,7 +6719,7 @@ func (m *Monitor) pollVMsAndContainersEfficient(ctx context.Context, instanceNam m.pollReplicationStatus(ctx, instanceName, client, allVMs) - log.Info(). + log.Debug(). Str("instance", instanceName). Int("vms", len(allVMs)). Int("containers", len(allContainers)). diff --git a/internal/monitoring/monitor_polling.go b/internal/monitoring/monitor_polling.go index 7a04e4b..bdbdd01 100644 --- a/internal/monitoring/monitor_polling.go +++ b/internal/monitoring/monitor_polling.go @@ -208,7 +208,7 @@ func (m *Monitor) pollVMsWithNodes(ctx context.Context, instanceName string, clu } } - log.Info(). + log.Debug(). Str("instance", instanceName). Int("totalNodes", len(nodes)). Int("onlineNodes", onlineNodes). @@ -864,7 +864,7 @@ func (m *Monitor) pollVMsWithNodes(ctx context.Context, instanceName string, clu } duration := time.Since(startTime) - log.Info(). + log.Debug(). Str("instance", instanceName). Int("totalVMs", len(allVMs)). Int("successfulNodes", successfulNodes). @@ -913,7 +913,7 @@ func (m *Monitor) pollContainersWithNodes(ctx context.Context, instanceName stri } } - log.Info(). + log.Debug(). Str("instance", instanceName). Int("totalNodes", len(nodes)). Int("onlineNodes", onlineNodes). @@ -1173,7 +1173,7 @@ func (m *Monitor) pollContainersWithNodes(ctx context.Context, instanceName stri } duration := time.Since(startTime) - log.Info(). + log.Debug(). Str("instance", instanceName). Int("totalContainers", len(allContainers)). Int("successfulNodes", successfulNodes). @@ -1236,7 +1236,7 @@ func (m *Monitor) pollStorageWithNodes(ctx context.Context, instanceName string, } } - log.Info(). + log.Debug(). Str("instance", instanceName). Int("totalNodes", len(nodes)). Int("onlineNodes", onlineNodes). @@ -1623,7 +1623,7 @@ func (m *Monitor) pollStorageWithNodes(ctx context.Context, instanceName string, Int("failedNodes", failedNodes). Msg("All nodes failed to retrieve storage - check Proxmox API permissions for Datastore.Audit on all storage") } else { - log.Info(). + log.Debug(). Str("instance", instanceName). Int("totalStorage", len(allStorage)). Int("successfulNodes", successfulNodes).