mirror of
https://github.com/wearepixel/pulsewise-collector.git
synced 2026-11-14 14:01:50 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9365e64cdb | ||
|
|
ef6fa1a07f | ||
|
|
b9b31414b0 | ||
|
|
ebdc5a2c48 |
@@ -15,6 +15,7 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -43,7 +44,7 @@ const (
|
|||||||
const (
|
const (
|
||||||
defaultURL = "https://pulsewise.app/api/collect"
|
defaultURL = "https://pulsewise.app/api/collect"
|
||||||
versionCheckURL = "https://pulsewise.app/collector/release/latest"
|
versionCheckURL = "https://pulsewise.app/collector/release/latest"
|
||||||
collectionInterval = 30 * time.Second
|
collectionInterval = 60 * time.Second
|
||||||
updateCheckInterval = 6 * time.Hour
|
updateCheckInterval = 6 * time.Hour
|
||||||
configFilePath = "/etc/pulsewise-collector/config"
|
configFilePath = "/etc/pulsewise-collector/config"
|
||||||
stateFilePath = "/etc/pulsewise-collector/state"
|
stateFilePath = "/etc/pulsewise-collector/state"
|
||||||
@@ -246,8 +247,7 @@ func main() {
|
|||||||
// ─────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
func runVersionCommand() {
|
func runVersionCommand() {
|
||||||
fmt.Printf("\n %spulsewise-collector%s\n", ansiBold, ansiReset)
|
fmt.Printf("\n %spulsewise-collector %s%sv%s%s\n\n", ansiBold, ansiReset, ansiCyan, version, ansiReset)
|
||||||
fmt.Printf(" %s%sv%s%s\n\n", ansiBold, ansiCyan, version, ansiReset)
|
|
||||||
|
|
||||||
fmt.Printf(" %sChecking for updates...%s ", ansiDim, ansiReset)
|
fmt.Printf(" %sChecking for updates...%s ", ansiDim, ansiReset)
|
||||||
latest, err := fetchLatestVersion()
|
latest, err := fetchLatestVersion()
|
||||||
@@ -270,8 +270,7 @@ func runUpdateCommand() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("\n %spulsewise-collector%s\n", ansiBold, ansiReset)
|
fmt.Printf("\n %spulsewise-collector %s%sv%s%s\n\n", ansiBold, ansiReset, ansiCyan, version, ansiReset)
|
||||||
fmt.Printf(" %s%sv%s%s\n\n", ansiBold, ansiCyan, version, ansiReset)
|
|
||||||
|
|
||||||
fmt.Printf(" %sChecking for updates...%s ", ansiDim, ansiReset)
|
fmt.Printf(" %sChecking for updates...%s ", ansiDim, ansiReset)
|
||||||
latest, err := fetchLatestVersion()
|
latest, err := fetchLatestVersion()
|
||||||
@@ -293,7 +292,7 @@ func runUpdateCommand() {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("%sDone.%s\n", ansiGreen, ansiReset)
|
fmt.Printf("%sDone.%s\n\n", ansiGreen, ansiReset)
|
||||||
fmt.Printf(" Successfully updated to %sv%s%s.\n\n", ansiCyan, latest, ansiReset)
|
fmt.Printf(" Successfully updated to %sv%s%s.\n\n", ansiCyan, latest, ansiReset)
|
||||||
|
|
||||||
restartService()
|
restartService()
|
||||||
@@ -910,12 +909,34 @@ func collectMetrics(config *Config) (*Metrics, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CPU — single sample with percpu=true, then average for the total.
|
// CPU and process collection run concurrently so their measurement
|
||||||
// Calling cpu.Percent twice with separate 1s windows can produce
|
// windows overlap. Previously, processes were sampled 1+ second after
|
||||||
// wildly inconsistent totals vs per-core values.
|
// the CPU window ended, causing spikes to appear in system CPU but not
|
||||||
cpuPerCore, err := cpu.Percent(time.Second, true)
|
// in the process list (the offending process had already finished).
|
||||||
if err != nil {
|
var (
|
||||||
return nil, fmt.Errorf("failed to get CPU percent: %w", err)
|
cpuPerCore []float64
|
||||||
|
cpuErr error
|
||||||
|
processes []ProcessInfo
|
||||||
|
processErr error
|
||||||
|
)
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(2)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
cpuPerCore, cpuErr = cpu.Percent(time.Second, true)
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
processes, processErr = collectTopProcesses()
|
||||||
|
}()
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
if cpuErr != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get CPU percent: %w", cpuErr)
|
||||||
}
|
}
|
||||||
metrics.CPU.PerCore = cpuPerCore
|
metrics.CPU.PerCore = cpuPerCore
|
||||||
if len(cpuPerCore) > 0 {
|
if len(cpuPerCore) > 0 {
|
||||||
@@ -1054,10 +1075,9 @@ func collectMetrics(config *Config) (*Metrics, error) {
|
|||||||
prevNet = current
|
prevNet = current
|
||||||
}
|
}
|
||||||
|
|
||||||
// Top processes
|
// Top processes (collected concurrently with CPU above)
|
||||||
processes, err := collectTopProcesses()
|
if processErr != nil {
|
||||||
if err != nil {
|
log.Printf("Warning: Failed to collect process info: %v", processErr)
|
||||||
log.Printf("Warning: Failed to collect process info: %v", err)
|
|
||||||
metrics.Processes = []ProcessInfo{}
|
metrics.Processes = []ProcessInfo{}
|
||||||
} else {
|
} else {
|
||||||
metrics.Processes = processes
|
metrics.Processes = processes
|
||||||
|
|||||||
Reference in New Issue
Block a user