mirror of
				https://github.com/siderolabs/talos.git
				synced 2025-11-04 02:11:12 +01:00 
			
		
		
		
	Processes and their info are not guaranteed to be present on the api-based data gathered by the dashboard. Therefore, we switch to using nil-safe access to the CPU time when rendering the process table. Closes siderolabs/talos#7645. Signed-off-by: Utku Ozdemir <utku.ozdemir@siderolabs.com>
		
			
				
	
	
		
			115 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			115 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// This Source Code Form is subject to the terms of the Mozilla Public
 | 
						|
// License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
						|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
 | 
						|
 | 
						|
package components
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"path/filepath"
 | 
						|
	"sort"
 | 
						|
	"strings"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"github.com/dustin/go-humanize"
 | 
						|
	ui "github.com/gizak/termui/v3"
 | 
						|
	"github.com/gizak/termui/v3/widgets"
 | 
						|
 | 
						|
	"github.com/siderolabs/talos/internal/pkg/dashboard/apidata"
 | 
						|
)
 | 
						|
 | 
						|
// ProcessTable represents the widget with process info.
 | 
						|
type ProcessTable struct {
 | 
						|
	widgets.List
 | 
						|
}
 | 
						|
 | 
						|
// NewProcessTable initializes ProcessTable.
 | 
						|
func NewProcessTable() *ProcessTable {
 | 
						|
	widget := &ProcessTable{
 | 
						|
		List: *widgets.NewList(),
 | 
						|
	}
 | 
						|
 | 
						|
	widget.Border = false
 | 
						|
	widget.Title = fmt.Sprintf("%6s  %1s  %6s  %6s  %8s  %8s  %10s  %4s  %s",
 | 
						|
		"PID",
 | 
						|
		"S",
 | 
						|
		"CPU%",
 | 
						|
		"MEM%",
 | 
						|
		"VIRT",
 | 
						|
		"RES",
 | 
						|
		"TIME+",
 | 
						|
		"THR",
 | 
						|
		"COMMAND",
 | 
						|
	)
 | 
						|
	widget.Rows = []string{
 | 
						|
		noData,
 | 
						|
	}
 | 
						|
	widget.SelectedRowStyle = ui.NewStyle(ui.Theme.List.Text.Fg, ui.Theme.List.Text.Bg, ui.ModifierReverse)
 | 
						|
 | 
						|
	return widget
 | 
						|
}
 | 
						|
 | 
						|
// OnAPIDataChange implements the APIDataListener interface.
 | 
						|
func (widget *ProcessTable) OnAPIDataChange(node string, data *apidata.Data) {
 | 
						|
	nodeData := data.Nodes[node]
 | 
						|
 | 
						|
	if nodeData == nil {
 | 
						|
		widget.Rows = []string{
 | 
						|
			noData,
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		widget.Rows = widget.Rows[:0]
 | 
						|
 | 
						|
		totalMem := nodeData.Memory.GetMeminfo().GetMemtotal() * 1024
 | 
						|
		if totalMem == 0 {
 | 
						|
			totalMem = 1
 | 
						|
		}
 | 
						|
 | 
						|
		totalWeightedCPU := nodeData.CPUUsageByName("total_weighted")
 | 
						|
		if totalWeightedCPU == 0 {
 | 
						|
			totalWeightedCPU = 1
 | 
						|
		}
 | 
						|
 | 
						|
		// All downstream logic relies on nodeData.Processes to be not nil
 | 
						|
		// Putting a check here to reduce cyclomatic complexity
 | 
						|
		if nodeData.Processes == nil {
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		if nodeData.ProcsDiff != nil {
 | 
						|
			sort.Slice(nodeData.Processes.Processes, func(i, j int) bool {
 | 
						|
				proc1 := nodeData.Processes.Processes[i]
 | 
						|
				proc2 := nodeData.Processes.Processes[j]
 | 
						|
 | 
						|
				return nodeData.ProcsDiff[proc1.Pid].CpuTime > nodeData.ProcsDiff[proc2.Pid].CpuTime
 | 
						|
			})
 | 
						|
		}
 | 
						|
 | 
						|
		for _, proc := range nodeData.Processes.Processes {
 | 
						|
			var args string
 | 
						|
 | 
						|
			switch {
 | 
						|
			case proc.Executable == "":
 | 
						|
				args = proc.Command
 | 
						|
			case proc.Args != "" && strings.Fields(proc.Args)[0] == filepath.Base(strings.Fields(proc.Executable)[0]):
 | 
						|
				args = strings.Replace(proc.Args, strings.Fields(proc.Args)[0], proc.Executable, 1)
 | 
						|
			default:
 | 
						|
				args = proc.Args
 | 
						|
			}
 | 
						|
 | 
						|
			line := fmt.Sprintf("%7d  %s  %6.1f  %6.1f  %8s  %8s  %10s  %4d  %s",
 | 
						|
				proc.GetPid(),
 | 
						|
				proc.State,
 | 
						|
				nodeData.ProcsDiff[proc.Pid].GetCpuTime()/totalWeightedCPU*100.0,
 | 
						|
				float64(proc.ResidentMemory)/float64(totalMem)*100.0,
 | 
						|
				humanize.Bytes(proc.VirtualMemory),
 | 
						|
				humanize.Bytes(proc.ResidentMemory),
 | 
						|
				time.Duration(proc.CpuTime)*time.Second,
 | 
						|
				proc.Threads,
 | 
						|
				args,
 | 
						|
			)
 | 
						|
			widget.Rows = append(widget.Rows, line)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 |