Commit 57081b96 authored by vicotor's avatar vicotor

update disk info

parent 319ff52e
Pipeline #887 canceled with stages
...@@ -8,6 +8,7 @@ import ( ...@@ -8,6 +8,7 @@ import (
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
"log" "log"
"net/http" "net/http"
"strings"
"time" "time"
"nodemonitor/types" "nodemonitor/types"
...@@ -17,32 +18,56 @@ var ( ...@@ -17,32 +18,56 @@ var (
serverURL = flag.String("server", "http://localhost:8080", "Server URL") serverURL = flag.String("server", "http://localhost:8080", "Server URL")
interval = flag.Duration("interval", 5*time.Second, "Report interval") interval = flag.Duration("interval", 5*time.Second, "Report interval")
localRpc = flag.String("local-rpc", "", "Local Node RPC URL") localRpc = flag.String("local-rpc", "", "Local Node RPC URL")
diskPaths = flag.String("disks", "/", "Comma-separated list of disk paths to monitor (e.g., /,/data,/logs)")
nameTag = flag.String("name-tag", "", "Name tag") nameTag = flag.String("name-tag", "", "Name tag")
) )
func main() { type AgentConfig struct {
ServerURL string
Interval time.Duration
LocalRpc string
DiskPaths []string
NameTag string
}
func parseConfig() *AgentConfig {
flag.Parse() flag.Parse()
if *nameTag == "" { paths := strings.Split(*diskPaths, ",")
for i, path := range paths {
paths[i] = strings.TrimSpace(path)
}
return &AgentConfig{
ServerURL: *serverURL,
Interval: *interval,
LocalRpc: *localRpc,
DiskPaths: paths,
NameTag: *nameTag,
}
}
func main() {
config := parseConfig()
if config.NameTag == "" {
log.Fatal("name-tag is required") log.Fatal("name-tag is required")
} }
nodeID := *nameTag log.Printf("Starting agent with node ID: %s", config.NameTag)
log.Printf("Starting agent with node ID: %s", nodeID)
log.Printf("Reporting to server: %s", *serverURL) log.Printf("Reporting to server: %s", *serverURL)
ticker := time.NewTicker(*interval) ticker := time.NewTicker(config.Interval)
defer ticker.Stop() defer ticker.Stop()
var nodeClient *ethclient.Client var nodeClient *ethclient.Client
var err error var err error
if len(*localRpc) > 0 { if len(config.LocalRpc) > 0 {
nodeClient, err = ethclient.Dial(*localRpc) nodeClient, err = ethclient.Dial(config.LocalRpc)
if err != nil { if err != nil {
log.Fatalf("Failed to connect to local node RPC: %v", err) log.Fatalf("Failed to connect to local node RPC: %v", err)
} }
} }
for { for {
status := collectNodeStatus(nodeID, nodeClient) status := collectNodeStatus(config, nodeClient)
if err := reportToServer(status); err != nil { if err := reportToServer(status); err != nil {
log.Printf("Failed to report to server: %v", err) log.Printf("Failed to report to server: %v", err)
} else { } else {
...@@ -53,23 +78,21 @@ func main() { ...@@ -53,23 +78,21 @@ func main() {
} }
} }
func collectNodeStatus(nodeID string, nodeClient *ethclient.Client) types.NodeStatus { func collectNodeStatus(conf *AgentConfig, nodeClient *ethclient.Client) types.NodeStatus {
cpuUsage := getCPUUsage() cpuUsage := getCPUUsage()
memUsage, memTotal, memFree := getMemoryInfo() memUsage, memTotal, memFree := getMemoryInfo()
diskUsage, diskTotal, diskFree := getDiskInfo() diskInfos := getDiskInfo(conf.DiskPaths)
privateIP := getPrivateIP() privateIP := getPrivateIP()
publicIP := getPublicIP() publicIP := getPublicIP()
nodeHeight := getNodeHeight(nodeClient) nodeHeight := getNodeHeight(nodeClient)
return types.NodeStatus{ return types.NodeStatus{
NodeID: nodeID, NodeID: conf.NameTag,
CPUUsage: cpuUsage, CPUUsage: cpuUsage,
MemoryUsage: memUsage, MemoryUsage: memUsage,
MemoryTotal: memTotal, MemoryTotal: memTotal,
MemoryFree: memFree, MemoryFree: memFree,
DiskUsage: diskUsage, DiskInfos: diskInfos,
DiskTotal: diskTotal,
DiskFree: diskFree,
PrivateIP: privateIP, PrivateIP: privateIP,
PublicIP: publicIP, PublicIP: publicIP,
Height: nodeHeight, Height: nodeHeight,
......
...@@ -7,6 +7,7 @@ import ( ...@@ -7,6 +7,7 @@ import (
"io" "io"
"net" "net"
"net/http" "net/http"
"nodemonitor/types"
"os" "os"
"strconv" "strconv"
"strings" "strings"
...@@ -74,13 +75,52 @@ func getMemoryInfo() (float64, uint64, uint64) { ...@@ -74,13 +75,52 @@ func getMemoryInfo() (float64, uint64, uint64) {
return v.UsedPercent, v.Total, v.Available return v.UsedPercent, v.Total, v.Available
} }
// getDiskInfo gets disk usage information // getDiskInfo gets disk usage information for multiple paths
func getDiskInfo() (float64, uint64, uint64) { func getDiskInfo(paths []string) []types.DiskInfo {
var diskInfos []types.DiskInfo
// Default paths if none provided
if len(paths) == 0 {
paths = []string{"/"}
}
for _, path := range paths {
usage, err := disk.Usage(path)
if err != nil {
// Add error entry for failed disk
diskInfos = append(diskInfos, types.DiskInfo{
Path: path,
UsedPercent: 0,
Total: 0,
Free: 0,
})
continue
}
diskInfos = append(diskInfos, types.DiskInfo{
Path: path,
UsedPercent: usage.UsedPercent,
Total: usage.Total,
Free: usage.Free,
})
}
return diskInfos
}
// getSystemDiskInfo gets system disk (root) usage
func getSystemDiskInfo() types.DiskInfo {
usage, err := disk.Usage("/") usage, err := disk.Usage("/")
if err != nil { if err != nil {
return 0, 0, 0 return types.DiskInfo{Path: "/", UsedPercent: 0, Total: 0, Free: 0}
}
return types.DiskInfo{
Path: "/",
UsedPercent: usage.UsedPercent,
Total: usage.Total,
Free: usage.Free,
} }
return usage.UsedPercent, usage.Total, usage.Free
} }
// getNodeID generates a unique node identifier // getNodeID generates a unique node identifier
......
...@@ -50,7 +50,6 @@ func (s *Server) handleReport(w http.ResponseWriter, r *http.Request) { ...@@ -50,7 +50,6 @@ func (s *Server) handleReport(w http.ResponseWriter, r *http.Request) {
log.Printf("Received report from node: %s", status.NodeID) log.Printf("Received report from node: %s", status.NodeID)
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
func (s *Server) handleNodes(w http.ResponseWriter, r *http.Request) { func (s *Server) handleNodes(w http.ResponseWriter, r *http.Request) {
s.mutex.RLock() s.mutex.RLock()
nodes := make([]*types.NodeStatus, 0, len(s.nodes)) nodes := make([]*types.NodeStatus, 0, len(s.nodes))
...@@ -75,6 +74,7 @@ func (s *Server) handleNodes(w http.ResponseWriter, r *http.Request) { ...@@ -75,6 +74,7 @@ func (s *Server) handleNodes(w http.ResponseWriter, r *http.Request) {
th { background-color: #f2f2f2; } th { background-color: #f2f2f2; }
.offline { background-color: #ffebee; } .offline { background-color: #ffebee; }
.online { background-color: #e8f5e8; } .online { background-color: #e8f5e8; }
.disk-item { margin-bottom: 5px; }
</style> </style>
</head> </head>
<body> <body>
...@@ -88,8 +88,7 @@ func (s *Server) handleNodes(w http.ResponseWriter, r *http.Request) { ...@@ -88,8 +88,7 @@ func (s *Server) handleNodes(w http.ResponseWriter, r *http.Request) {
<th>CPU Usage (%)</th> <th>CPU Usage (%)</th>
<th>Memory Usage (%)</th> <th>Memory Usage (%)</th>
<th>Memory (Free/Total)</th> <th>Memory (Free/Total)</th>
<th>Disk Usage (%)</th> <th>Disk Information</th>
<th>Disk (Free/Total)</th>
<th>Private IP</th> <th>Private IP</th>
<th>Public IP</th> <th>Public IP</th>
<th>Last Report</th> <th>Last Report</th>
...@@ -102,8 +101,7 @@ func (s *Server) handleNodes(w http.ResponseWriter, r *http.Request) { ...@@ -102,8 +101,7 @@ func (s *Server) handleNodes(w http.ResponseWriter, r *http.Request) {
<td>{{printf "%.2f" .CPUUsage}}</td> <td>{{printf "%.2f" .CPUUsage}}</td>
<td>{{printf "%.2f" .MemoryUsage}}</td> <td>{{printf "%.2f" .MemoryUsage}}</td>
<td>{{.MemoryInfo}}</td> <td>{{.MemoryInfo}}</td>
<td>{{printf "%.2f" .DiskUsage}}</td> <td>{{.AllDisksInfo}}</td>
<td>{{.DiskInfo}}</td>
<td>{{.PrivateIP}}</td> <td>{{.PrivateIP}}</td>
<td>{{.PublicIP}}</td> <td>{{.PublicIP}}</td>
<td>{{.LastReport}}</td> <td>{{.LastReport}}</td>
...@@ -119,7 +117,7 @@ func (s *Server) handleNodes(w http.ResponseWriter, r *http.Request) { ...@@ -119,7 +117,7 @@ func (s *Server) handleNodes(w http.ResponseWriter, r *http.Request) {
Status string Status string
StatusClass string StatusClass string
MemoryInfo string MemoryInfo string
DiskInfo string AllDisksInfo string
LastReport string LastReport string
} }
...@@ -133,12 +131,28 @@ func (s *Server) handleNodes(w http.ResponseWriter, r *http.Request) { ...@@ -133,12 +131,28 @@ func (s *Server) handleNodes(w http.ResponseWriter, r *http.Request) {
statusClass = "offline" statusClass = "offline"
} }
// Format all disk information
var allDisksInfo string
if len(node.DiskInfos) > 0 {
for _, diskInfo := range node.DiskInfos {
mountPoint := diskInfo.Path
usage := diskInfo.UsedPercent * 100
allDisksInfo += fmt.Sprintf("<div class='disk-item'><strong>%s:</strong> %.2f%% (%.2f GB / %.2f GB)</div>",
mountPoint,
usage,
float64(diskInfo.Free)/(1024*1024*1024),
float64(diskInfo.Total)/(1024*1024*1024))
}
} else {
allDisksInfo = "No disk information available"
}
nodeViews[i] = NodeView{ nodeViews[i] = NodeView{
NodeStatus: node, NodeStatus: node,
Status: status, Status: status,
StatusClass: statusClass, StatusClass: statusClass,
MemoryInfo: fmt.Sprintf("%.2f GB / %.2f GB", float64(node.MemoryFree)/(1024*1024*1024), float64(node.MemoryTotal)/(1024*1024*1024)), MemoryInfo: fmt.Sprintf("%.2f GB / %.2f GB", float64(node.MemoryFree)/(1024*1024*1024), float64(node.MemoryTotal)/(1024*1024*1024)),
DiskInfo: fmt.Sprintf("%.2f GB / %.2f GB", float64(node.DiskFree)/(1024*1024*1024), float64(node.DiskTotal)/(1024*1024*1024)), AllDisksInfo: allDisksInfo,
LastReport: node.Timestamp.Format("2006-01-02 15:04:05"), LastReport: node.Timestamp.Format("2006-01-02 15:04:05"),
} }
} }
...@@ -163,7 +177,6 @@ func (s *Server) handleNodes(w http.ResponseWriter, r *http.Request) { ...@@ -163,7 +177,6 @@ func (s *Server) handleNodes(w http.ResponseWriter, r *http.Request) {
return return
} }
} }
func main() { func main() {
flag.Parse() flag.Parse()
......
...@@ -9,12 +9,18 @@ type NodeStatus struct { ...@@ -9,12 +9,18 @@ type NodeStatus struct {
MemoryUsage float64 `json:"memory_usage"` // Memory usage percentage MemoryUsage float64 `json:"memory_usage"` // Memory usage percentage
MemoryTotal uint64 `json:"memory_total"` // Total memory in bytes MemoryTotal uint64 `json:"memory_total"` // Total memory in bytes
MemoryFree uint64 `json:"memory_free"` // Free memory in bytes MemoryFree uint64 `json:"memory_free"` // Free memory in bytes
DiskUsage float64 `json:"disk_usage"` // Disk usage percentage DiskInfos []DiskInfo `json:"disk_infos"` // List of disk usage info
DiskTotal uint64 `json:"disk_total"` // Total disk space in bytes
DiskFree uint64 `json:"disk_free"` // Free disk space in bytes
PrivateIP string `json:"private_ip"` // Internal IP address PrivateIP string `json:"private_ip"` // Internal IP address
PublicIP string `json:"public_ip"` // External IP address PublicIP string `json:"public_ip"` // External IP address
Height string `json:"height"` // Node height (e.g., blockchain height) Height string `json:"height"` // Node height (e.g., blockchain height)
Timestamp time.Time `json:"timestamp"` // Report timestamp Timestamp time.Time `json:"timestamp"` // Report timestamp
LastHeartbeat time.Time `json:"last_heartbeat"` // Last heartbeat time LastHeartbeat time.Time `json:"last_heartbeat"` // Last heartbeat time
} }
// DiskInfo represents disk usage information for a single disk
type DiskInfo struct {
Path string `json:"path"`
UsedPercent float64 `json:"used_percent"`
Total uint64 `json:"total"`
Free uint64 `json:"free"`
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment