mirror of
https://github.com/tw93/Mole.git
synced 2026-02-12 06:29:00 +00:00
Merge pull request #321 from iamxorum/network_graph
`mo status`: improve network graph
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
<!-- {"contributors":["tw93","JackPhallen","bhadraagada","amanthanvi","alexandear","rubnogueira","biplavbarua","bsisduck","jimmystridh","fte-jjmartres","Else00","carolyn-sun","MohammedEsafi","ndbroadbent","Sizk","thijsvanhal","yuzeguitarist","zeldrisho","bunizao","frozturk","huyixi","purofle","NanmiCoder","Schlauer-Hax","anonymort","khipu-luke","LmanTW","kwakubiney","kowyo","jalen0x","Hensell","Copper-Eye","ClathW","andmev"],"collaborators":["tw93"],"bots":["github-actions[bot]","dependabot[bot]"]} -->
|
<!-- {"contributors":["tw93","bhadraagada","JackPhallen","amanthanvi","alexandear","rubnogueira","biplavbarua","bsisduck","jimmystridh","fte-jjmartres","Else00","carolyn-sun","MohammedEsafi","ndbroadbent","Sizk","thijsvanhal","yuzeguitarist","zeldrisho","bunizao","frozturk","huyixi","purofle","Schlauer-Hax","anonymort","khipu-luke","LmanTW","kwakubiney","kowyo","jalen0x","Hensell","Copper-Eye","ClathW","andmev"],"collaborators":["iamxorum"],"bots":["github-actions[bot]","dependabot[bot]"]} -->
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1000" height="685">
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1000" height="685">
|
||||||
<style>.contributor-link { cursor: pointer; }</style>
|
<style>.contributor-link { cursor: pointer; }</style>
|
||||||
<g transform="translate(45, 45)">
|
<g transform="translate(45, 45)">
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 325 KiB After Width: | Height: | Size: 325 KiB |
@@ -22,18 +22,19 @@ type MetricsSnapshot struct {
|
|||||||
HealthScore int // 0-100 system health score
|
HealthScore int // 0-100 system health score
|
||||||
HealthScoreMsg string // Brief explanation
|
HealthScoreMsg string // Brief explanation
|
||||||
|
|
||||||
CPU CPUStatus
|
CPU CPUStatus
|
||||||
GPU []GPUStatus
|
GPU []GPUStatus
|
||||||
Memory MemoryStatus
|
Memory MemoryStatus
|
||||||
Disks []DiskStatus
|
Disks []DiskStatus
|
||||||
DiskIO DiskIOStatus
|
DiskIO DiskIOStatus
|
||||||
Network []NetworkStatus
|
Network []NetworkStatus
|
||||||
Proxy ProxyStatus
|
NetworkHistory NetworkHistory
|
||||||
Batteries []BatteryStatus
|
Proxy ProxyStatus
|
||||||
Thermal ThermalStatus
|
Batteries []BatteryStatus
|
||||||
Sensors []SensorReading
|
Thermal ThermalStatus
|
||||||
Bluetooth []BluetoothDevice
|
Sensors []SensorReading
|
||||||
TopProcesses []ProcessInfo
|
Bluetooth []BluetoothDevice
|
||||||
|
TopProcesses []ProcessInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
type HardwareInfo struct {
|
type HardwareInfo struct {
|
||||||
@@ -104,6 +105,12 @@ type NetworkStatus struct {
|
|||||||
TxRateMBs float64
|
TxRateMBs float64
|
||||||
IP string
|
IP string
|
||||||
}
|
}
|
||||||
|
type NetworkHistory struct {
|
||||||
|
RxHistory []float64
|
||||||
|
TxHistory []float64
|
||||||
|
}
|
||||||
|
|
||||||
|
const NetworkHistorySize = 20 // number of checks to keep
|
||||||
|
|
||||||
type ProxyStatus struct {
|
type ProxyStatus struct {
|
||||||
Enabled bool
|
Enabled bool
|
||||||
@@ -156,6 +163,7 @@ type Collector struct {
|
|||||||
// Fast metrics (1s).
|
// Fast metrics (1s).
|
||||||
prevNet map[string]net.IOCountersStat
|
prevNet map[string]net.IOCountersStat
|
||||||
lastNetAt time.Time
|
lastNetAt time.Time
|
||||||
|
netHistory NetworkHistory
|
||||||
lastGPUAt time.Time
|
lastGPUAt time.Time
|
||||||
cachedGPU []GPUStatus
|
cachedGPU []GPUStatus
|
||||||
prevDiskIO disk.IOCountersStat
|
prevDiskIO disk.IOCountersStat
|
||||||
@@ -263,6 +271,7 @@ func (c *Collector) Collect() (MetricsSnapshot, error) {
|
|||||||
Disks: diskStats,
|
Disks: diskStats,
|
||||||
DiskIO: diskIO,
|
DiskIO: diskIO,
|
||||||
Network: netStats,
|
Network: netStats,
|
||||||
|
NetworkHistory: c.netHistory,
|
||||||
Proxy: proxyStats,
|
Proxy: proxyStats,
|
||||||
Batteries: batteryStats,
|
Batteries: batteryStats,
|
||||||
Thermal: thermalStats,
|
Thermal: thermalStats,
|
||||||
|
|||||||
@@ -70,6 +70,20 @@ func (c *Collector) collectNetwork(now time.Time) ([]NetworkStatus, error) {
|
|||||||
result = result[:3]
|
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
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -208,7 +208,7 @@ func buildCards(m MetricsSnapshot, _ int) []cardData {
|
|||||||
renderDiskCard(m.Disks, m.DiskIO),
|
renderDiskCard(m.Disks, m.DiskIO),
|
||||||
renderBatteryCard(m.Batteries, m.Thermal),
|
renderBatteryCard(m.Batteries, m.Thermal),
|
||||||
renderProcessCard(m.TopProcesses),
|
renderProcessCard(m.TopProcesses),
|
||||||
renderNetworkCard(m.Network, m.Proxy),
|
renderNetworkCard(m.Network, m.NetworkHistory, m.Proxy),
|
||||||
}
|
}
|
||||||
if hasSensorData(m.Sensors) {
|
if hasSensorData(m.Sensors) {
|
||||||
cards = append(cards, renderSensorsCard(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))
|
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 lines []string
|
||||||
var totalRx, totalTx float64
|
var totalRx, totalTx float64
|
||||||
var primaryIP string
|
var primaryIP string
|
||||||
@@ -441,10 +441,11 @@ func renderNetworkCard(netStats []NetworkStatus, proxy ProxyStatus) cardData {
|
|||||||
if len(netStats) == 0 {
|
if len(netStats) == 0 {
|
||||||
lines = []string{subtleStyle.Render("Collecting...")}
|
lines = []string{subtleStyle.Render("Collecting...")}
|
||||||
} else {
|
} else {
|
||||||
rxBar := netBar(totalRx)
|
// sparkline graphs
|
||||||
txBar := netBar(totalTx)
|
rxSparkline := sparkline(history.RxHistory, totalRx)
|
||||||
lines = append(lines, fmt.Sprintf("Down %s %s", rxBar, formatRate(totalRx)))
|
txSparkline := sparkline(history.TxHistory, totalTx)
|
||||||
lines = append(lines, fmt.Sprintf("Up %s %s", txBar, formatRate(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.
|
// Show proxy and IP on one line.
|
||||||
var infoParts []string
|
var infoParts []string
|
||||||
if proxy.Enabled {
|
if proxy.Enabled {
|
||||||
@@ -475,6 +476,57 @@ func netBar(rate float64) string {
|
|||||||
return okStyle.Render(bar)
|
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 {
|
func renderBatteryCard(batts []BatteryStatus, thermal ThermalStatus) cardData {
|
||||||
var lines []string
|
var lines []string
|
||||||
if len(batts) == 0 {
|
if len(batts) == 0 {
|
||||||
|
|||||||
Reference in New Issue
Block a user