Skip to content

Commit d37a463

Browse files
committed
feat: enhance node statistics reporting with version info and improved message handling
1 parent 9312e7c commit d37a463

File tree

2 files changed

+86
-10
lines changed

2 files changed

+86
-10
lines changed

api/analytic/nodes.go

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ import (
77
"github.com/0xJacky/Nginx-UI/internal/analytic"
88
"github.com/0xJacky/Nginx-UI/internal/helper"
99
"github.com/0xJacky/Nginx-UI/internal/kernel"
10+
"github.com/0xJacky/Nginx-UI/internal/version"
1011
"github.com/gin-gonic/gin"
1112
"github.com/gorilla/websocket"
13+
"github.com/shirou/gopsutil/v4/cpu"
1214
"github.com/uozi-tech/cosy/logger"
1315
)
1416

@@ -27,16 +29,61 @@ func GetNodeStat(c *gin.Context) {
2729

2830
defer ws.Close()
2931

32+
// Counter to track iterations for periodic full info update
33+
counter := 0
34+
const fullInfoInterval = 6 // Send full info every 6 iterations (every minute if interval is 10s)
35+
3036
for {
37+
var data interface{}
38+
39+
// Every fullInfoInterval iterations, send complete node information including version
40+
if counter%fullInfoInterval == 0 {
41+
// Get complete node information including version
42+
runtimeInfo, err := version.GetRuntimeInfo()
43+
if err != nil {
44+
logger.Error("Failed to get runtime info:", err)
45+
// Fallback to stat only
46+
data = analytic.GetNodeStat()
47+
} else {
48+
cpuInfo, _ := cpu.Info()
49+
memory, _ := analytic.GetMemoryStat()
50+
ver := version.GetVersionInfo()
51+
diskUsage, _ := analytic.GetDiskStat()
52+
53+
nodeInfo := analytic.NodeInfo{
54+
NodeRuntimeInfo: runtimeInfo,
55+
CPUNum: len(cpuInfo),
56+
MemoryTotal: memory.Total,
57+
DiskTotal: diskUsage.Total,
58+
Version: ver.Version,
59+
}
60+
61+
stat := analytic.GetNodeStat()
62+
63+
// Send complete node information
64+
data = analytic.Node{
65+
NodeInfo: nodeInfo,
66+
NodeStat: stat,
67+
}
68+
69+
logger.Debugf("Sending complete node info including version: %s", ver.Version)
70+
}
71+
} else {
72+
// Send only stat information for performance
73+
data = analytic.GetNodeStat()
74+
}
75+
3176
// write
32-
err = ws.WriteJSON(analytic.GetNodeStat())
77+
err = ws.WriteJSON(data)
3378
if err != nil {
3479
if helper.IsUnexpectedWebsocketError(err) {
3580
logger.Error(err)
3681
}
3782
break
3883
}
3984

85+
counter++
86+
4087
select {
4188
case <-kernel.Context.Done():
4289
return

internal/analytic/node_record.go

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package analytic
22

33
import (
44
"context"
5+
"encoding/json"
56
"fmt"
67
"net/http"
78
"sync"
@@ -650,11 +651,12 @@ func nodeAnalyticRecord(env *model.Environment, ctx context.Context) error {
650651
_ = c.Close()
651652
}()
652653

653-
var nodeStat NodeStat
654654
messageCount := 0
655655

656656
for {
657-
err = c.ReadJSON(&nodeStat)
657+
// Use json.RawMessage to handle both NodeStat and Node types
658+
var rawMsg json.RawMessage
659+
err = c.ReadJSON(&rawMsg)
658660
if err != nil {
659661
if helper.IsUnexpectedWebsocketError(err) {
660662
logger.Debugf("nodeAnalyticRecord: Unexpected WebSocket error for environment ID: %d, error: %v", env.ID, err)
@@ -667,15 +669,42 @@ func nodeAnalyticRecord(env *model.Environment, ctx context.Context) error {
667669
messageCount++
668670
logger.Debugf("nodeAnalyticRecord: Received message #%d from environment ID: %d", messageCount, env.ID)
669671

670-
// set online
671-
nodeStat.Status = true
672-
nodeStat.ResponseAt = time.Now()
673-
674672
mutex.Lock()
675673
if NodeMap[env.ID] != nil {
676-
NodeMap[env.ID].NodeStat = nodeStat
677-
logger.Debugf("nodeAnalyticRecord: Updated NodeStat for environment ID: %d, Status: %t, ResponseAt: %v",
678-
env.ID, nodeStat.Status, nodeStat.ResponseAt)
674+
// Try to unmarshal as complete Node first (contains both NodeInfo and NodeStat)
675+
var fullNode Node
676+
if err := json.Unmarshal(rawMsg, &fullNode); err == nil && fullNode.Version != "" {
677+
// Check if version has changed
678+
oldVersion := NodeMap[env.ID].Version
679+
if oldVersion != "" && oldVersion != fullNode.Version {
680+
logger.Infof("nodeAnalyticRecord: Version updated for environment ID: %d, from %s to %s",
681+
env.ID, oldVersion, fullNode.Version)
682+
}
683+
684+
// This is a complete Node with version info - update everything
685+
NodeMap[env.ID].NodeInfo = fullNode.NodeInfo
686+
NodeMap[env.ID].NodeStat = fullNode.NodeStat
687+
// Ensure status and response time are set
688+
NodeMap[env.ID].NodeStat.Status = true
689+
NodeMap[env.ID].NodeStat.ResponseAt = time.Now()
690+
691+
logger.Debugf("nodeAnalyticRecord: Updated complete Node info for environment ID: %d, Version: %s, Status: %t, ResponseAt: %v",
692+
env.ID, fullNode.Version, NodeMap[env.ID].NodeStat.Status, NodeMap[env.ID].NodeStat.ResponseAt)
693+
} else {
694+
// Fall back to NodeStat only
695+
var nodeStat NodeStat
696+
if err := json.Unmarshal(rawMsg, &nodeStat); err == nil {
697+
// set online
698+
nodeStat.Status = true
699+
nodeStat.ResponseAt = time.Now()
700+
701+
NodeMap[env.ID].NodeStat = nodeStat
702+
logger.Debugf("nodeAnalyticRecord: Updated NodeStat for environment ID: %d, Status: %t, ResponseAt: %v",
703+
env.ID, nodeStat.Status, nodeStat.ResponseAt)
704+
} else {
705+
logger.Debugf("nodeAnalyticRecord: Failed to unmarshal message for environment ID: %d, error: %v", env.ID, err)
706+
}
707+
}
679708
} else {
680709
logger.Debugf("nodeAnalyticRecord: Warning - Node not found in NodeMap for environment ID: %d", env.ID)
681710
}

0 commit comments

Comments
 (0)