Add link speed and utilization tracking to interface stats

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Ian Gulliver
2026-01-26 12:16:44 -08:00
parent 3255c1cfe5
commit 2af5ad51d7
3 changed files with 106 additions and 27 deletions

View File

@@ -9,9 +9,10 @@ import (
type PortErrorType string
const (
ErrorTypeStartup PortErrorType = "startup"
ErrorTypeNew PortErrorType = "new"
ErrorTypeUnreachable PortErrorType = "unreachable"
ErrorTypeStartup PortErrorType = "startup"
ErrorTypeNew PortErrorType = "new"
ErrorTypeUnreachable PortErrorType = "unreachable"
ErrorTypeHighUtilization PortErrorType = "high_utilization"
)
type PortError struct {
@@ -24,6 +25,7 @@ type PortError struct {
OutErrors uint64 `json:"out_errors"`
InDelta uint64 `json:"in_delta,omitempty"`
OutDelta uint64 `json:"out_delta,omitempty"`
Utilization float64 `json:"utilization,omitempty"`
FirstSeen time.Time `json:"first_seen"`
LastUpdated time.Time `json:"last_updated"`
}
@@ -65,6 +67,59 @@ func (e *ErrorTracker) CheckPort(node *Node, portName string, stats *InterfaceSt
}
}
func (e *ErrorTracker) CheckUtilization(node *Node, portName string, stats *InterfaceStats) {
if stats == nil || stats.Speed == 0 {
return
}
changed := e.checkUtilizationLocked(node, portName, stats)
if changed {
e.t.NotifyUpdate()
}
}
func (e *ErrorTracker) checkUtilizationLocked(node *Node, portName string, stats *InterfaceStats) bool {
e.mu.Lock()
defer e.mu.Unlock()
maxBytesRate := stats.InBytesRate
if stats.OutBytesRate > maxBytesRate {
maxBytesRate = stats.OutBytesRate
}
speedBytes := float64(stats.Speed) / 8.0
utilization := (maxBytesRate / speedBytes) * 100.0
key := "util:" + node.TypeID + ":" + portName
now := time.Now()
if utilization < 70.0 {
return false
}
if existing, ok := e.errors[key]; ok {
if utilization > existing.Utilization {
existing.Utilization = utilization
existing.LastUpdated = now
return true
}
return false
}
e.nextID++
e.errors[key] = &PortError{
ID: fmt.Sprintf("err-%d", e.nextID),
NodeTypeID: node.TypeID,
NodeName: node.DisplayName(),
PortName: portName,
ErrorType: ErrorTypeHighUtilization,
Utilization: utilization,
FirstSeen: now,
LastUpdated: now,
}
return true
}
func (e *ErrorTracker) checkPortLocked(node *Node, portName string, stats *InterfaceStats) bool {
e.mu.Lock()
defer e.mu.Unlock()