Maksim Totmin 1e6f432230 feat: metrics agent for FreeSWITCH and Asterisk nodes
- 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)
2026-06-25 16:59:10 +07:00

58 lines
1.3 KiB
Go

package agent
import (
"encoding/json"
"fmt"
"log"
natsgo "github.com/nats-io/nats.go"
"github.com/pulse-lets-go/internal/models"
)
// Publisher публикует метрики в NATS.
type Publisher struct {
nc *natsgo.Conn
nodeID string
}
// NewPublisher создаёт NATS publisher.
func NewPublisher(natsURL, user, password, nodeID string) (*Publisher, error) {
opts := []natsgo.Option{
natsgo.ReconnectWait(natsgo.DefaultReconnectWait),
natsgo.MaxReconnects(-1),
}
if user != "" && password != "" {
opts = append(opts, natsgo.UserInfo(user, password))
}
nc, err := natsgo.Connect(natsURL, opts...)
if err != nil {
return nil, fmt.Errorf("nats connect: %w", err)
}
log.Printf("[publisher] NATS подключён к %s", natsURL)
return &Publisher{nc: nc, nodeID: nodeID}, nil
}
// Publish отправляет метрику в NATS: pulse.metrics.<node_id>.
func (p *Publisher) Publish(m *models.NodeMetric) error {
subject := fmt.Sprintf("pulse.metrics.%s", p.nodeID)
data, err := json.Marshal(m)
if err != nil {
return fmt.Errorf("marshal metric: %w", err)
}
if err := p.nc.Publish(subject, data); err != nil {
return fmt.Errorf("publish: %w", err)
}
return nil
}
// Close закрывает NATS-соединение.
func (p *Publisher) Close() {
if p.nc != nil {
p.nc.Close()
}
}