Combine PortError and Error into single type

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Ian Gulliver
2026-01-28 21:55:33 -08:00
parent f5d90636bb
commit 41000bd4a0
2 changed files with 44 additions and 70 deletions

102
errors.go
View File

@@ -6,31 +6,29 @@ import (
"time" "time"
) )
type PortErrorType string
const ( const (
ErrorTypeStartup PortErrorType = "startup" ErrorTypeStartup = "startup"
ErrorTypeNew PortErrorType = "new" ErrorTypeNew = "new"
ErrorTypeUnreachable PortErrorType = "unreachable" ErrorTypeUnreachable = "unreachable"
ErrorTypeHighUtilization PortErrorType = "high_utilization" ErrorTypeHighUtilization = "high_utilization"
) )
type PortError struct { type Error struct {
ID string `json:"id"` ID string `json:"id"`
NodeTypeID string `json:"node_typeid"` NodeTypeID string `json:"node_typeid"`
NodeName string `json:"node_name"` NodeName string `json:"node_name"`
PortName string `json:"port_name"` Type string `json:"type"`
ErrorType PortErrorType `json:"error_type"` Port string `json:"port,omitempty"`
InErrors uint64 `json:"in_errors"` InErrors uint64 `json:"in_errors,omitempty"`
OutErrors uint64 `json:"out_errors"` OutErrors uint64 `json:"out_errors,omitempty"`
InDelta uint64 `json:"in_delta,omitempty"` InDelta uint64 `json:"in_delta,omitempty"`
OutDelta uint64 `json:"out_delta,omitempty"` OutDelta uint64 `json:"out_delta,omitempty"`
Utilization float64 `json:"utilization,omitempty"` Utilization float64 `json:"utilization,omitempty"`
FirstSeen time.Time `json:"first_seen"` FirstSeen time.Time `json:"first_seen,omitempty"`
LastUpdated time.Time `json:"last_updated"` LastUpdated time.Time `json:"last_updated,omitempty"`
} }
type portErrorBaseline struct { type errorBaseline struct {
InErrors uint64 InErrors uint64
OutErrors uint64 OutErrors uint64
HasData bool HasData bool
@@ -38,8 +36,8 @@ type portErrorBaseline struct {
type ErrorTracker struct { type ErrorTracker struct {
mu sync.RWMutex mu sync.RWMutex
errors map[string]*PortError errors map[string]*Error
baselines map[string]*portErrorBaseline baselines map[string]*errorBaseline
suppressedUnreachable map[string]bool suppressedUnreachable map[string]bool
unreachableNodes map[string]bool unreachableNodes map[string]bool
nextID int nextID int
@@ -48,8 +46,8 @@ type ErrorTracker struct {
func NewErrorTracker(t *Tendrils) *ErrorTracker { func NewErrorTracker(t *Tendrils) *ErrorTracker {
return &ErrorTracker{ return &ErrorTracker{
errors: map[string]*PortError{}, errors: map[string]*Error{},
baselines: map[string]*portErrorBaseline{}, baselines: map[string]*errorBaseline{},
suppressedUnreachable: map[string]bool{}, suppressedUnreachable: map[string]bool{},
unreachableNodes: map[string]bool{}, unreachableNodes: map[string]bool{},
t: t, t: t,
@@ -107,12 +105,12 @@ func (e *ErrorTracker) checkUtilizationLocked(node *Node, portName string, stats
} }
e.nextID++ e.nextID++
e.errors[key] = &PortError{ e.errors[key] = &Error{
ID: fmt.Sprintf("err-%d", e.nextID), ID: fmt.Sprintf("err-%d", e.nextID),
NodeTypeID: node.TypeID, NodeTypeID: node.TypeID,
NodeName: node.DisplayName(), NodeName: node.DisplayName(),
PortName: portName, Port: portName,
ErrorType: ErrorTypeHighUtilization, Type: ErrorTypeHighUtilization,
Utilization: utilization, Utilization: utilization,
FirstSeen: now, FirstSeen: now,
LastUpdated: now, LastUpdated: now,
@@ -130,22 +128,22 @@ func (e *ErrorTracker) checkPortLocked(node *Node, portName string, stats *Inter
now := time.Now() now := time.Now()
if baseline == nil || !baseline.HasData { if baseline == nil || !baseline.HasData {
e.baselines[key] = &portErrorBaseline{ e.baselines[key] = &errorBaseline{
InErrors: stats.InErrors, InErrors: stats.InErrors,
OutErrors: stats.OutErrors, OutErrors: stats.OutErrors,
HasData: true, HasData: true,
} }
if stats.InErrors > 0 || stats.OutErrors > 0 { if stats.InErrors > 0 || stats.OutErrors > 0 {
e.nextID++ e.nextID++
e.errors[key] = &PortError{ e.errors[key] = &Error{
ID: fmt.Sprintf("err-%d", e.nextID), ID: fmt.Sprintf("err-%d", e.nextID),
NodeTypeID: node.TypeID, NodeTypeID: node.TypeID,
NodeName: node.DisplayName(), NodeName: node.DisplayName(),
PortName: portName, Port: portName,
ErrorType: ErrorTypeStartup, Type: ErrorTypeStartup,
InErrors: stats.InErrors, InErrors: stats.InErrors,
OutErrors: stats.OutErrors, OutErrors: stats.OutErrors,
FirstSeen: now, FirstSeen: now,
LastUpdated: now, LastUpdated: now,
} }
return true return true
@@ -172,12 +170,12 @@ func (e *ErrorTracker) checkPortLocked(node *Node, portName string, stats *Inter
existing.LastUpdated = now existing.LastUpdated = now
} else { } else {
e.nextID++ e.nextID++
e.errors[key] = &PortError{ e.errors[key] = &Error{
ID: fmt.Sprintf("err-%d", e.nextID), ID: fmt.Sprintf("err-%d", e.nextID),
NodeTypeID: node.TypeID, NodeTypeID: node.TypeID,
NodeName: node.DisplayName(), NodeName: node.DisplayName(),
PortName: portName, Port: portName,
ErrorType: ErrorTypeNew, Type: ErrorTypeNew,
InErrors: stats.InErrors, InErrors: stats.InErrors,
OutErrors: stats.OutErrors, OutErrors: stats.OutErrors,
InDelta: inDelta, InDelta: inDelta,
@@ -208,7 +206,7 @@ func (e *ErrorTracker) clearErrorLocked(errorID string) bool {
for key, err := range e.errors { for key, err := range e.errors {
if err.ID == errorID { if err.ID == errorID {
if err.ErrorType == ErrorTypeUnreachable { if err.Type == ErrorTypeUnreachable {
e.suppressedUnreachable[key] = true e.suppressedUnreachable[key] = true
} }
delete(e.errors, key) delete(e.errors, key)
@@ -231,11 +229,11 @@ func (e *ErrorTracker) clearAllErrorsLocked() bool {
had := len(e.errors) > 0 had := len(e.errors) > 0
for key, err := range e.errors { for key, err := range e.errors {
if err.ErrorType == ErrorTypeUnreachable { if err.Type == ErrorTypeUnreachable {
e.suppressedUnreachable[key] = true e.suppressedUnreachable[key] = true
} }
} }
e.errors = map[string]*PortError{} e.errors = map[string]*Error{}
return had return had
} }
@@ -245,18 +243,7 @@ func (e *ErrorTracker) GetErrors() []*Error {
errors := make([]*Error, 0, len(e.errors)) errors := make([]*Error, 0, len(e.errors))
for _, err := range e.errors { for _, err := range e.errors {
errors = append(errors, &Error{ errors = append(errors, err)
ID: err.ID,
NodeTypeID: err.NodeTypeID,
NodeName: err.NodeName,
Type: string(err.ErrorType),
Port: err.PortName,
InErrors: err.InErrors,
OutErrors: err.OutErrors,
InDelta: err.InDelta,
OutDelta: err.OutDelta,
Utilization: err.Utilization,
})
} }
return errors return errors
} }
@@ -300,12 +287,11 @@ func (e *ErrorTracker) setUnreachableLocked(node *Node) (changed bool, becameUnr
now := time.Now() now := time.Now()
e.nextID++ e.nextID++
e.errors[key] = &PortError{ e.errors[key] = &Error{
ID: fmt.Sprintf("err-%d", e.nextID), ID: fmt.Sprintf("err-%d", e.nextID),
NodeTypeID: node.TypeID, NodeTypeID: node.TypeID,
NodeName: node.DisplayName(), NodeName: node.DisplayName(),
PortName: "", Type: ErrorTypeUnreachable,
ErrorType: ErrorTypeUnreachable,
FirstSeen: now, FirstSeen: now,
LastUpdated: now, LastUpdated: now,
} }

12
http.go
View File

@@ -32,18 +32,6 @@ type StatusResponse struct {
BroadcastStats *BroadcastStatsResponse `json:"broadcast_stats,omitempty"` BroadcastStats *BroadcastStatsResponse `json:"broadcast_stats,omitempty"`
} }
type Error struct {
ID string `json:"id"`
NodeTypeID string `json:"node_typeid"`
NodeName string `json:"node_name"`
Type string `json:"type"`
Port string `json:"port,omitempty"`
InErrors uint64 `json:"in_errors,omitempty"`
OutErrors uint64 `json:"out_errors,omitempty"`
InDelta uint64 `json:"in_delta,omitempty"`
OutDelta uint64 `json:"out_delta,omitempty"`
Utilization float64 `json:"utilization,omitempty"`
}
func (t *Tendrils) startHTTPServer() { func (t *Tendrils) startHTTPServer() {
if err := ensureCert(); err != nil { if err := ensureCert(); err != nil {