- pulse-lets-go-agent: collects metrics from PBX nodes via ESL (FreeSWITCH) or AMI (Asterisk) - AMI client (raw TCP) for Asterisk Manager Interface - Collector interface: collect, connect, subscribe hangup events, close - FreeSWITCH collector: show channels, max_sessions, idle_cpu - Asterisk collector: CoreShowChannels, CoreSettings - System collector: /proc/loadavg, /proc/stat (CPU idle) - Failure tracker: sliding window for call_failure_rate - NATS publisher: pulse.metrics.<node_id> every 5 seconds - Graceful shutdown, retry logic (5 failures → status=down) - Template configs for UC nodes (Asterisk) and ses-sip (FreeSWITCH)
85 lines
1.8 KiB
Go
85 lines
1.8 KiB
Go
package agent
|
|
|
|
import (
|
|
"bufio"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// nowTS возвращает текущий unix timestamp.
|
|
func nowTS() int64 {
|
|
return time.Now().Unix()
|
|
}
|
|
|
|
// SystemStats содержит системные метрики (CPU, load).
|
|
type SystemStats struct {
|
|
Load1 float64 // load average 1m
|
|
Load5 float64 // load average 5m
|
|
Load15 float64 // load average 15m
|
|
IdleCPU float64 // процент простоя CPU
|
|
}
|
|
|
|
// CollectSystem собирает системные метрики из /proc.
|
|
func CollectSystem() *SystemStats {
|
|
load1, load5, load15 := loadAvg()
|
|
return &SystemStats{
|
|
Load1: load1,
|
|
Load5: load5,
|
|
Load15: load15,
|
|
IdleCPU: cpuIdle(),
|
|
}
|
|
}
|
|
|
|
// loadAvg читает /proc/loadavg.
|
|
func loadAvg() (float64, float64, float64) {
|
|
data, err := os.ReadFile("/proc/loadavg")
|
|
if err != nil {
|
|
return 0, 0, 0
|
|
}
|
|
parts := strings.Fields(string(data))
|
|
if len(parts) < 3 {
|
|
return 0, 0, 0
|
|
}
|
|
load1, _ := strconv.ParseFloat(parts[0], 64)
|
|
load5, _ := strconv.ParseFloat(parts[1], 64)
|
|
load15, _ := strconv.ParseFloat(parts[2], 64)
|
|
return load1, load5, load15
|
|
}
|
|
|
|
// cpuIdle вычисляет процент простоя CPU из /proc/stat.
|
|
func cpuIdle() float64 {
|
|
file, err := os.Open("/proc/stat")
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
defer file.Close()
|
|
|
|
scanner := bufio.NewScanner(file)
|
|
for scanner.Scan() {
|
|
line := scanner.Text()
|
|
if !strings.HasPrefix(line, "cpu ") {
|
|
continue
|
|
}
|
|
fields := strings.Fields(line)
|
|
if len(fields) < 8 {
|
|
return 0
|
|
}
|
|
// cpu user nice system idle iowait irq softirq steal ...
|
|
var total, idle float64
|
|
for i, f := range fields[1:] {
|
|
val, _ := strconv.ParseFloat(f, 64)
|
|
total += val
|
|
if i == 3 || i == 4 { // idle + iowait
|
|
idle += val
|
|
}
|
|
}
|
|
if total > 0 {
|
|
return (idle / total) * 100.0
|
|
}
|
|
return 0
|
|
}
|
|
return 0
|
|
}
|