mirror of
https://github.com/tw93/Mole.git
synced 2026-02-04 18:34:46 +00:00
imp: mo status network graph
This commit is contained in:
@@ -22,18 +22,19 @@ type MetricsSnapshot struct {
|
||||
HealthScore int // 0-100 system health score
|
||||
HealthScoreMsg string // Brief explanation
|
||||
|
||||
CPU CPUStatus
|
||||
GPU []GPUStatus
|
||||
Memory MemoryStatus
|
||||
Disks []DiskStatus
|
||||
DiskIO DiskIOStatus
|
||||
Network []NetworkStatus
|
||||
Proxy ProxyStatus
|
||||
Batteries []BatteryStatus
|
||||
Thermal ThermalStatus
|
||||
Sensors []SensorReading
|
||||
Bluetooth []BluetoothDevice
|
||||
TopProcesses []ProcessInfo
|
||||
CPU CPUStatus
|
||||
GPU []GPUStatus
|
||||
Memory MemoryStatus
|
||||
Disks []DiskStatus
|
||||
DiskIO DiskIOStatus
|
||||
Network []NetworkStatus
|
||||
NetworkHistory NetworkHistory
|
||||
Proxy ProxyStatus
|
||||
Batteries []BatteryStatus
|
||||
Thermal ThermalStatus
|
||||
Sensors []SensorReading
|
||||
Bluetooth []BluetoothDevice
|
||||
TopProcesses []ProcessInfo
|
||||
}
|
||||
|
||||
type HardwareInfo struct {
|
||||
@@ -104,6 +105,12 @@ type NetworkStatus struct {
|
||||
TxRateMBs float64
|
||||
IP string
|
||||
}
|
||||
type NetworkHistory struct {
|
||||
RxHistory []float64
|
||||
TxHistory []float64
|
||||
}
|
||||
|
||||
const NetworkHistorySize = 20 // number of checks to keep
|
||||
|
||||
type ProxyStatus struct {
|
||||
Enabled bool
|
||||
@@ -156,6 +163,7 @@ type Collector struct {
|
||||
// Fast metrics (1s).
|
||||
prevNet map[string]net.IOCountersStat
|
||||
lastNetAt time.Time
|
||||
netHistory NetworkHistory
|
||||
lastGPUAt time.Time
|
||||
cachedGPU []GPUStatus
|
||||
prevDiskIO disk.IOCountersStat
|
||||
@@ -263,6 +271,7 @@ func (c *Collector) Collect() (MetricsSnapshot, error) {
|
||||
Disks: diskStats,
|
||||
DiskIO: diskIO,
|
||||
Network: netStats,
|
||||
NetworkHistory: c.netHistory,
|
||||
Proxy: proxyStats,
|
||||
Batteries: batteryStats,
|
||||
Thermal: thermalStats,
|
||||
|
||||
@@ -70,6 +70,20 @@ func (c *Collector) collectNetwork(now time.Time) ([]NetworkStatus, error) {
|
||||
result = result[:3]
|
||||
}
|
||||
|
||||
var totalRx, totalTx float64
|
||||
for _, r := range result {
|
||||
totalRx += r.RxRateMBs
|
||||
totalTx += r.TxRateMBs
|
||||
}
|
||||
c.netHistory.RxHistory = append(c.netHistory.RxHistory, totalRx)
|
||||
c.netHistory.TxHistory = append(c.netHistory.TxHistory, totalTx)
|
||||
if len(c.netHistory.RxHistory) > NetworkHistorySize {
|
||||
c.netHistory.RxHistory = c.netHistory.RxHistory[len(c.netHistory.RxHistory)-NetworkHistorySize:]
|
||||
}
|
||||
if len(c.netHistory.TxHistory) > NetworkHistorySize {
|
||||
c.netHistory.TxHistory = c.netHistory.TxHistory[len(c.netHistory.TxHistory)-NetworkHistorySize:]
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -208,7 +208,7 @@ func buildCards(m MetricsSnapshot, _ int) []cardData {
|
||||
renderDiskCard(m.Disks, m.DiskIO),
|
||||
renderBatteryCard(m.Batteries, m.Thermal),
|
||||
renderProcessCard(m.TopProcesses),
|
||||
renderNetworkCard(m.Network, m.Proxy),
|
||||
renderNetworkCard(m.Network, m.NetworkHistory, m.Proxy),
|
||||
}
|
||||
if hasSensorData(m.Sensors) {
|
||||
cards = append(cards, renderSensorsCard(m.Sensors))
|
||||
@@ -425,7 +425,7 @@ func miniBar(percent float64) string {
|
||||
return colorizePercent(percent, strings.Repeat("▮", filled)+strings.Repeat("▯", 5-filled))
|
||||
}
|
||||
|
||||
func renderNetworkCard(netStats []NetworkStatus, proxy ProxyStatus) cardData {
|
||||
func renderNetworkCard(netStats []NetworkStatus, history NetworkHistory, proxy ProxyStatus) cardData {
|
||||
var lines []string
|
||||
var totalRx, totalTx float64
|
||||
var primaryIP string
|
||||
@@ -441,10 +441,11 @@ func renderNetworkCard(netStats []NetworkStatus, proxy ProxyStatus) cardData {
|
||||
if len(netStats) == 0 {
|
||||
lines = []string{subtleStyle.Render("Collecting...")}
|
||||
} else {
|
||||
rxBar := netBar(totalRx)
|
||||
txBar := netBar(totalTx)
|
||||
lines = append(lines, fmt.Sprintf("Down %s %s", rxBar, formatRate(totalRx)))
|
||||
lines = append(lines, fmt.Sprintf("Up %s %s", txBar, formatRate(totalTx)))
|
||||
// sparkline graphs
|
||||
rxSparkline := sparkline(history.RxHistory, totalRx)
|
||||
txSparkline := sparkline(history.TxHistory, totalTx)
|
||||
lines = append(lines, fmt.Sprintf("Down %s %s", rxSparkline, formatRate(totalRx)))
|
||||
lines = append(lines, fmt.Sprintf("Up %s %s", txSparkline, formatRate(totalTx)))
|
||||
// Show proxy and IP on one line.
|
||||
var infoParts []string
|
||||
if proxy.Enabled {
|
||||
@@ -475,6 +476,57 @@ func netBar(rate float64) string {
|
||||
return okStyle.Render(bar)
|
||||
}
|
||||
|
||||
// 8 levels: ▁▂▃▄▅▆▇█
|
||||
func sparkline(history []float64, current float64) string {
|
||||
const width = 16
|
||||
blocks := []rune{'▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'}
|
||||
|
||||
data := make([]float64, 0, width)
|
||||
if len(history) > 0 {
|
||||
// Take the most recent points.
|
||||
start := 0
|
||||
if len(history) > width {
|
||||
start = len(history) - width
|
||||
}
|
||||
data = append(data, history[start:]...)
|
||||
}
|
||||
// padding with zeros at the start
|
||||
for len(data) < width {
|
||||
data = append([]float64{0}, data...)
|
||||
}
|
||||
if len(data) > width {
|
||||
data = data[len(data)-width:]
|
||||
}
|
||||
|
||||
maxVal := 0.1
|
||||
for _, v := range data {
|
||||
if v > maxVal {
|
||||
maxVal = v
|
||||
}
|
||||
}
|
||||
|
||||
var builder strings.Builder
|
||||
for _, v := range data {
|
||||
level := int((v / maxVal) * float64(len(blocks)-1))
|
||||
if level < 0 {
|
||||
level = 0
|
||||
}
|
||||
if level >= len(blocks) {
|
||||
level = len(blocks) - 1
|
||||
}
|
||||
builder.WriteRune(blocks[level])
|
||||
}
|
||||
|
||||
result := builder.String()
|
||||
if current > 8 {
|
||||
return dangerStyle.Render(result)
|
||||
}
|
||||
if current > 3 {
|
||||
return warnStyle.Render(result)
|
||||
}
|
||||
return okStyle.Render(result)
|
||||
}
|
||||
|
||||
func renderBatteryCard(batts []BatteryStatus, thermal ThermalStatus) cardData {
|
||||
var lines []string
|
||||
if len(batts) == 0 {
|
||||
|
||||
Reference in New Issue
Block a user