Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
liming6
dcu-process-montor
Commits
9608d37d
Commit
9608d37d
authored
Nov 13, 2025
by
liming6
Browse files
fix 修复折线图的bug
parent
acd70ae1
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
124 additions
and
53 deletions
+124
-53
cmd/dcutop/dcutop
cmd/dcutop/dcutop
+0
-0
cmd/dcutop/tui/dcuinfo.go
cmd/dcutop/tui/dcuinfo.go
+5
-8
cmd/dcutop/tui/main.go
cmd/dcutop/tui/main.go
+7
-7
cmd/dcutop/tui/sysload.go
cmd/dcutop/tui/sysload.go
+41
-24
cmd/dcutop/tui/timechart.go
cmd/dcutop/tui/timechart.go
+5
-4
cmd/dcutop/tui/tui_test.go
cmd/dcutop/tui/tui_test.go
+12
-8
utils/unit.go
utils/unit.go
+46
-2
utils/utils_test.go
utils/utils_test.go
+8
-0
No files found.
cmd/dcutop/dcutop
deleted
100755 → 0
View file @
acd70ae1
File deleted
cmd/dcutop/tui/dcuinfo.go
View file @
9608d37d
...
...
@@ -26,9 +26,8 @@ const (
BottomLine
=
`╞═══════════════════════════════╧══════════════════════╧══════════════════════╪`
OtherWidth
=
8
StaticWidth
=
87
// 固定表格的宽度
ProgressMaxWidth
=
105
// 进度条最大宽度
ProgressMinWidth
=
15
// 进度条最小宽度
StaticWidth
=
79
// 固定表格的宽度
ProgressMinWidth
=
15
// 进度条最小宽度
)
func
(
m
*
ModelDCUInfo
)
Init
()
tea
.
Cmd
{
...
...
@@ -36,10 +35,8 @@ func (m *ModelDCUInfo) Init() tea.Cmd {
return
tea
.
Quit
}
m
.
proWidth
=
ProgressMinWidth
if
m
.
width
>
StaticWidth
+
ProgressMaxWidth
{
m
.
proWidth
=
ProgressMaxWidth
}
else
{
m
.
proWidth
=
m
.
width
-
StaticWidth
if
m
.
width
>
StaticWidth
+
ProgressMinWidth
+
OtherWidth
{
m
.
proWidth
=
m
.
width
-
OtherWidth
-
StaticWidth
}
m
.
pro
=
progress
.
New
(
progress
.
WithDefaultGradient
(),
progress
.
WithWidth
(
m
.
proWidth
))
return
nil
...
...
@@ -127,7 +124,7 @@ func (m *ModelDCUInfo) View() string {
if
len
(
infos
)
>
0
{
lineWidth
=
lipgloss
.
Width
(
infos
[
0
])
}
subLen
:=
lineWidth
-
StaticWidth
+
OtherWidth
-
1
subLen
:=
lineWidth
-
StaticWidth
-
1
if
subLen
<=
0
{
subLen
=
0
}
...
...
cmd/dcutop/tui/main.go
View file @
9608d37d
...
...
@@ -44,7 +44,7 @@ func NewModelMain(width, height int) ModelMain {
result
.
height
=
height
result
.
Header
=
&
ModelHeader
{}
result
.
DCUInfo
=
&
ModelDCUInfo
{
width
:
width
,
height
:
height
,
info
:
make
(
map
[
int
]
backend
.
DCUInfo
)}
result
.
SysLoad
=
NewModelSysLoad
(
100
)
result
.
SysLoad
=
NewModelSysLoad
(
width
)
return
result
}
...
...
@@ -95,13 +95,13 @@ func (m *ModelMain) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) {
case
TickMsg
:
// 定时事件
m
.
index
++
updateModelInfo
(
m
.
modelMsg
,
m
.
index
,
time
.
Time
(
msg
))
cmds
:=
make
([]
tea
.
Cmd
,
0
)
header
,
cmdHeader
:=
m
.
Header
.
Update
(
m
.
modelMsg
)
dcuInfo
,
dcuHeader
:=
m
.
DCUInfo
.
Update
(
m
.
modelMsg
)
header
,
_
:=
m
.
Header
.
Update
(
m
.
modelMsg
)
dcuInfo
,
_
:=
m
.
DCUInfo
.
Update
(
m
.
modelMsg
)
sysLoad
,
_
:=
m
.
SysLoad
.
Update
(
m
.
modelMsg
)
m
.
Header
=
header
.
(
*
ModelHeader
)
m
.
DCUInfo
=
dcuInfo
.
(
*
ModelDCUInfo
)
cmds
=
append
(
cmds
,
cmdHeader
,
dcuHeader
,
tickCmd
()
)
return
m
,
t
ea
.
Batch
(
cmds
...
)
m
.
SysLoad
=
sysLoad
.
(
*
ModelSysLoad
)
return
m
,
t
ickCmd
(
)
case
ModelMsg
:
// 初始化
header
,
_
:=
m
.
Header
.
Update
(
m
.
modelMsg
)
dcuInfo
,
_
:=
m
.
DCUInfo
.
Update
(
m
.
modelMsg
)
...
...
@@ -157,7 +157,7 @@ func initModelInfo(model *ModelMsg) error {
func
updateModelInfo
(
modelMsg
*
ModelMsg
,
index
uint64
,
t
time
.
Time
)
{
modelMsg
.
index
=
index
modelMsg
.
t
=
t
if
modelMsg
.
index
%
2
0
==
0
{
if
modelMsg
.
index
%
6
0
==
0
{
backend
.
UpdateDCUInfo
(
true
)
}
else
{
backend
.
UpdateDCUInfo
(
false
)
...
...
cmd/dcutop/tui/sysload.go
View file @
9608d37d
...
...
@@ -6,6 +6,7 @@ import (
"get-container/cmd/dcutop/tchart"
"get-container/utils"
"maps"
"strings"
"sync"
"time"
...
...
@@ -18,21 +19,23 @@ import (
const
(
SysLoadHeight
=
5
// 固定图表高度
SysLoadWidth
=
77
// 固定图表宽度,不包含左右的边框
SysLoadCap
=
5
00
// 记录
SysLoadCap
=
6
00
// 记录
)
// ModelSysLoad 系统负载组件
type
ModelSysLoad
struct
{
SysMem
*
MyTimeChart
SysCPU
*
MyTimeChart
DCU
*
MyTimeChart
DCUMem
*
MyTimeChart
Cache
map
[
int
]
backend
.
DCUInfo
SysInfo
*
linkedhashmap
.
Map
[
time
.
Time
,
SysLoadInfo
]
Keys
*
binaryheap
.
Heap
[
time
.
Time
]
current
*
SysLoadInfo
line
string
style
lipgloss
.
Style
SysMem
*
MyTimeChart
SysCPU
*
MyTimeChart
DCU
*
MyTimeChart
DCUMem
*
MyTimeChart
Cache
map
[
int
]
backend
.
DCUInfo
SysInfo
*
linkedhashmap
.
Map
[
time
.
Time
,
SysLoadInfo
]
Keys
*
binaryheap
.
Heap
[
time
.
Time
]
current
*
SysLoadInfo
topLine
string
bottomLine
string
style
lipgloss
.
Style
width
int
// 组件总宽度
}
type
SysLoadInfo
struct
{
...
...
@@ -50,6 +53,7 @@ type SysLoadInfo struct {
func
NewModelSysLoad
(
width
int
)
*
ModelSysLoad
{
result
:=
ModelSysLoad
{}
result
.
width
=
width
result
.
Cache
=
make
(
map
[
int
]
backend
.
DCUInfo
)
result
.
SysInfo
=
linkedhashmap
.
New
[
time
.
Time
,
SysLoadInfo
]()
result
.
Keys
=
binaryheap
.
NewWith
(
func
(
a
,
b
time
.
Time
)
int
{
...
...
@@ -61,11 +65,14 @@ func NewModelSysLoad(width int) *ModelSysLoad {
}
return
0
})
subLine
:=
width
-
StaticWidth
-
1
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
.
DCU
=
New
(
width
,
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
.
line
=
genXAxis
(
SysLoadWidth
)
+
myBorder
.
Middle
+
genXAxis
(
width
)
result
.
DCU
=
New
(
subLine
,
SysLoadHeight
,
0
,
100
,
map
[
string
]
lipgloss
.
Color
{
"default"
:
lipgloss
.
Color
(
"#00ff00ff"
)})
result
.
DCUMem
=
New
(
subLine
,
SysLoadHeight
,
0
,
100
,
map
[
string
]
lipgloss
.
Color
{
"default"
:
lipgloss
.
Color
(
"#eeff00ff"
)})
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
()
return
&
result
}
...
...
@@ -118,10 +125,12 @@ func (m *ModelSysLoad) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) {
}
func
(
m
*
ModelSysLoad
)
View
()
string
{
load
:=
fmt
.
Sprintf
(
"Load Average: %.2f %.2f %.2f"
,
m
.
current
.
Load1
,
m
.
current
.
Load5
,
m
.
current
.
Load15
)
mem
:=
fmt
.
Sprintf
(
"MEM: %s (%.1f%%)"
,
"todo"
,
12.3
)
dcuMem
:=
fmt
.
Sprintf
(
"AVG DCU MEM: %.1f%%"
,
m
.
current
.
DCUMemUsageAvg
)
dcu
:=
fmt
.
Sprintf
(
"AVG DCU UTL: %.1f%%"
,
m
.
current
.
DCUUsageAvg
)
memUsed
:=
utils
.
MemorySize
{
Num
:
m
.
current
.
MemUsed
,
Unit
:
utils
.
Byte
}
load
:=
fmt
.
Sprintf
(
" Load Average: %.2f %.2f %.2f"
,
m
.
current
.
Load1
,
m
.
current
.
Load5
,
m
.
current
.
Load15
)
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
)
mem
=
StackPosition
(
mem
,
m
.
SysMem
.
View
(),
lipgloss
.
Bottom
,
lipgloss
.
Left
)
...
...
@@ -129,13 +138,13 @@ func (m *ModelSysLoad) View() string {
dcu
=
StackPosition
(
dcu
,
m
.
DCU
.
View
(),
lipgloss
.
Bottom
,
lipgloss
.
Left
)
load
=
m
.
style
.
Border
(
myBorder
,
false
,
true
,
false
)
.
Render
(
load
)
mem
=
m
.
style
.
Render
(
mem
)
dcuMem
=
m
.
style
.
Border
(
myBorder
,
false
,
true
,
false
,
false
)
.
UnsetBorderRight
()
.
Render
(
dcuMem
)
dcu
=
m
.
style
.
Render
(
dcu
)
mem
=
m
.
style
.
Border
(
myBorder
,
false
,
true
,
false
)
.
Render
(
mem
)
dcuMem
=
m
.
style
.
Border
(
myBorder
,
false
,
true
,
false
,
false
)
.
Render
(
dcuMem
)
dcu
=
m
.
style
.
Border
(
myBorder
,
false
,
true
,
false
,
false
)
.
Render
(
dcu
)
up
:=
lipgloss
.
JoinHorizontal
(
lipgloss
.
Top
,
load
,
dcuMem
)
down
:=
lipgloss
.
JoinHorizontal
(
lipgloss
.
Top
,
mem
,
dcu
)
return
lipgloss
.
JoinVertical
(
lipgloss
.
Left
,
up
,
m
.
l
ine
,
down
)
return
lipgloss
.
JoinVertical
(
lipgloss
.
Left
,
up
,
m
.
topL
ine
,
down
,
m
.
bottomLine
)
}
// updateInfo
...
...
@@ -159,7 +168,7 @@ func (m *ModelSysLoad) updateInfo(t time.Time) {
for
k
,
v
:=
range
m
.
Cache
{
s
.
DCUMemUsageAvg
+=
v
.
MemUsedPerent
s
.
DCUMemUsage
[
k
]
=
v
.
MemUsedPerent
s
.
DCU
Mem
UsageAvg
+=
v
.
DCUUTil
s
.
DCUUsageAvg
+=
v
.
DCUUTil
s
.
DCUUsage
[
k
]
=
v
.
DCUUTil
}
l
:=
len
(
m
.
Cache
)
...
...
@@ -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
)}}}})
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
()
}
cmd/dcutop/tui/timechart.go
View file @
9608d37d
...
...
@@ -99,7 +99,7 @@ func New(width, height int, vmin, vmax float64, dataSet map[string]lipgloss.Colo
copy
(
result
.
dataSet
[
k
],
initPoints
)
}
result
.
lockDataSet
.
Unlock
()
s
:=
tchart
.
New
(
width
,
height
,
s
:=
tchart
.
New
(
width
,
height
+
1
,
tchart
.
WithLineStyle
(
runes
.
ThinLineStyle
),
tchart
.
WithZoneManager
(
zoneManager
),
tchart
.
WithYRange
(
vmin
,
vmax
),
...
...
@@ -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
)
{
// 更新chart
s
:=
tchart
.
New
(
m
.
width
,
m
.
height
,
s
:=
tchart
.
New
(
m
.
width
,
m
.
height
+
1
,
tchart
.
WithLineStyle
(
runes
.
ThinLineStyle
),
tchart
.
WithZoneManager
(
m
.
zM
),
tchart
.
WithYRange
(
m
.
min
,
m
.
max
),
...
...
@@ -189,6 +189,7 @@ func (m *MyTimeChart) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) {
func
(
m
*
MyTimeChart
)
View
()
string
{
rl
:=
m
.
lockChart
.
RLocker
()
rl
.
Lock
()
defer
rl
.
Unlock
()
return
m
.
zM
.
Scan
(
m
.
chart
.
View
())
str
:=
m
.
zM
.
Scan
(
m
.
chart
.
View
())
rl
.
Unlock
()
return
str
[
m
.
width
+
1
:
]
}
cmd/dcutop/tui/tui_test.go
View file @
9608d37d
...
...
@@ -52,20 +52,24 @@ func TestModel(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
()
s
:=
chart
.
View
()
t
.
Logf
(
"%s"
,
s
)
t
.
Logf
(
"
\n
%s"
,
s
)
time
.
Sleep
(
time
.
Second
)
now
:=
time
.
Now
()
points
:=
make
(
map
[
string
][]
tchart
.
TimePoint
)
points
[
"default"
]
=
[]
tchart
.
TimePoint
{{
Time
:
now
,
Value
:
20
.0
}}
points
[
"other"
]
=
[]
tchart
.
TimePoint
{{
Time
:
now
,
Value
:
30
.0
}}
points
[
"default"
]
=
[]
tchart
.
TimePoint
{{
Time
:
now
,
Value
:
94
.0
}}
points
[
"other"
]
=
[]
tchart
.
TimePoint
{{
Time
:
now
,
Value
:
94
.0
}}
chart
.
Update
(
MyTimeChartMsg
{
Points
:
points
})
_
=
len
(
chart
.
dataSet
)
t
.
Logf
(
"%s"
,
chart
.
View
())
time
.
Sleep
(
time
.
Second
)
now
=
time
.
Now
()
points
=
make
(
map
[
string
][]
tchart
.
TimePoint
)
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
)
{
...
...
utils/unit.go
View file @
9608d37d
...
...
@@ -9,6 +9,34 @@ import (
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
(
Byte
StorageCapacityUnit
=
1
KB
StorageCapacityUnit
=
Byte
*
1000
...
...
@@ -35,6 +63,22 @@ type MemorySize struct {
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
)
{
s
=
strings
.
Trim
(
strings
.
TrimSpace
(
s
),
"
\n
"
)
s
=
strings
.
ReplaceAll
(
s
,
" "
,
""
)
...
...
@@ -46,7 +90,7 @@ func ParseUnit(s string) (StorageCapacityUnit, error) {
// [KB K '' B]
// [B '' '' B]
matchs
:=
ReUnit
.
FindStringSubmatch
(
s
)
if
matchs
==
nil
||
len
(
matchs
)
<
4
{
if
len
(
matchs
)
<
4
{
return
0
,
fmt
.
Errorf
(
"invalid storage size unit: %s"
,
s
)
}
isI
:=
matchs
[
2
]
==
"i"
...
...
@@ -91,7 +135,7 @@ func ParseMemorySize(s string) (*MemorySize, error) {
return
nil
,
fmt
.
Errorf
(
"invalid memory size format: %s"
,
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
)
}
...
...
utils/utils_test.go
View file @
9608d37d
...
...
@@ -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
())
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment