83 lines
2.4 KiB
Go
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,
|
|
})
|
|
}
|