From 232103b08cbed120abcff8064d345d788dfbb2b1 Mon Sep 17 00:00:00 2001 From: lirui Date: Sun, 4 Jan 2026 22:06:37 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=BD=91=E7=BB=9C=E6=B5=81?= =?UTF-8?q?=E9=87=8F=E7=9B=91=E6=8E=A7=E6=98=BE=E7=A4=BA=EF=BC=8C=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E5=85=89=E6=A0=87=E6=8E=A7=E5=88=B6=E5=92=8C=E6=B5=81?= =?UTF-8?q?=E9=87=8F=E6=9D=A1=E5=BD=A2=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/nodeprobe/main.go | 100 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 90 insertions(+), 10 deletions(-) diff --git a/cmd/nodeprobe/main.go b/cmd/nodeprobe/main.go index 2d27ad1..c0f7699 100644 --- a/cmd/nodeprobe/main.go +++ b/cmd/nodeprobe/main.go @@ -26,8 +26,9 @@ func main() { // 2. 设置刷新间隔(默认 1 秒) interval := 1 * time.Second - // 3. 打印表头 - printHeader() + // 3. 隐藏光标 + fmt.Print("\033[?25l") + defer fmt.Print("\033[?25h") // 退出时恢复光标 // 4. 创建 ticker 定时器 ticker := time.NewTicker(interval) @@ -37,7 +38,15 @@ func main() { sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM) - // 6. 主循环 + // 6. 首次显示 + clearScreen() + currStats, _ := netstat.GetInterfaceStats() + rates := netstat.CalculateRate(prevStats, currStats, interval) + printHeader() + printStats(rates, currStats) + prevStats = currStats + + // 7. 主循环 for { select { case <-ticker.C: @@ -50,24 +59,38 @@ func main() { // 计算速率 rates := netstat.CalculateRate(prevStats, currStats, interval) - // 打印一行统计 + // 移动光标到开头并打印统计 + moveCursorToTop() + printHeader() printStats(rates, currStats) // 更新上一次的数据 prevStats = currStats case <-sigChan: + fmt.Print("\033[?25h") // 恢复光标 fmt.Println("\nExiting...") return } } } +// 清屏 +func clearScreen() { + fmt.Print("\033[2J") + fmt.Print("\033[H") +} + +// 移动光标到顶部 +func moveCursorToTop() { + fmt.Print("\033[H") +} + func printHeader() { fmt.Println("Network Interface Traffic Monitor") fmt.Println("----------------------------------") - fmt.Printf("%-10s %15s %15s %15s %15s\n", - "Interface", "RX Rate", "TX Rate", "RX Total", "TX Total") + fmt.Printf("%-20s %30s %30s %15s %15s\n", + "Interface", "Download", "Upload", "RX Total", "TX Total") fmt.Println("----------------------------------") } @@ -78,15 +101,72 @@ func printStats(rates []netstat.TrafficRate, stats []netstat.InterfaceStats) { statsMap[s.Name] = s } + // 找出最大速率用于归一化 + maxRate := 0.0 + for _, r := range rates { + if r.RxKbps*1000 > maxRate { + maxRate = r.RxKbps * 1000 + } + if r.TxKbps*1000 > maxRate { + maxRate = r.TxKbps * 1000 + } + } + if maxRate == 0 { + maxRate = 1 + } + for _, r := range rates { s := statsMap[r.Name] - fmt.Printf("%-10s %15s %15s %15s %15s\n", + + // 生成下载和上传的可视化条形图 + rxBar := makeTrafficBar(r.RxKbps*1000, maxRate, true) + txBar := makeTrafficBar(r.TxKbps*1000, maxRate, false) + + fmt.Printf("%-20s %30s %30s %15s %15s\n", r.Name, - netstat.FormatBps(r.RxKbps*1000), - netstat.FormatBps(r.TxKbps*1000), + rxBar, + txBar, netstat.FormatBytes(float64(s.RxBytes)), netstat.FormatBytes(float64(s.TxBytes)), ) } - fmt.Println() + // 清除剩余行(如果接口数量减少) + fmt.Print("\033[J") +} + +// 生成流量条形图 +func makeTrafficBar(bps, maxBps float64, isDownload bool) string { + // ANSI 颜色代码 + green := "\033[32m" // 下载用绿色 + blue := "\033[36m" // 上传用青色 + reset := "\033[0m" + + color := blue + if isDownload { + color = green + } + + // 计算条形图长度(最多10个字符) + barLength := 10 + filledLength := int((bps / maxBps) * float64(barLength)) + if filledLength > barLength { + filledLength = barLength + } + + // 使用不同的字符显示强度 + blocks := []rune{'▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'} + bar := "" + + for i := 0; i < barLength; i++ { + if i < filledLength { + bar += string(blocks[7]) // 满格 + } else { + bar += string(blocks[0]) // 空格 + } + } + + // 格式化速率信息 + speedStr := netstat.FormatBps(bps) + + return fmt.Sprintf("%s%s%s %9s", color, bar, reset, speedStr) }