model: per-port top source addresses and the span a report's stats cover
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
6663b268c8
commit
cb07e08e7b
2 files changed
+66
-10
No files matched your search
+50
-10
@@ -2,6 +2,7 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
@@ -287,6 +288,42 @@ type Stat struct {
|
||||
Conns int64 `json:"conns"`
|
||||
BytesIn int64 `json:"bytesIn"` // client -> target
|
||||
BytesOut int64 `json:"bytesOut"` // target -> client
|
||||
// Sources are the busiest client addresses behind these numbers (at most MaxSources),
|
||||
// busiest first. Addresses beyond that are only counted in the totals above.
|
||||
Sources []SourceStat `json:"sources,omitempty"`
|
||||
}
|
||||
|
||||
// MaxSources is how many client addresses an edge names per port in one report.
|
||||
const MaxSources = 10
|
||||
|
||||
// SourceStat is one client address's traffic on a port since the last report.
|
||||
type SourceStat struct {
|
||||
IP string `json:"ip"`
|
||||
Conns int64 `json:"conns"`
|
||||
BytesIn int64 `json:"bytesIn"`
|
||||
BytesOut int64 `json:"bytesOut"`
|
||||
}
|
||||
|
||||
// TopSources keeps the n busiest of a port's client addresses (by bytes, then connections), busiest first.
|
||||
func TopSources(all map[string]*SourceStat, n int) []SourceStat {
|
||||
out := make([]SourceStat, 0, len(all))
|
||||
for _, s := range all {
|
||||
out = append(out, *s)
|
||||
}
|
||||
sort.Slice(out, func(i, j int) bool {
|
||||
a, b := out[i], out[j]
|
||||
if ta, tb := a.BytesIn+a.BytesOut, b.BytesIn+b.BytesOut; ta != tb {
|
||||
return ta > tb
|
||||
}
|
||||
if a.Conns != b.Conns {
|
||||
return a.Conns > b.Conns
|
||||
}
|
||||
return a.IP < b.IP
|
||||
})
|
||||
if len(out) > n {
|
||||
out = out[:n]
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// LogEntry is one access-log line.
|
||||
@@ -325,16 +362,19 @@ type ContainerPort struct {
|
||||
|
||||
// EdgeReport is what blacktip posts back.
|
||||
type EdgeReport struct {
|
||||
IPs []string `json:"ips"`
|
||||
PublicKey string `json:"publicKey"` // the edge's WireGuard public key
|
||||
Status map[string]MappingStatus `json:"status"`
|
||||
Stats map[string]Stat `json:"stats"` // deltas since last report
|
||||
Containers []Container `json:"containers"`
|
||||
MailChecks map[string]MailCheck `json:"mailChecks"` // by mail-egress ID
|
||||
Version string `json:"version,omitempty"`
|
||||
AutoUpdate bool `json:"autoUpdate,omitempty"`
|
||||
UpdateMsg string `json:"updateMsg,omitempty"` // outcome of the update asked for by UpdateID
|
||||
UpdateID string `json:"updateId,omitempty"`
|
||||
IPs []string `json:"ips"`
|
||||
PublicKey string `json:"publicKey"` // the edge's WireGuard public key
|
||||
Status map[string]MappingStatus `json:"status"`
|
||||
Stats map[string]Stat `json:"stats"` // deltas since last report
|
||||
// StatsSeconds is how long Stats covers (the time since the previous report that carried them),
|
||||
// so a rate can be worked out however irregular the reports are.
|
||||
StatsSeconds float64 `json:"statsSeconds,omitempty"`
|
||||
Containers []Container `json:"containers"`
|
||||
MailChecks map[string]MailCheck `json:"mailChecks"` // by mail-egress ID
|
||||
Version string `json:"version,omitempty"`
|
||||
AutoUpdate bool `json:"autoUpdate,omitempty"`
|
||||
UpdateMsg string `json:"updateMsg,omitempty"` // outcome of the update asked for by UpdateID
|
||||
UpdateID string `json:"updateId,omitempty"`
|
||||
// progress of that update, for the dashboard's progress bar and log
|
||||
UpdateStage string `json:"updateStage,omitempty"`
|
||||
UpdatePct int `json:"updatePct,omitempty"`
|
||||
|
||||
Reference in new issue
Block a user