mirror of
https://github.com/gogrlx/nats-server.git
synced 2026-04-02 03:38:42 -07:00
WIP: theoretically, populate expvar maps
This commit is contained in:
@@ -4503,6 +4503,8 @@ func (c *client) diagnosticsLoop() {
|
||||
c.mu.Unlock()
|
||||
return
|
||||
}
|
||||
expvarMaps := s.diagnosticExpvarMaps
|
||||
routeID := c.route.remoteID
|
||||
c.mu.Unlock()
|
||||
var err error
|
||||
for {
|
||||
@@ -4519,7 +4521,7 @@ func (c *client) diagnosticsLoop() {
|
||||
}
|
||||
return
|
||||
}
|
||||
(&c.diagMetrics).PopulateFromTCPDiagnostics(&c.diagTCPData)
|
||||
(&c.diagMetrics).PopulateFromTCPDiagnostics(&c.diagTCPData, expvarMaps, routeID)
|
||||
c.mu.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,6 +224,9 @@ type Server struct {
|
||||
|
||||
// exporting account name the importer experienced issues with
|
||||
incompleteAccExporterMap sync.Map
|
||||
|
||||
// Diagnostic metrics maps
|
||||
diagnosticExpvarMaps *TCPInfoExpMaps
|
||||
}
|
||||
|
||||
// Make sure all are 64bits for atomic use
|
||||
@@ -295,18 +298,19 @@ func NewServer(opts *Options) (*Server, error) {
|
||||
now := time.Now()
|
||||
|
||||
s := &Server{
|
||||
kp: kp,
|
||||
configFile: opts.ConfigFile,
|
||||
info: info,
|
||||
prand: rand.New(rand.NewSource(time.Now().UnixNano())),
|
||||
opts: opts,
|
||||
done: make(chan bool, 1),
|
||||
start: now,
|
||||
configTime: now,
|
||||
gwLeafSubs: NewSublistWithCache(),
|
||||
httpBasePath: httpBasePath,
|
||||
eventIds: nuid.New(),
|
||||
routesToSelf: make(map[string]struct{}),
|
||||
kp: kp,
|
||||
configFile: opts.ConfigFile,
|
||||
info: info,
|
||||
prand: rand.New(rand.NewSource(time.Now().UnixNano())),
|
||||
opts: opts,
|
||||
done: make(chan bool, 1),
|
||||
start: now,
|
||||
configTime: now,
|
||||
gwLeafSubs: NewSublistWithCache(),
|
||||
httpBasePath: httpBasePath,
|
||||
eventIds: nuid.New(),
|
||||
routesToSelf: make(map[string]struct{}),
|
||||
diagnosticExpvarMaps: NewTCPInfoExpMaps(),
|
||||
}
|
||||
|
||||
// Trusted root operator keys.
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"expvar"
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
@@ -106,7 +107,44 @@ type TCPInfoExpMetrics struct {
|
||||
RTTVariance expvar.Int
|
||||
}
|
||||
|
||||
func (m *TCPInfoExpMetrics) PopulateFromTCPDiagnostics(d *TCPDiagnostics) {
|
||||
type TCPInfoExpMaps struct {
|
||||
UnreadData *expvar.Map
|
||||
UnsentData *expvar.Map
|
||||
UnAckedPackets *expvar.Map
|
||||
LostPackets *expvar.Map
|
||||
RetransOutPackets *expvar.Map
|
||||
TotalRetransPackets *expvar.Map
|
||||
PathMTU *expvar.Map
|
||||
LastDataSentMSec *expvar.Map
|
||||
LastDataRecvMSec *expvar.Map
|
||||
RTT *expvar.Map
|
||||
RTTVariance *expvar.Map
|
||||
}
|
||||
|
||||
// Reflection note: we're using reflection once at startup, for maps
|
||||
// population, and once each time a new ID for a client is seen (eg, new
|
||||
// gateway), not on reconnect, so this should be rare enough that Reflection
|
||||
// should be better than repeating all those field-names yet another time. I
|
||||
// could possibly construct TCPInfoExpMaps dynamically but ... let's not go
|
||||
// down that hole.
|
||||
|
||||
// NewTCPInfoExpMaps should only be called once in a given process.
|
||||
func NewTCPInfoExpMaps() *TCPInfoExpMaps {
|
||||
all := TCPInfoExpMaps{}
|
||||
t := reflect.TypeOf(&all).Elem()
|
||||
v := reflect.ValueOf(&all).Elem()
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
m := expvar.NewMap(t.Field(i).Name)
|
||||
v.Field(i).Set(reflect.ValueOf(m))
|
||||
}
|
||||
return &all
|
||||
}
|
||||
|
||||
func (m *TCPInfoExpMetrics) PopulateFromTCPDiagnostics(d *TCPDiagnostics, maps *TCPInfoExpMaps, fullLabel string) {
|
||||
// Might need to switch the label to be sanitized; we'll see.
|
||||
if v := maps.UnreadData.Get(fullLabel); v == nil {
|
||||
populateExpvarMapsTCPDiagnostics(maps, fullLabel, m)
|
||||
}
|
||||
m.UnreadData.Set(int64(d.UnreadData))
|
||||
m.UnsentData.Set(int64(d.UnsentData))
|
||||
m.UnAckedPackets.Set(int64(d.Info.Unacked))
|
||||
@@ -119,3 +157,16 @@ func (m *TCPInfoExpMetrics) PopulateFromTCPDiagnostics(d *TCPDiagnostics) {
|
||||
m.RTT.Set(int64(d.Info.Rtt))
|
||||
m.RTTVariance.Set(int64(d.Info.Rttvar))
|
||||
}
|
||||
|
||||
// Theoretically this could race against itself, but it would require two
|
||||
// callers for a given fullLabel, in different go-routines, so I'm skipping
|
||||
// that guard (to avoid complicating the reflect iteration with handling an
|
||||
// exception for a mutex, or moving the maps into a sub-struct).
|
||||
func populateExpvarMapsTCPDiagnostics(maps *TCPInfoExpMaps, fullLabel string, metrics *TCPInfoExpMetrics) {
|
||||
tm := reflect.TypeOf(maps).Elem()
|
||||
vm := reflect.ValueOf(maps).Elem()
|
||||
vmetrics := reflect.ValueOf(metrics)
|
||||
for i := 0; i < vm.NumField(); i++ {
|
||||
vm.Field(i).Interface().(*expvar.Map).Set(fullLabel, vmetrics.FieldByName(tm.Field(i).Name))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
type TCPInfo struct{}
|
||||
type TCPDiagnostics struct{}
|
||||
type TCPInfoExpMetrics struct{}
|
||||
type TCPInfoExpMaps struct{}
|
||||
|
||||
var ErrNotSupported = errors.New("error: operation not supported on this platform")
|
||||
|
||||
@@ -37,6 +38,11 @@ func GetSocketTCPDiagnostics(conn *net.TCPConn, diag *TCPDiagnostics) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (m *TCPInfoExpMetrics) PopulateFromTCPDiagnostics(d *TCPDiagnostics) {}
|
||||
func (m *TCPInfoExpMetrics) PopulateFromTCPDiagnostics(d *TCPDiagnostics, maps *TCPInfoExpMaps, fullLabel string) {
|
||||
}
|
||||
|
||||
func NewTCPInfoExpMaps() *TCPInfoExpMaps {
|
||||
return &TCPInfoExpMaps{}
|
||||
}
|
||||
|
||||
// There will be other functions here, as we populate maps.
|
||||
|
||||
Reference in New Issue
Block a user