Commit 57081b96 authored by vicotor's avatar vicotor

update disk info

parent 319ff52e
Pipeline #887 canceled with stages
......@@ -8,6 +8,7 @@ import (
"github.com/ethereum/go-ethereum/ethclient"
"log"
"net/http"
"strings"
"time"
"nodemonitor/types"
......@@ -17,32 +18,56 @@ var (
serverURL = flag.String("server", "http://localhost:8080", "Server URL")
interval = flag.Duration("interval", 5*time.Second, "Report interval")
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")
)
func main() {
type AgentConfig struct {
ServerURL string
Interval time.Duration
LocalRpc string
DiskPaths []string
NameTag string
}
func parseConfig() *AgentConfig {
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")
}
nodeID := *nameTag
log.Printf("Starting agent with node ID: %s", nodeID)
log.Printf("Starting agent with node ID: %s", config.NameTag)
log.Printf("Reporting to server: %s", *serverURL)
ticker := time.NewTicker(*interval)
ticker := time.NewTicker(config.Interval)
defer ticker.Stop()
var nodeClient *ethclient.Client
var err error
if len(*localRpc) > 0 {
nodeClient, err = ethclient.Dial(*localRpc)
if len(config.LocalRpc) > 0 {
nodeClient, err = ethclient.Dial(config.LocalRpc)
if err != nil {
log.Fatalf("Failed to connect to local node RPC: %v", err)
}
}
for {
status := collectNodeStatus(nodeID, nodeClient)
status := collectNodeStatus(config, nodeClient)
if err := reportToServer(status); err != nil {
log.Printf("Failed to report to server: %v", err)
} else {
......@@ -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()
memUsage, memTotal, memFree := getMemoryInfo()
diskUsage, diskTotal, diskFree := getDiskInfo()
diskInfos := getDiskInfo(conf.DiskPaths)
privateIP := getPrivateIP()
publicIP := getPublicIP()
nodeHeight := getNodeHeight(nodeClient)
return types.NodeStatus{
NodeID: nodeID,
NodeID: conf.NameTag,
CPUUsage: cpuUsage,
MemoryUsage: memUsage,
MemoryTotal: memTotal,
MemoryFree: memFree,
DiskUsage: diskUsage,
DiskTotal: diskTotal,
DiskFree: diskFree,
DiskInfos: diskInfos,
PrivateIP: privateIP,
PublicIP: publicIP,
Height: nodeHeight,
......
......@@ -7,6 +7,7 @@ import (
"io"
"net"
"net/http"
"nodemonitor/types"
"os"
"strconv"
"strings"
......@@ -74,13 +75,52 @@ func getMemoryInfo() (float64, uint64, uint64) {
return v.UsedPercent, v.Total, v.Available
}
// getDiskInfo gets disk usage information
func getDiskInfo() (float64, uint64, uint64) {
// getDiskInfo gets disk usage information for multiple paths
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("/")
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
......
......@@ -50,7 +50,6 @@ func (s *Server) handleReport(w http.ResponseWriter, r *http.Request) {
log.Printf("Received report from node: %s", status.NodeID)
w.WriteHeader(http.StatusOK)
}
func (s *Server) handleNodes(w http.ResponseWriter, r *http.Request) {
s.mutex.RLock()
nodes := make([]*types.NodeStatus, 0, len(s.nodes))
......@@ -75,6 +74,7 @@ func (s *Server) handleNodes(w http.ResponseWriter, r *http.Request) {
th { background-color: #f2f2f2; }
.offline { background-color: #ffebee; }
.online { background-color: #e8f5e8; }
.disk-item { margin-bottom: 5px; }
</style>
</head>
<body>
......@@ -84,12 +84,11 @@ func (s *Server) handleNodes(w http.ResponseWriter, r *http.Request) {
<tr>
<th>Node ID</th>
<th>Status</th>
<th>Height</th>
<th>Height</th>
<th>CPU Usage (%)</th>
<th>Memory Usage (%)</th>
<th>Memory (Free/Total)</th>
<th>Disk Usage (%)</th>
<th>Disk (Free/Total)</th>
<th>Disk Information</th>
<th>Private IP</th>
<th>Public IP</th>
<th>Last Report</th>
......@@ -98,12 +97,11 @@ func (s *Server) handleNodes(w http.ResponseWriter, r *http.Request) {
<tr class="{{.StatusClass}}">
<td>{{.NodeID}}</td>
<td>{{.Status}}</td>
<td>{{.Height}}</td>
<td>{{.Height}}</td>
<td>{{printf "%.2f" .CPUUsage}}</td>
<td>{{printf "%.2f" .MemoryUsage}}</td>
<td>{{.MemoryInfo}}</td>
<td>{{printf "%.2f" .DiskUsage}}</td>
<td>{{.DiskInfo}}</td>
<td>{{.AllDisksInfo}}</td>
<td>{{.PrivateIP}}</td>
<td>{{.PublicIP}}</td>
<td>{{.LastReport}}</td>
......@@ -116,11 +114,11 @@ func (s *Server) handleNodes(w http.ResponseWriter, r *http.Request) {
type NodeView struct {
*types.NodeStatus
Status string
StatusClass string
MemoryInfo string
DiskInfo string
LastReport string
Status string
StatusClass string
MemoryInfo string
AllDisksInfo string
LastReport string
}
nodeViews := make([]NodeView, len(nodes))
......@@ -133,13 +131,29 @@ func (s *Server) handleNodes(w http.ResponseWriter, r *http.Request) {
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{
NodeStatus: node,
Status: status,
StatusClass: statusClass,
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)),
LastReport: node.Timestamp.Format("2006-01-02 15:04:05"),
NodeStatus: node,
Status: status,
StatusClass: statusClass,
MemoryInfo: fmt.Sprintf("%.2f GB / %.2f GB", float64(node.MemoryFree)/(1024*1024*1024), float64(node.MemoryTotal)/(1024*1024*1024)),
AllDisksInfo: allDisksInfo,
LastReport: node.Timestamp.Format("2006-01-02 15:04:05"),
}
}
......@@ -163,7 +177,6 @@ func (s *Server) handleNodes(w http.ResponseWriter, r *http.Request) {
return
}
}
func main() {
flag.Parse()
......
......@@ -4,17 +4,23 @@ import "time"
// NodeStatus represents the status information of a node
type NodeStatus struct {
NodeID string `json:"node_id"`
CPUUsage float64 `json:"cpu_usage"` // CPU usage percentage
MemoryUsage float64 `json:"memory_usage"` // Memory usage percentage
MemoryTotal uint64 `json:"memory_total"` // Total memory in bytes
MemoryFree uint64 `json:"memory_free"` // Free memory in bytes
DiskUsage float64 `json:"disk_usage"` // Disk usage percentage
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
PublicIP string `json:"public_ip"` // External IP address
Height string `json:"height"` // Node height (e.g., blockchain height)
Timestamp time.Time `json:"timestamp"` // Report timestamp
LastHeartbeat time.Time `json:"last_heartbeat"` // Last heartbeat time
NodeID string `json:"node_id"`
CPUUsage float64 `json:"cpu_usage"` // CPU usage percentage
MemoryUsage float64 `json:"memory_usage"` // Memory usage percentage
MemoryTotal uint64 `json:"memory_total"` // Total memory in bytes
MemoryFree uint64 `json:"memory_free"` // Free memory in bytes
DiskInfos []DiskInfo `json:"disk_infos"` // List of disk usage info
PrivateIP string `json:"private_ip"` // Internal IP address
PublicIP string `json:"public_ip"` // External IP address
Height string `json:"height"` // Node height (e.g., blockchain height)
Timestamp time.Time `json:"timestamp"` // Report timestamp
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