Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
185 changes: 167 additions & 18 deletions agent/app/service/process.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package service

import (
"bufio"
"fmt"
"github.com/1Panel-dev/1Panel/agent/app/dto/request"
"github.com/1Panel-dev/1Panel/agent/utils/common"
"github.com/1Panel-dev/1Panel/agent/utils/websocket"
"github.com/shirou/gopsutil/v4/process"
"os"
"strconv"
"strings"
"time"
)

Expand All @@ -31,7 +35,7 @@
return nil
}

func (ps *ProcessService) GetProcessInfoByPID(pid int32) (*websocket.PsProcessData, error) {

Check failure on line 38 in agent/app/service/process.go

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this method to reduce its Cognitive Complexity from 20 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=1Panel-dev_1Panel&issues=AZrDPTdaI6VmzbhRH-Zs&open=AZrDPTdaI6VmzbhRH-Zs&pullRequest=11093
p, err := process.NewProcess(pid)
if err != nil {
return nil, fmt.Errorf("get process info by pid %v: %v", pid, err)
Expand Down Expand Up @@ -103,24 +107,20 @@
data.CmdLine = cmdline
}

if memInfo, err := p.MemoryInfo(); err == nil {
data.Rss = common.FormatBytes(memInfo.RSS)
data.VMS = common.FormatBytes(memInfo.VMS)
data.HWM = common.FormatBytes(memInfo.HWM)
data.Data = common.FormatBytes(memInfo.Data)
data.Stack = common.FormatBytes(memInfo.Stack)
data.Locked = common.FormatBytes(memInfo.Locked)
data.Swap = common.FormatBytes(memInfo.Swap)
data.RssValue = memInfo.RSS
} else {
data.Rss = "--"
data.Data = "--"
data.VMS = "--"
data.HWM = "--"
data.Stack = "--"
data.Locked = "--"
data.Swap = "--"
data.RssValue = 0
if memDetail, err := getMemoryDetail(p.Pid); err == nil {
data.Rss = common.FormatBytes(memDetail.RSS)
data.VMS = common.FormatBytes(memDetail.VMS)
data.HWM = common.FormatBytes(memDetail.HWM)
data.Data = common.FormatBytes(memDetail.Data)
data.Stack = common.FormatBytes(memDetail.Stack)
data.Locked = common.FormatBytes(memDetail.Locked)
data.Swap = common.FormatBytes(memDetail.Swap)
data.Dirty = common.FormatBytes(memDetail.Dirty)
data.RssValue = memDetail.RSS
data.PSS = common.FormatBytes(memDetail.PSS)
data.USS = common.FormatBytes(memDetail.USS)
data.Shared = common.FormatBytes(memDetail.Shared)
data.Text = common.FormatBytes(memDetail.Text)
}

if envs, err := p.Environ(); err == nil {
Expand All @@ -133,3 +133,152 @@

return data, nil
}

type MemoryDetail struct {
RSS uint64
VMS uint64
HWM uint64
Data uint64
Stack uint64
Locked uint64
Swap uint64

PSS uint64
USS uint64
Shared uint64
Text uint64
Dirty uint64
}

func getMemoryDetail(pid int32) (*MemoryDetail, error) {

Check warning on line 153 in agent/app/service/process.go

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove the 'Get' prefix from this function name.

See more on https://sonarcloud.io/project/issues?id=1Panel-dev_1Panel&issues=AZrDPTdaI6VmzbhRH-Zt&open=AZrDPTdaI6VmzbhRH-Zt&pullRequest=11093
mem := &MemoryDetail{}

if err := readStatus(pid, mem); err != nil {
return nil, err
}

if err := readSmapsRollup(pid, mem); err != nil {
if err := readSmaps(pid, mem); err != nil {
return nil, err
}
}
return mem, nil
}

func readStatus(pid int32, mem *MemoryDetail) error {
filePath := fmt.Sprintf("/proc/%d/status", pid)
file, err := os.Open(filePath)
if err != nil {
return err
}
defer file.Close()

scanner := bufio.NewScanner(file)

for scanner.Scan() {
line := scanner.Text()
fields := strings.Fields(line)
if len(fields) < 2 {
continue
}

key := strings.TrimSuffix(fields[0], ":")
value, _ := strconv.ParseUint(fields[1], 10, 64)

Check failure on line 186 in agent/app/service/process.go

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Handle this error explicitly or document why it can be safely ignored.

See more on https://sonarcloud.io/project/issues?id=1Panel-dev_1Panel&issues=AZrDPTdaI6VmzbhRH-Zu&open=AZrDPTdaI6VmzbhRH-Zu&pullRequest=11093
value *= 1024

switch key {
case "VmRSS":
mem.RSS = value
case "VmSize":
mem.VMS = value
case "VmData":
mem.Data = value
case "VmSwap":
mem.Swap = value
case "VmExe":
mem.Text = value
case "RssShmem":
mem.Shared = value
case "VmHWM":
mem.HWM = value
case "VmStk":
mem.Stack = value
case "VmLck":
mem.Locked = value
}
}

return scanner.Err()
}

func readSmapsRollup(pid int32, mem *MemoryDetail) error {
filePath := fmt.Sprintf("/proc/%d/smaps_rollup", pid)
file, err := os.Open(filePath)
if err != nil {
return err
}
defer file.Close()

scanner := bufio.NewScanner(file)

for scanner.Scan() {
line := scanner.Text()
fields := strings.Fields(line)
if len(fields) < 2 {
continue
}

key := strings.TrimSuffix(fields[0], ":")
value, _ := strconv.ParseUint(fields[1], 10, 64)

Check failure on line 232 in agent/app/service/process.go

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Handle this error explicitly or document why it can be safely ignored.

See more on https://sonarcloud.io/project/issues?id=1Panel-dev_1Panel&issues=AZrDPTdaI6VmzbhRH-Zv&open=AZrDPTdaI6VmzbhRH-Zv&pullRequest=11093
value *= 1024

switch key {
case "Pss":
mem.PSS = value
case "Private_Clean", "Private_Dirty":
mem.USS += value
case "Shared_Clean", "Shared_Dirty":
if mem.Shared == 0 {
mem.Shared = value
}
}
}

return scanner.Err()
}

func readSmaps(pid int32, mem *MemoryDetail) error {
filePath := fmt.Sprintf("/proc/%d/smaps", pid)
file, err := os.Open(filePath)
if err != nil {
return err
}
defer file.Close()

scanner := bufio.NewScanner(file)

for scanner.Scan() {
line := scanner.Text()
fields := strings.Fields(line)
if len(fields) < 2 {
continue
}

key := strings.TrimSuffix(fields[0], ":")
value, _ := strconv.ParseUint(fields[1], 10, 64)

Check failure on line 268 in agent/app/service/process.go

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Handle this error explicitly or document why it can be safely ignored.

See more on https://sonarcloud.io/project/issues?id=1Panel-dev_1Panel&issues=AZrDPTdaI6VmzbhRH-Zw&open=AZrDPTdaI6VmzbhRH-Zw&pullRequest=11093
value *= 1024

switch key {
case "Pss":
mem.PSS += value
case "Private_Clean", "Private_Dirty":
mem.USS += value
case "Shared_Clean", "Shared_Dirty":
if mem.Shared == 0 {
mem.Shared += value
}
}
}

return scanner.Err()
}
5 changes: 5 additions & 0 deletions agent/utils/websocket/process_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ type PsProcessData struct {
Stack string `json:"stack"`
Locked string `json:"locked"`
Swap string `json:"swap"`
Dirty string `json:"dirty"`
PSS string `json:"pss"`
USS string `json:"uss"`
Shared string `json:"shared"`
Text string `json:"text"`

CpuValue float64 `json:"cpuValue"`
RssValue uint64 `json:"rssValue"`
Expand Down
5 changes: 5 additions & 0 deletions frontend/src/api/interface/process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ export namespace Process {
stack: string;
locked: string;
swap: string;
dirty: string;
pss: string;
uss: string;
shared: string;
text: string;

cpuValue: number;
rssValue: number;
Expand Down
5 changes: 5 additions & 0 deletions frontend/src/views/host/process/process/detail/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,17 @@
<el-tab-pane :label="$t('process.mem')" name="mem">
<el-descriptions :column="2" border>
<el-descriptions-item :label="'rss'">{{ data.rss }}</el-descriptions-item>
<el-descriptions-item :label="'pss'">{{ data.pss }}</el-descriptions-item>
<el-descriptions-item :label="'uss'">{{ data.uss }}</el-descriptions-item>
<el-descriptions-item :label="'swap'">{{ data.swap }}</el-descriptions-item>
<el-descriptions-item :label="'shared'">{{ data.shared }}</el-descriptions-item>
<el-descriptions-item :label="'vms'">{{ data.vms }}</el-descriptions-item>
<el-descriptions-item :label="'hwm'">{{ data.hwm }}</el-descriptions-item>
<el-descriptions-item :label="'data'">{{ data.data }}</el-descriptions-item>
<el-descriptions-item :label="'stack'">{{ data.stack }}</el-descriptions-item>
<el-descriptions-item :label="'locked'">{{ data.locked }}</el-descriptions-item>
<el-descriptions-item :label="'text'">{{ data.text }}</el-descriptions-item>
<el-descriptions-item :label="'dirty'">{{ data.dirty }}</el-descriptions-item>
</el-descriptions>
</el-tab-pane>
<el-tab-pane :label="$t('process.openFiles')" name="openFiles">
Expand Down
Loading