Files
2026-06-16 21:52:10 +04:00

83 lines
2.4 KiB
Go

package cluster
import (
"errors"
"fmt"
"math"
"strings"
"pxmon/internal/history"
)
type InterfaceP95Snapshot struct {
ClusterName string `json:"cluster"`
ClusterID string `json:"cluster_id"`
Interface string `json:"interface"`
Range history.RangeShortcut `json:"range"`
Samples int `json:"samples"`
P95Mbps float64 `json:"p95_mbps"`
AvgMbps float64 `json:"avg_mbps"`
MaxMbps float64 `json:"max_mbps"`
Series []history.NodeSamplePoint `json:"series,omitempty"`
}
func (s *Service) CollectInterfaceP95(selector, iface string, rng history.RangeShortcut) (InterfaceP95Snapshot, error) {
iface = strings.TrimSpace(iface)
if iface == "" {
return InterfaceP95Snapshot{}, errors.New("interface is required")
}
c, err := s.Get(selector)
if err != nil {
return InterfaceP95Snapshot{}, err
}
store := s.NetworkStore()
if store == nil {
return InterfaceP95Snapshot{}, errors.New("history store not configured")
}
snaps, err := store.Load(c.ID, rng.Since(s.now()))
if err != nil {
return InterfaceP95Snapshot{}, err
}
series := history.AggregateNodeSeries(snaps, iface)
out := InterfaceP95Snapshot{
ClusterName: c.Name,
ClusterID: c.ID,
Interface: iface,
Range: rng,
Samples: len(series),
P95Mbps: history.PercentileMbps(series, 95),
Series: series,
}
if len(series) == 0 {
return out, nil
}
var sum, maxV float64
for _, p := range series {
sum += p.TotalMbps
if p.TotalMbps > maxV {
maxV = p.TotalMbps
}
}
out.AvgMbps = sum / float64(len(series))
out.MaxMbps = maxV
return out, nil
}
func (s *Service) RenderInterfaceP95GraphPNG(snap InterfaceP95Snapshot) ([]byte, error) {
if len(snap.Series) == 0 {
return history.RenderNodeNetworkPNG([]history.NodeSamplePoint{}, history.ChartOptions{
Title: fmt.Sprintf("%s: %s", snap.ClusterName, snap.Interface),
Subtitle: "No samples",
})
}
subtitle := fmt.Sprintf("P95 %.1f Mbps | max %.1f Mbps | avg %.1f Mbps", snap.P95Mbps, snap.MaxMbps, snap.AvgMbps)
if math.IsNaN(snap.P95Mbps) {
subtitle = "No samples"
}
return history.RenderNodeNetworkPNG(snap.Series, history.ChartOptions{
Title: fmt.Sprintf("%s: %s", snap.ClusterName, snap.Interface),
Subtitle: subtitle,
Percentile: 95,
})
}