Commit 7622e62a authored by liming6's avatar liming6
Browse files

feature 配置为全屏模式,提出部分优化项

parent 63d7bbfc
# Todo
待办清单:
- [x] 解析/etc/passwd文件,解析Linux系统用户和家目录
- [ ] 解析docker容器相关信息,尝试找出启动容器的用户
- [ ] 使用包装命令,记录容器和系统用户的对应关系
- [ ] 添加一种docker top命令查找进程的容器归属的方法
- [ ] 调研一种golang tui库
package main
import (
"get-container/cmd/dcutop/tui"
"log"
"os"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/x/term"
)
func main() {
w, h, err := term.GetSize(os.Stdout.Fd())
if err != nil {
log.Fatalf("error get terminal size: %v", err)
}
model := tui.NewModelMain(w, h)
if _, err := tea.NewProgram(&model).Run(); err != nil {
log.Fatalf("error create program; %v", err)
}
os.Exit(0)
}
// type TickMsg time.Time
// type model struct {
// c *tui.MyTimeChart
// }
// func (m *model) Init() tea.Cmd {
// m.c = tui.New(100, 20, 0, 100, map[string]lipgloss.Color{"default": lipgloss.Color("#ff2222ff"), "other": lipgloss.Color("#0037ffff")})
// return tea.Batch(m.c.Init(), tea.Tick(time.Second, func(t time.Time) tea.Msg {
// return TickMsg(t)
// }))
// }
// func (m *model) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) {
// switch msg := inputMsg.(type) {
// case TickMsg:
// randPoint1 := rand.Float64() * 100.0
// randPoint2 := rand.Float64() * 100.0
// now := time.Now()
// timePoint1 := tchart.TimePoint{Time: now, Value: randPoint1}
// timePoint2 := tchart.TimePoint{Time: now, Value: randPoint2}
// tmsg := tui.MyTimeChartMsg{Points: map[string][]tchart.TimePoint{"default": {timePoint1}, "other": {timePoint2}}}
// mm, cmd := m.c.Update(tmsg)
// m.c = mm.(*tui.MyTimeChart)
// return m, tea.Batch(cmd, tea.Tick(time.Second, func(t time.Time) tea.Msg {
// return TickMsg(t)
// }))
// case tea.KeyMsg:
// switch msg.String() {
// case "q", "ctrl+c":
// return m, tea.Quit
// }
// }
// return m, nil
// }
// func (m *model) View() string {
// sty := lipgloss.NewStyle().Border(lipgloss.NormalBorder())
// st := sty.SetString(m.c.View()).String()
// return st + "\n"
// }
// func main() {
// _, err := tea.NewProgram(&model{}).Run()
// if err != nil {
// log.Fatal(err)
// }
// }
# Todo
待办清单:
解决非root用户执行出错的问题
优化抓取数据逻辑,避免卡顿
- 减少无效数据的收集
- 多goroutine收集数据,收集数据的goroutine不阻塞tui相关goroutine的运行
尝试使用.so文件抓取系统信息,而非使用二进制文件的输出,以提高采集效率
提高采集频率
集成docker相关功能,同时注意错误隔断,避免无用错误影响主逻辑(docker容器重启会影响获取docker容器相关信息,会返回err)
package backend package backend
import ( import (
"fmt"
"get-container/docker" "get-container/docker"
"get-container/gpu" "get-container/gpu"
"get-container/utils" "get-container/utils"
"maps" "maps"
"math"
"os" "os"
"strconv" "strconv"
"strings"
"sync" "sync"
"time" "time"
...@@ -254,7 +257,7 @@ func getProcessInfo(pids []int32) map[int32]ProcessInfo { ...@@ -254,7 +257,7 @@ func getProcessInfo(pids []int32) map[int32]ProcessInfo {
item.Mem, _ = p.MemoryPercent() item.Mem, _ = p.MemoryPercent()
t, err := p.Times() t, err := p.Times()
if err == nil { if err == nil {
item.Time = (time.Duration((t.System+t.User)*1000.0) * time.Millisecond).String() item.Time = durationStr(time.Duration((t.System + t.User)) * time.Second)
} }
item.Cmd, _ = p.Cmdline() item.Cmd, _ = p.Cmdline()
a, b := dockerPids[item.Pid] a, b := dockerPids[item.Pid]
...@@ -301,3 +304,11 @@ func GetDCUProcessInfo() map[int][]DCUProcessInfo { ...@@ -301,3 +304,11 @@ func GetDCUProcessInfo() map[int][]DCUProcessInfo {
} }
return result return result
} }
// durationStr 将时间段格式化为 小时:分钟:秒s的格式
func durationStr(d time.Duration) string {
h := int(math.Floor(d.Hours()))
m := int(d.Minutes()) % 60
s := int(math.Floor(d.Seconds())) % 60
return strings.Replace(fmt.Sprintf("%d:%2d:%2d", h, m, s), " ", "0", -1)
}
File added
package main
import (
"get-container/cmd/hytop/tui"
"log"
"os"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/x/term"
)
func main() {
w, h, err := term.GetSize(os.Stdout.Fd())
if err != nil {
log.Fatalf("error get terminal size: %v", err)
}
model := tui.NewModelMain(w, h)
if _, err := tea.NewProgram(&model, tea.WithAltScreen()).Run(); err != nil {
log.Fatalf("error create program; %v", err)
}
os.Exit(0)
}
...@@ -2,14 +2,16 @@ package tui ...@@ -2,14 +2,16 @@ package tui
import ( import (
"fmt" "fmt"
"get-container/cmd/dcutop/backend" "get-container/cmd/hytop/backend"
"maps" "maps"
"regexp"
"strconv" "strconv"
"strings" "strings"
"github.com/charmbracelet/bubbles/progress" "github.com/charmbracelet/bubbles/progress"
tea "github.com/charmbracelet/bubbletea" tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss"
"github.com/muesli/termenv"
) )
type ModelDCUInfo struct { type ModelDCUInfo struct {
...@@ -30,6 +32,10 @@ const ( ...@@ -30,6 +32,10 @@ const (
ProgressMinWidth = 15 // 进度条最小宽度 ProgressMinWidth = 15 // 进度条最小宽度
) )
var (
ReDCUName = regexp.MustCompile(`(?i)^[A-Z0-9-_]*`)
)
func (m *ModelDCUInfo) Init() tea.Cmd { func (m *ModelDCUInfo) Init() tea.Cmd {
if m.width < StaticWidth+ProgressMinWidth { if m.width < StaticWidth+ProgressMinWidth {
return tea.Quit return tea.Quit
...@@ -38,7 +44,7 @@ func (m *ModelDCUInfo) Init() tea.Cmd { ...@@ -38,7 +44,7 @@ func (m *ModelDCUInfo) Init() tea.Cmd {
if m.width > StaticWidth+ProgressMinWidth+OtherWidth { if m.width > StaticWidth+ProgressMinWidth+OtherWidth {
m.proWidth = m.width - OtherWidth - StaticWidth m.proWidth = m.width - OtherWidth - StaticWidth
} }
m.pro = progress.New(progress.WithDefaultGradient(), progress.WithWidth(m.proWidth)) m.pro = progress.New(progress.WithColorProfile(termenv.TrueColor), progress.WithGradient("#0000ffff", "#ff0000ff"), progress.WithWidth(m.proWidth))
return nil return nil
} }
...@@ -63,9 +69,9 @@ func (m *ModelDCUInfo) View() string { ...@@ -63,9 +69,9 @@ func (m *ModelDCUInfo) View() string {
strBuilder.WriteByte(' ') strBuilder.WriteByte(' ')
strBuilder.WriteString(FormatStr(strconv.Itoa(ii.Id), 4, lipgloss.Left)) strBuilder.WriteString(FormatStr(strconv.Itoa(ii.Id), 4, lipgloss.Left))
strBuilder.WriteByte(' ') strBuilder.WriteByte(' ')
strBuilder.WriteString(FormatStr(ii.Name, 6, lipgloss.Left)) strBuilder.WriteString(FormatStr(ReDCUName.FindString(ii.Name), 8, lipgloss.Left))
strBuilder.WriteByte(' ') strBuilder.WriteByte(' ')
strBuilder.WriteString(FormatStr(ii.PerformanceLevel, 17, lipgloss.Right)) strBuilder.WriteString(FormatStr(ii.PerformanceLevel, 15, lipgloss.Right))
strBuilder.WriteByte(' ') strBuilder.WriteByte(' ')
strBuilder.WriteString(myBorder.Left) strBuilder.WriteString(myBorder.Left)
strBuilder.WriteByte(' ') strBuilder.WriteByte(' ')
......
...@@ -42,17 +42,18 @@ const ( ...@@ -42,17 +42,18 @@ const (
) )
var ( var (
KeyStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#842cffff")).Italic(true) KeyStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#842cffff")).Italic(true)
KeyH, KeyQ = KeyStyle.SetString("h").String(), KeyStyle.SetString("q").String() KeyH, KeyQ = KeyStyle.SetString("h").String(), KeyStyle.SetString("q").String()
Space = strings.Repeat(" ", 28) Space = strings.Repeat(" ", 28)
HeaderBorderStyle = lipgloss.NewStyle().Border(myBorder, true, true, false, true)
) )
func (mh *ModelHeader) View() string { func (mh *ModelHeader) View() string {
header := fmt.Sprintf("%s%s(Press %s for help or %s for quit)\n", mh.t.Format("2006-01-02 15:04:05"), Space, KeyH, KeyQ) header := fmt.Sprintf("%s%s(Press %s for help or %s for quit)\n", mh.t.Format("2006-01-02 15:04:05"), Space, KeyH, KeyQ)
style := lipgloss.NewStyle().Padding(0, 1) style := lipgloss.NewStyle().Padding(0, 1)
borderStyle := lipgloss.NewStyle().Border(myBorder, true, true, false, true)
hyv := style.Width(18).Render(fmt.Sprintf("hytop: %s", mh.DCUTopVersion)) hyv := style.Width(18).Render(fmt.Sprintf("hytop: %s", mh.DCUTopVersion))
drv := style.Width(35).Render(fmt.Sprintf("Driver Version: %s", mh.DriverVersion)) drv := style.Width(35).Render(fmt.Sprintf("Driver Version: %s", mh.DriverVersion))
smiv := style.Width(24).Render(fmt.Sprintf("SMI Version: %s", mh.SMIVersion)) smiv := style.Width(24).Render(fmt.Sprintf("SMI Version: %s", mh.SMIVersion))
return header + borderStyle.Render(hyv+drv+smiv) + Title return header + HeaderBorderStyle.Render(hyv+drv+smiv) + Title
} }
package tui package tui
import ( import (
"get-container/cmd/dcutop/backend" "get-container/cmd/hytop/backend"
"get-container/gpu" "get-container/gpu"
"get-container/utils" "get-container/utils"
"time" "time"
...@@ -122,7 +122,7 @@ func (m *ModelMain) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) { ...@@ -122,7 +122,7 @@ func (m *ModelMain) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) {
} }
func (m *ModelMain) View() string { func (m *ModelMain) View() string {
return m.Header.View() + m.DCUInfo.View() + m.SysLoad.View() + m.ProcessInfo.Header + m.ProcessInfo.View() + "\n" return m.Header.View() + m.DCUInfo.View() + m.SysLoad.View() + m.ProcessInfo.View() + "\n"
} }
var myBorder = lipgloss.Border{ var myBorder = lipgloss.Border{
......
...@@ -2,7 +2,7 @@ package tui ...@@ -2,7 +2,7 @@ package tui
import ( import (
"fmt" "fmt"
"get-container/cmd/dcutop/backend" "get-container/cmd/hytop/backend"
"maps" "maps"
"strings" "strings"
...@@ -11,7 +11,6 @@ import ( ...@@ -11,7 +11,6 @@ import (
) )
type ModelProcessInfo struct { type ModelProcessInfo struct {
Header string
Title string Title string
DoubleMiddleLine string DoubleMiddleLine string
MiddleLine string MiddleLine string
...@@ -46,9 +45,6 @@ func (m *ModelProcessInfo) Init() tea.Cmd { ...@@ -46,9 +45,6 @@ func (m *ModelProcessInfo) Init() tea.Cmd {
sb.WriteString(uah) sb.WriteString(uah)
sb.WriteString(myBorder.Right) sb.WriteString(myBorder.Right)
sb.WriteByte('\n') sb.WriteByte('\n')
m.Header = sb.String()
sb.Reset()
sb.WriteString(myBorder.Left) sb.WriteString(myBorder.Left)
sb.WriteString(ModelProcessInfoTitle) sb.WriteString(ModelProcessInfoTitle)
sb.WriteString(strings.Repeat(" ", m.width-2-lipgloss.Width(ModelProcessInfoTitle))) sb.WriteString(strings.Repeat(" ", m.width-2-lipgloss.Width(ModelProcessInfoTitle)))
...@@ -107,13 +103,15 @@ func (m *ModelProcessInfo) View() string { ...@@ -107,13 +103,15 @@ func (m *ModelProcessInfo) View() string {
} }
lines = append(lines, m.MiddleLine) lines = append(lines, m.MiddleLine)
} }
if !haveProcess {
return m.Title + m.DoubleMiddleLine + m.NoProceseLine + m.BottomLine
}
sb.WriteString(m.Title) sb.WriteString(m.Title)
sb.WriteString(m.DoubleMiddleLine) sb.WriteString(m.DoubleMiddleLine)
for _, v := range lines[:len(lines)-1] { if !haveProcess {
sb.WriteString(v) sb.WriteString(m.NoProceseLine)
} else {
for _, v := range lines[:len(lines)-1] {
sb.WriteString(v)
}
} }
sb.WriteString(m.BottomLine) sb.WriteString(m.BottomLine)
return sb.String() return sb.String()
......
...@@ -2,9 +2,10 @@ package tui ...@@ -2,9 +2,10 @@ package tui
import ( import (
"fmt" "fmt"
"get-container/cmd/dcutop/backend" "get-container/cmd/hytop/backend"
"get-container/cmd/dcutop/tchart" "get-container/cmd/hytop/tchart"
"get-container/utils" "get-container/utils"
"image/color"
"maps" "maps"
"strings" "strings"
"sync" "sync"
...@@ -14,6 +15,8 @@ import ( ...@@ -14,6 +15,8 @@ import (
"github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss"
"github.com/emirpasic/gods/v2/maps/linkedhashmap" "github.com/emirpasic/gods/v2/maps/linkedhashmap"
"github.com/emirpasic/gods/v2/trees/binaryheap" "github.com/emirpasic/gods/v2/trees/binaryheap"
"github.com/lucasb-eyer/go-colorful"
"github.com/muesli/gamut"
) )
const ( const (
...@@ -36,6 +39,7 @@ type ModelSysLoad struct { ...@@ -36,6 +39,7 @@ type ModelSysLoad struct {
bottomLine string bottomLine string
style lipgloss.Style style lipgloss.Style
width int // 组件总宽度 width int // 组件总宽度
colors []color.Color
} }
type SysLoadInfo struct { type SysLoadInfo struct {
...@@ -66,14 +70,15 @@ func NewModelSysLoad(width int) *ModelSysLoad { ...@@ -66,14 +70,15 @@ func NewModelSysLoad(width int) *ModelSysLoad {
return 0 return 0
}) })
subLine := width - StaticWidth - 1 subLine := width - StaticWidth - 1
result.SysMem = New(SysLoadWidth, SysLoadHeight, 0, 100, map[string]lipgloss.Color{"default": lipgloss.Color("#0400ffff")}) result.SysMem = NewTimeChart(SysLoadWidth, SysLoadHeight, 0, 100, map[string]lipgloss.Color{"default": lipgloss.Color("#20ff2cff")})
result.SysCPU = New(SysLoadWidth, SysLoadHeight, 0, 100, map[string]lipgloss.Color{"default": lipgloss.Color("#8400ffff")}) result.SysCPU = NewTimeChart(SysLoadWidth, SysLoadHeight, 0, 100, map[string]lipgloss.Color{"default": lipgloss.Color("#ff3030ff")})
result.DCU = New(subLine, SysLoadHeight, 0, 100, map[string]lipgloss.Color{"default": lipgloss.Color("#00ff00ff")}) result.DCU = NewTimeChart(subLine, SysLoadHeight, 0, 100, map[string]lipgloss.Color{"default": lipgloss.Color("#27ffdbff")})
result.DCUMem = New(subLine, SysLoadHeight, 0, 100, map[string]lipgloss.Color{"default": lipgloss.Color("#eeff00ff")}) result.DCUMem = NewTimeChart(subLine, SysLoadHeight, 0, 100, map[string]lipgloss.Color{"default": lipgloss.Color("#20b1ffff")})
result.topLine = myBorder.MiddleLeft + genXAxis(SysLoadWidth) + myBorder.Middle + genXAxis(subLine) + myBorder.MiddleRight 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.bottomLine = "╞" + strings.Repeat(myBorder.Bottom, SysLoadWidth) + "╧" + strings.Repeat(myBorder.Bottom, subLine) + "╡"
result.style = lipgloss.NewStyle() result.style = lipgloss.NewStyle()
result.colors = gamut.Blends(lipgloss.Color("#ff0000"), lipgloss.Color("#00ff00ff"), SysLoadHeight)
return &result return &result
} }
...@@ -127,14 +132,16 @@ func (m *ModelSysLoad) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) { ...@@ -127,14 +132,16 @@ func (m *ModelSysLoad) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) {
func (m *ModelSysLoad) View() string { func (m *ModelSysLoad) View() string {
memUsed := utils.MemorySize{Num: m.current.MemUsed, Unit: utils.Byte} 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) load := fmt.Sprintf(" Load Average: %.2f %.2f %.2f\n CPU: %.1f%%", m.current.Load1, m.current.Load5, m.current.Load15, m.current.CPUPercent)
mem := fmt.Sprintf(" MEM: %s (%.1f%%)", memUsed.HumanReadStr(1), m.current.MemUsedPercent) mem := fmt.Sprintf(" MEM: %s (%.1f%%)", memUsed.HumanReadStr(1), m.current.MemUsedPercent)
dcuMem := fmt.Sprintf(" AVG DCU MEM: %.1f%%", m.current.DCUMemUsageAvg) dcuMem := fmt.Sprintf(" AVG DCU MEM: %.1f%%", m.current.DCUMemUsageAvg)
dcu := fmt.Sprintf(" AVG DCU UTL: %.1f%%", m.current.DCUUsageAvg) 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)
dcuMem = StackPosition(dcuMem, m.DCUMem.View(), lipgloss.Top, lipgloss.Left) s := m.DCUMem.View()
s = lipgloss.NewStyle().Foreground(lipgloss.Color("rgba(158, 143, 28, 0.86)")).Render(s)
dcuMem = StackPosition(dcuMem, s, lipgloss.Top, lipgloss.Left)
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)
...@@ -144,7 +151,7 @@ func (m *ModelSysLoad) View() string { ...@@ -144,7 +151,7 @@ func (m *ModelSysLoad) View() string {
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.topLine, down, m.bottomLine) return lipgloss.JoinVertical(lipgloss.Left, up, m.topLine, down, m.bottomLine) + "\n"
} }
// updateInfo // updateInfo
...@@ -208,3 +215,13 @@ func (m *ModelSysLoad) updateInfo(t time.Time) { ...@@ -208,3 +215,13 @@ func (m *ModelSysLoad) updateInfo(t time.Time) {
} }
wg.Wait() wg.Wait()
} }
func (m *ModelSysLoad) RanderColor(str string) string {
lines := strings.Split(strings.Trim(str, "\n"), "\n")
result := ""
for k, line := range lines {
c, _ := colorful.MakeColor(m.colors[k])
result += lipgloss.NewStyle().Foreground(lipgloss.Color(c.Hex())).Render(line) + "\n"
}
return result
}
...@@ -7,7 +7,7 @@ import ( ...@@ -7,7 +7,7 @@ import (
"sync" "sync"
"time" "time"
"get-container/cmd/dcutop/tchart" "get-container/cmd/hytop/tchart"
"github.com/NimbleMarkets/ntcharts/canvas/runes" "github.com/NimbleMarkets/ntcharts/canvas/runes"
tea "github.com/charmbracelet/bubbletea" tea "github.com/charmbracelet/bubbletea"
...@@ -20,7 +20,7 @@ const ( ...@@ -20,7 +20,7 @@ const (
) )
var ( var (
axisFStyle = lipgloss.NewStyle().Inline(true).Foreground(lipgloss.Color("#707070ff")) axisFStyle = lipgloss.NewStyle().Inline(true).Foreground(lipgloss.Color("#4d4d4dff"))
) )
// genXAxis 生成X轴,参数l是x轴的长度 // genXAxis 生成X轴,参数l是x轴的长度
...@@ -72,7 +72,7 @@ type MyTimeChart struct { ...@@ -72,7 +72,7 @@ type MyTimeChart struct {
} }
// New 新建图表,其中dataSet的Key为数据集名称,value为数据集的颜色 // New 新建图表,其中dataSet的Key为数据集名称,value为数据集的颜色
func New(width, height int, vmin, vmax float64, dataSet map[string]lipgloss.Color) *MyTimeChart { func NewTimeChart(width, height int, vmin, vmax float64, dataSet map[string]lipgloss.Color) *MyTimeChart {
result := MyTimeChart{} result := MyTimeChart{}
result.max = vmax result.max = vmax
result.min = vmin result.min = vmin
......
...@@ -2,13 +2,11 @@ package tui ...@@ -2,13 +2,11 @@ package tui
import ( import (
"fmt" "fmt"
"get-container/cmd/dcutop/tchart" "get-container/cmd/hytop/tchart"
"strings"
"testing" "testing"
"time" "time"
"github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss"
"github.com/emirpasic/gods/v2/trees/binaryheap"
) )
const S = `├───────────────────────────────┼──────────────────────┼──────────────────────┼ const S = `├───────────────────────────────┼──────────────────────┼──────────────────────┼
...@@ -52,7 +50,7 @@ func TestModel(t *testing.T) { ...@@ -52,7 +50,7 @@ func TestModel(t *testing.T) {
} }
func TestMyTimeChart(t *testing.T) { func TestMyTimeChart(t *testing.T) {
chart := New(100, 5, 0.0, 100.0, map[string]lipgloss.Color{"default": lipgloss.Color("#ff2222ff"), "other": lipgloss.Color("#0037ffff")}) chart := NewTimeChart(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("\n%s", s) t.Logf("\n%s", s)
...@@ -73,35 +71,6 @@ func TestMyTimeChart(t *testing.T) { ...@@ -73,35 +71,6 @@ func TestMyTimeChart(t *testing.T) {
} }
func TestBinaryHeap(t *testing.T) { func TestBinaryHeap(t *testing.T) {
t.Log(ReDCUName.FindString("BW200, U"))
heap := binaryheap.NewWith(func(a, b time.Time) int { t.Log(ReDCUName.FindString("K100_Ai, U"))
if a.After(b) {
return 1
}
if a.Before(b) {
return -1
}
return 0
})
now := time.Now()
for i := range 5 {
heap.Push(now.Add(time.Duration(i) * time.Second))
}
for {
tt, ok := heap.Pop()
if ok {
t.Logf("%s", tt)
} else {
break
}
}
}
func TestNewModelProcessInfo(t *testing.T) {
m := NewModelProcessInfo(130)
t.Logf("\n%s", m.Header)
for l := range strings.SplitSeq(m.Header, "\n") {
t.Log(lipgloss.Width(l))
}
t.Logf("\n%s", m.View())
} }
...@@ -17,6 +17,10 @@ import ( ...@@ -17,6 +17,10 @@ import (
"github.com/moby/moby/client" "github.com/moby/moby/client"
) )
func init() {
_ = initContainerInfo()
}
/** /**
有两种方法获取进程属于哪个容器 有两种方法获取进程属于哪个容器
1. 通过查询pid命名空间,仅在没有指定--pid参数时有效 1. 通过查询pid命名空间,仅在没有指定--pid参数时有效
...@@ -47,7 +51,7 @@ type ContainersInfo struct { ...@@ -47,7 +51,7 @@ type ContainersInfo struct {
type ContainerPsInfo struct { type ContainerPsInfo struct {
Pid int32 Pid int32
Ppid uint64 Ppid int32
Uid string Uid string
Cmd string Cmd string
} }
...@@ -83,18 +87,18 @@ func ParsePsInfo(topInfo map[string]container.TopResponse) (map[string][]Contain ...@@ -83,18 +87,18 @@ func ParsePsInfo(topInfo map[string]container.TopResponse) (map[string][]Contain
for _, fields := range topResp.Processes { for _, fields := range topResp.Processes {
item := ContainerPsInfo{} item := ContainerPsInfo{}
if v, ok := indexMap["pid"]; ok { if v, ok := indexMap["pid"]; ok {
pid, err := strconv.ParseUint(fields[v], 10, 64) pid, err := strconv.ParseInt(fields[v], 10, 64)
if err != nil { if err != nil {
return nil, err return nil, err
} }
item.Pid = int32(pid) item.Pid = int32(pid)
} }
if v, ok := indexMap["ppid"]; ok { if v, ok := indexMap["ppid"]; ok {
ppid, err := strconv.ParseUint(fields[v], 10, 64) ppid, err := strconv.ParseInt(fields[v], 10, 64)
if err != nil { if err != nil {
return nil, err return nil, err
} }
item.Ppid = ppid item.Ppid = int32(ppid)
} }
if v, ok := indexMap["uid"]; ok { if v, ok := indexMap["uid"]; ok {
item.Uid = fields[v] item.Uid = fields[v]
...@@ -128,10 +132,6 @@ func (info *ContainersInfo) Get() (map[string]container.InspectResponse, sync.Lo ...@@ -128,10 +132,6 @@ func (info *ContainersInfo) Get() (map[string]container.InspectResponse, sync.Lo
return info.inspectInfo, rl return info.inspectInfo, rl
} }
func init() {
_ = initContainerInfo()
}
func initContainerInfo() error { func initContainerInfo() error {
inspect, lists, tops, err := getContainerInfo() inspect, lists, tops, err := getContainerInfo()
if err != nil { if err != nil {
......
...@@ -90,16 +90,11 @@ func TestDocker(t *testing.T) { ...@@ -90,16 +90,11 @@ func TestDocker(t *testing.T) {
} }
func TestGetProcessIdInDocker(t *testing.T) { func TestGetProcessIdInDocker(t *testing.T) {
// now := time.Now()
// pids, err := ContainerInfo.GetProcessIdInDocker(true)
// d := time.Since(now)
// if err != nil {
// t.Error(err)
// }
// t.Logf("%v", d.Seconds())
// t.Logf("%+v", pids)
now := time.Now() now := time.Now()
err := initContainerInfo()
if err != nil {
t.Error(err)
}
pids, err := ContainerInfo.GetProcessIdInDocker(false) pids, err := ContainerInfo.GetProcessIdInDocker(false)
d := time.Since(now) d := time.Since(now)
if err != nil { if err != nil {
......
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