Commit 9608d37d authored by liming6's avatar liming6
Browse files

fix 修复折线图的bug

parent acd70ae1
...@@ -26,9 +26,8 @@ const ( ...@@ -26,9 +26,8 @@ const (
BottomLine = `╞═══════════════════════════════╧══════════════════════╧══════════════════════╪` BottomLine = `╞═══════════════════════════════╧══════════════════════╧══════════════════════╪`
OtherWidth = 8 OtherWidth = 8
StaticWidth = 87 // 固定表格的宽度 StaticWidth = 79 // 固定表格的宽度
ProgressMaxWidth = 105 // 进度条最大宽度 ProgressMinWidth = 15 // 进度条最小宽度
ProgressMinWidth = 15 // 进度条最小宽度
) )
func (m *ModelDCUInfo) Init() tea.Cmd { func (m *ModelDCUInfo) Init() tea.Cmd {
...@@ -36,10 +35,8 @@ func (m *ModelDCUInfo) Init() tea.Cmd { ...@@ -36,10 +35,8 @@ func (m *ModelDCUInfo) Init() tea.Cmd {
return tea.Quit return tea.Quit
} }
m.proWidth = ProgressMinWidth m.proWidth = ProgressMinWidth
if m.width > StaticWidth+ProgressMaxWidth { if m.width > StaticWidth+ProgressMinWidth+OtherWidth {
m.proWidth = ProgressMaxWidth m.proWidth = m.width - OtherWidth - StaticWidth
} else {
m.proWidth = m.width - StaticWidth
} }
m.pro = progress.New(progress.WithDefaultGradient(), progress.WithWidth(m.proWidth)) m.pro = progress.New(progress.WithDefaultGradient(), progress.WithWidth(m.proWidth))
return nil return nil
...@@ -127,7 +124,7 @@ func (m *ModelDCUInfo) View() string { ...@@ -127,7 +124,7 @@ func (m *ModelDCUInfo) View() string {
if len(infos) > 0 { if len(infos) > 0 {
lineWidth = lipgloss.Width(infos[0]) lineWidth = lipgloss.Width(infos[0])
} }
subLen := lineWidth - StaticWidth + OtherWidth - 1 subLen := lineWidth - StaticWidth - 1
if subLen <= 0 { if subLen <= 0 {
subLen = 0 subLen = 0
} }
......
...@@ -44,7 +44,7 @@ func NewModelMain(width, height int) ModelMain { ...@@ -44,7 +44,7 @@ func NewModelMain(width, height int) ModelMain {
result.height = height result.height = height
result.Header = &ModelHeader{} result.Header = &ModelHeader{}
result.DCUInfo = &ModelDCUInfo{width: width, height: height, info: make(map[int]backend.DCUInfo)} result.DCUInfo = &ModelDCUInfo{width: width, height: height, info: make(map[int]backend.DCUInfo)}
result.SysLoad = NewModelSysLoad(100) result.SysLoad = NewModelSysLoad(width)
return result return result
} }
...@@ -95,13 +95,13 @@ func (m *ModelMain) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) { ...@@ -95,13 +95,13 @@ func (m *ModelMain) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) {
case TickMsg: // 定时事件 case TickMsg: // 定时事件
m.index++ m.index++
updateModelInfo(m.modelMsg, m.index, time.Time(msg)) updateModelInfo(m.modelMsg, m.index, time.Time(msg))
cmds := make([]tea.Cmd, 0) header, _ := m.Header.Update(m.modelMsg)
header, cmdHeader := m.Header.Update(m.modelMsg) dcuInfo, _ := m.DCUInfo.Update(m.modelMsg)
dcuInfo, dcuHeader := m.DCUInfo.Update(m.modelMsg) sysLoad, _ := m.SysLoad.Update(m.modelMsg)
m.Header = header.(*ModelHeader) m.Header = header.(*ModelHeader)
m.DCUInfo = dcuInfo.(*ModelDCUInfo) m.DCUInfo = dcuInfo.(*ModelDCUInfo)
cmds = append(cmds, cmdHeader, dcuHeader, tickCmd()) m.SysLoad = sysLoad.(*ModelSysLoad)
return m, tea.Batch(cmds...) return m, tickCmd()
case ModelMsg: // 初始化 case ModelMsg: // 初始化
header, _ := m.Header.Update(m.modelMsg) header, _ := m.Header.Update(m.modelMsg)
dcuInfo, _ := m.DCUInfo.Update(m.modelMsg) dcuInfo, _ := m.DCUInfo.Update(m.modelMsg)
...@@ -157,7 +157,7 @@ func initModelInfo(model *ModelMsg) error { ...@@ -157,7 +157,7 @@ func initModelInfo(model *ModelMsg) error {
func updateModelInfo(modelMsg *ModelMsg, index uint64, t time.Time) { func updateModelInfo(modelMsg *ModelMsg, index uint64, t time.Time) {
modelMsg.index = index modelMsg.index = index
modelMsg.t = t modelMsg.t = t
if modelMsg.index%20 == 0 { if modelMsg.index%60 == 0 {
backend.UpdateDCUInfo(true) backend.UpdateDCUInfo(true)
} else { } else {
backend.UpdateDCUInfo(false) backend.UpdateDCUInfo(false)
......
...@@ -6,6 +6,7 @@ import ( ...@@ -6,6 +6,7 @@ import (
"get-container/cmd/dcutop/tchart" "get-container/cmd/dcutop/tchart"
"get-container/utils" "get-container/utils"
"maps" "maps"
"strings"
"sync" "sync"
"time" "time"
...@@ -18,21 +19,23 @@ import ( ...@@ -18,21 +19,23 @@ import (
const ( const (
SysLoadHeight = 5 // 固定图表高度 SysLoadHeight = 5 // 固定图表高度
SysLoadWidth = 77 // 固定图表宽度,不包含左右的边框 SysLoadWidth = 77 // 固定图表宽度,不包含左右的边框
SysLoadCap = 500 // 记录 SysLoadCap = 600 // 记录
) )
// ModelSysLoad 系统负载组件 // ModelSysLoad 系统负载组件
type ModelSysLoad struct { type ModelSysLoad struct {
SysMem *MyTimeChart SysMem *MyTimeChart
SysCPU *MyTimeChart SysCPU *MyTimeChart
DCU *MyTimeChart DCU *MyTimeChart
DCUMem *MyTimeChart DCUMem *MyTimeChart
Cache map[int]backend.DCUInfo Cache map[int]backend.DCUInfo
SysInfo *linkedhashmap.Map[time.Time, SysLoadInfo] SysInfo *linkedhashmap.Map[time.Time, SysLoadInfo]
Keys *binaryheap.Heap[time.Time] Keys *binaryheap.Heap[time.Time]
current *SysLoadInfo current *SysLoadInfo
line string topLine string
style lipgloss.Style bottomLine string
style lipgloss.Style
width int // 组件总宽度
} }
type SysLoadInfo struct { type SysLoadInfo struct {
...@@ -50,6 +53,7 @@ type SysLoadInfo struct { ...@@ -50,6 +53,7 @@ type SysLoadInfo struct {
func NewModelSysLoad(width int) *ModelSysLoad { func NewModelSysLoad(width int) *ModelSysLoad {
result := ModelSysLoad{} result := ModelSysLoad{}
result.width = width
result.Cache = make(map[int]backend.DCUInfo) result.Cache = make(map[int]backend.DCUInfo)
result.SysInfo = linkedhashmap.New[time.Time, SysLoadInfo]() result.SysInfo = linkedhashmap.New[time.Time, SysLoadInfo]()
result.Keys = binaryheap.NewWith(func(a, b time.Time) int { result.Keys = binaryheap.NewWith(func(a, b time.Time) int {
...@@ -61,11 +65,14 @@ func NewModelSysLoad(width int) *ModelSysLoad { ...@@ -61,11 +65,14 @@ func NewModelSysLoad(width int) *ModelSysLoad {
} }
return 0 return 0
}) })
subLine := width - StaticWidth - 1
result.SysMem = New(SysLoadWidth, SysLoadHeight, 0, 100, map[string]lipgloss.Color{"default": lipgloss.Color("#0400ffff")}) result.SysMem = New(SysLoadWidth, SysLoadHeight, 0, 100, map[string]lipgloss.Color{"default": lipgloss.Color("#0400ffff")})
result.SysCPU = New(SysLoadWidth, SysLoadHeight, 0, 100, map[string]lipgloss.Color{"default": lipgloss.Color("#8400ffff")}) result.SysCPU = New(SysLoadWidth, SysLoadHeight, 0, 100, map[string]lipgloss.Color{"default": lipgloss.Color("#8400ffff")})
result.DCU = New(width, SysLoadHeight, 0, 100, map[string]lipgloss.Color{"default": lipgloss.Color("#00ff00ff")}) result.DCU = New(subLine, SysLoadHeight, 0, 100, map[string]lipgloss.Color{"default": lipgloss.Color("#00ff00ff")})
result.DCUMem = New(width, SysLoadHeight, 0, 100, map[string]lipgloss.Color{"default": lipgloss.Color("#eeff00ff")}) result.DCUMem = New(subLine, SysLoadHeight, 0, 100, map[string]lipgloss.Color{"default": lipgloss.Color("#eeff00ff")})
result.line = genXAxis(SysLoadWidth) + myBorder.Middle + genXAxis(width)
result.topLine = myBorder.MiddleLeft + genXAxis(SysLoadWidth) + myBorder.Middle + genXAxis(subLine) + myBorder.MiddleRight
result.bottomLine = "╞" + strings.Repeat(myBorder.Bottom, SysLoadWidth) + "╧" + strings.Repeat(myBorder.Bottom, subLine) + "╡"
result.style = lipgloss.NewStyle() result.style = lipgloss.NewStyle()
return &result return &result
} }
...@@ -118,10 +125,12 @@ func (m *ModelSysLoad) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) { ...@@ -118,10 +125,12 @@ func (m *ModelSysLoad) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) {
} }
func (m *ModelSysLoad) View() string { func (m *ModelSysLoad) View() string {
load := fmt.Sprintf("Load Average: %.2f %.2f %.2f", m.current.Load1, m.current.Load5, m.current.Load15) memUsed := utils.MemorySize{Num: m.current.MemUsed, Unit: utils.Byte}
mem := fmt.Sprintf("MEM: %s (%.1f%%)", "todo", 12.3)
dcuMem := fmt.Sprintf("AVG DCU MEM: %.1f%%", m.current.DCUMemUsageAvg) load := fmt.Sprintf(" Load Average: %.2f %.2f %.2f", m.current.Load1, m.current.Load5, m.current.Load15)
dcu := fmt.Sprintf("AVG DCU UTL: %.1f%%", m.current.DCUUsageAvg) mem := fmt.Sprintf(" MEM: %s (%.1f%%)", memUsed.HumanReadStr(), m.current.MemUsedPercent)
dcuMem := fmt.Sprintf(" AVG DCU MEM: %.1f%%", m.current.DCUMemUsageAvg)
dcu := fmt.Sprintf(" AVG DCU UTL: %.1f%%", m.current.DCUUsageAvg)
load = StackPosition(load, m.SysCPU.View(), lipgloss.Top, lipgloss.Left) load = StackPosition(load, m.SysCPU.View(), lipgloss.Top, lipgloss.Left)
mem = StackPosition(mem, m.SysMem.View(), lipgloss.Bottom, lipgloss.Left) mem = StackPosition(mem, m.SysMem.View(), lipgloss.Bottom, lipgloss.Left)
...@@ -129,13 +138,13 @@ func (m *ModelSysLoad) View() string { ...@@ -129,13 +138,13 @@ func (m *ModelSysLoad) View() string {
dcu = StackPosition(dcu, m.DCU.View(), lipgloss.Bottom, lipgloss.Left) dcu = StackPosition(dcu, m.DCU.View(), lipgloss.Bottom, lipgloss.Left)
load = m.style.Border(myBorder, false, true, false).Render(load) load = m.style.Border(myBorder, false, true, false).Render(load)
mem = m.style.Render(mem) mem = m.style.Border(myBorder, false, true, false).Render(mem)
dcuMem = m.style.Border(myBorder, false, true, false, false).UnsetBorderRight().Render(dcuMem) dcuMem = m.style.Border(myBorder, false, true, false, false).Render(dcuMem)
dcu = m.style.Render(dcu) dcu = m.style.Border(myBorder, false, true, false, false).Render(dcu)
up := lipgloss.JoinHorizontal(lipgloss.Top, load, dcuMem) up := lipgloss.JoinHorizontal(lipgloss.Top, load, dcuMem)
down := lipgloss.JoinHorizontal(lipgloss.Top, mem, dcu) down := lipgloss.JoinHorizontal(lipgloss.Top, mem, dcu)
return lipgloss.JoinVertical(lipgloss.Left, up, m.line, down) return lipgloss.JoinVertical(lipgloss.Left, up, m.topLine, down, m.bottomLine)
} }
// updateInfo // updateInfo
...@@ -159,7 +168,7 @@ func (m *ModelSysLoad) updateInfo(t time.Time) { ...@@ -159,7 +168,7 @@ func (m *ModelSysLoad) updateInfo(t time.Time) {
for k, v := range m.Cache { for k, v := range m.Cache {
s.DCUMemUsageAvg += v.MemUsedPerent s.DCUMemUsageAvg += v.MemUsedPerent
s.DCUMemUsage[k] = v.MemUsedPerent s.DCUMemUsage[k] = v.MemUsedPerent
s.DCUMemUsageAvg += v.DCUUTil s.DCUUsageAvg += v.DCUUTil
s.DCUUsage[k] = v.DCUUTil s.DCUUsage[k] = v.DCUUTil
} }
l := len(m.Cache) l := len(m.Cache)
...@@ -188,6 +197,14 @@ func (m *ModelSysLoad) updateInfo(t time.Time) { ...@@ -188,6 +197,14 @@ func (m *ModelSysLoad) updateInfo(t time.Time) {
m4, _ := m.DCUMem.Update(MyTimeChartMsg{Points: map[string][]tchart.TimePoint{"default": {{Time: t, Value: float64(s.DCUMemUsageAvg)}}}}) m4, _ := m.DCUMem.Update(MyTimeChartMsg{Points: map[string][]tchart.TimePoint{"default": {{Time: t, Value: float64(s.DCUMemUsageAvg)}}}})
m.DCUMem = m4.(*MyTimeChart) m.DCUMem = m4.(*MyTimeChart)
}() }()
// todo // 存放数据
m.SysInfo.Put(t, s)
m.Keys.Push(t)
if m.Keys.Size() > SysLoadCap {
delKey, have := m.Keys.Pop()
if have {
m.SysInfo.Remove(delKey)
}
}
wg.Wait() wg.Wait()
} }
...@@ -99,7 +99,7 @@ func New(width, height int, vmin, vmax float64, dataSet map[string]lipgloss.Colo ...@@ -99,7 +99,7 @@ func New(width, height int, vmin, vmax float64, dataSet map[string]lipgloss.Colo
copy(result.dataSet[k], initPoints) copy(result.dataSet[k], initPoints)
} }
result.lockDataSet.Unlock() result.lockDataSet.Unlock()
s := tchart.New(width, height, s := tchart.New(width, height+1,
tchart.WithLineStyle(runes.ThinLineStyle), tchart.WithLineStyle(runes.ThinLineStyle),
tchart.WithZoneManager(zoneManager), tchart.WithZoneManager(zoneManager),
tchart.WithYRange(vmin, vmax), tchart.WithYRange(vmin, vmax),
...@@ -125,7 +125,7 @@ func New(width, height int, vmin, vmax float64, dataSet map[string]lipgloss.Colo ...@@ -125,7 +125,7 @@ func New(width, height int, vmin, vmax float64, dataSet map[string]lipgloss.Colo
func (m *MyTimeChart) PutPoint(points map[string][]tchart.TimePoint) { func (m *MyTimeChart) PutPoint(points map[string][]tchart.TimePoint) {
// 更新chart // 更新chart
s := tchart.New(m.width, m.height, s := tchart.New(m.width, m.height+1,
tchart.WithLineStyle(runes.ThinLineStyle), tchart.WithLineStyle(runes.ThinLineStyle),
tchart.WithZoneManager(m.zM), tchart.WithZoneManager(m.zM),
tchart.WithYRange(m.min, m.max), tchart.WithYRange(m.min, m.max),
...@@ -189,6 +189,7 @@ func (m *MyTimeChart) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) { ...@@ -189,6 +189,7 @@ func (m *MyTimeChart) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) {
func (m *MyTimeChart) View() string { func (m *MyTimeChart) View() string {
rl := m.lockChart.RLocker() rl := m.lockChart.RLocker()
rl.Lock() rl.Lock()
defer rl.Unlock() str := m.zM.Scan(m.chart.View())
return m.zM.Scan(m.chart.View()) rl.Unlock()
return str[m.width+1:]
} }
...@@ -52,20 +52,24 @@ func TestModel(t *testing.T) { ...@@ -52,20 +52,24 @@ func TestModel(t *testing.T) {
} }
func TestMyTimeChart(t *testing.T) { func TestMyTimeChart(t *testing.T) {
chart := New(100, 20, 0.0, 100.0, map[string]lipgloss.Color{"default": lipgloss.Color("#ff2222ff"), "other": lipgloss.Color("#0037ffff")}) chart := New(100, 5, 0.0, 100.0, map[string]lipgloss.Color{"default": lipgloss.Color("#ff2222ff"), "other": lipgloss.Color("#0037ffff")})
chart.Init() chart.Init()
s := chart.View() s := chart.View()
t.Logf("%s", s) t.Logf("\n%s", s)
time.Sleep(time.Second) time.Sleep(time.Second)
now := time.Now() now := time.Now()
points := make(map[string][]tchart.TimePoint) points := make(map[string][]tchart.TimePoint)
points["default"] = []tchart.TimePoint{{Time: now, Value: 20.0}} points["default"] = []tchart.TimePoint{{Time: now, Value: 94.0}}
points["other"] = []tchart.TimePoint{{Time: now, Value: 30.0}} points["other"] = []tchart.TimePoint{{Time: now, Value: 94.0}}
chart.Update(MyTimeChartMsg{Points: points}) chart.Update(MyTimeChartMsg{Points: points})
time.Sleep(time.Second)
_ = len(chart.dataSet) now = time.Now()
points = make(map[string][]tchart.TimePoint)
t.Logf("%s", chart.View()) points["default"] = []tchart.TimePoint{{Time: now, Value: 0.0}}
points["other"] = []tchart.TimePoint{{Time: now, Value: 0.0}}
chart.Update(MyTimeChartMsg{Points: points})
t.Logf("\n%s", chart.View())
t.Logf("ok")
} }
func TestBinaryHeap(t *testing.T) { func TestBinaryHeap(t *testing.T) {
......
...@@ -9,6 +9,34 @@ import ( ...@@ -9,6 +9,34 @@ import (
type StorageCapacityUnit uint64 type StorageCapacityUnit uint64
func (u StorageCapacityUnit) String() string {
switch u {
case Byte:
return "Byte"
case KB:
return "KB"
case MB:
return "MB"
case GB:
return "GB"
case TB:
return "TB"
case PB:
return "PB"
case KiB:
return "KiB"
case MiB:
return "MiB"
case GiB:
return "GiB"
case TiB:
return "TiB"
case PiB:
return "PiB"
}
return "unknow unit"
}
const ( const (
Byte StorageCapacityUnit = 1 Byte StorageCapacityUnit = 1
KB StorageCapacityUnit = Byte * 1000 KB StorageCapacityUnit = Byte * 1000
...@@ -35,6 +63,22 @@ type MemorySize struct { ...@@ -35,6 +63,22 @@ type MemorySize struct {
Unit StorageCapacityUnit Unit StorageCapacityUnit
} }
func (s MemorySize) HumanReadStr() string {
total := s.Num * uint64(s.Unit)
units := []StorageCapacityUnit{Byte, KiB, MiB, GiB, TiB, PiB}
var target StorageCapacityUnit
for k, v := range units {
if total/uint64(v) < 1 {
target = units[k-1]
break
} else {
target = v
}
}
num := float64(total) / float64(target)
return fmt.Sprintf("%.3f %s", num, target)
}
func ParseUnit(s string) (StorageCapacityUnit, error) { func ParseUnit(s string) (StorageCapacityUnit, error) {
s = strings.Trim(strings.TrimSpace(s), "\n") s = strings.Trim(strings.TrimSpace(s), "\n")
s = strings.ReplaceAll(s, " ", "") s = strings.ReplaceAll(s, " ", "")
...@@ -46,7 +90,7 @@ func ParseUnit(s string) (StorageCapacityUnit, error) { ...@@ -46,7 +90,7 @@ func ParseUnit(s string) (StorageCapacityUnit, error) {
// [KB K '' B] // [KB K '' B]
// [B '' '' B] // [B '' '' B]
matchs := ReUnit.FindStringSubmatch(s) matchs := ReUnit.FindStringSubmatch(s)
if matchs == nil || len(matchs) < 4 { if len(matchs) < 4 {
return 0, fmt.Errorf("invalid storage size unit: %s", s) return 0, fmt.Errorf("invalid storage size unit: %s", s)
} }
isI := matchs[2] == "i" isI := matchs[2] == "i"
...@@ -91,7 +135,7 @@ func ParseMemorySize(s string) (*MemorySize, error) { ...@@ -91,7 +135,7 @@ func ParseMemorySize(s string) (*MemorySize, error) {
return nil, fmt.Errorf("invalid memory size format: %s", s) return nil, fmt.Errorf("invalid memory size format: %s", s)
} }
matchs := ReStorageSize.FindStringSubmatch(s) matchs := ReStorageSize.FindStringSubmatch(s)
if matchs == nil || len(matchs) < 3 { if len(matchs) < 3 {
return nil, fmt.Errorf("invalid memory size format: %s", s) return nil, fmt.Errorf("invalid memory size format: %s", s)
} }
......
...@@ -53,3 +53,11 @@ func TestParseMemorySize(t *testing.T) { ...@@ -53,3 +53,11 @@ func TestParseMemorySize(t *testing.T) {
} }
} }
} }
func TestHumanReadStr(t *testing.T) {
ms := MemorySize{Num: 1025, Unit: Byte}
t.Log(ms.HumanReadStr())
ms.Num = 1025
ms.Unit = PiB
t.Log(ms.HumanReadStr())
}
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