feat: 容器列表资源使用率增加详情显示 (#2371)

Refs #2223 

![image](https://github.com/1Panel-dev/1Panel/assets/73214554/e7f8bd8f-dd9a-4783-91eb-56759bad843e)
This commit is contained in:
ssongliu 2023-09-21 17:34:22 +08:00 committed by GitHub
parent 04eb8191ed
commit 975ff06d69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 173 additions and 16 deletions

View File

@ -63,8 +63,16 @@ type ContainerUpgrade struct {
}
type ContainerListStats struct {
ContainerID string `json:"containerID"`
ContainerID string `json:"containerID"`
CPUTotalUsage uint64 `json:"cpuTotalUsage"`
SystemUsage uint64 `json:"systemUsage"`
CPUPercent float64 `json:"cpuPercent"`
PercpuUsage int `json:"percpuUsage"`
MemroyCache uint64 `json:"memoryCache"`
MemoryUsage uint64 `json:"memoryUsage"`
MemoryLimit uint64 `json:"memoryLimit"`
MemoryPercent float64 `json:"memoryPercent"`
}

View File

@ -208,8 +208,7 @@ func (u *ContainerService) ContainerListStats() ([]dto.ContainerListStats, error
wg.Add(len(list))
for i := 0; i < len(list); i++ {
go func(item types.Container) {
cpu, mem := loadCpuAndMem(client, item.ID)
datas = append(datas, dto.ContainerListStats{CPUPercent: cpu, MemoryPercent: mem, ContainerID: item.ID})
datas = append(datas, loadCpuAndMem(client, item.ID))
wg.Done()
}(list[i])
}
@ -766,26 +765,36 @@ func pullImages(ctx context.Context, client *client.Client, image string) error
return nil
}
func loadCpuAndMem(client *client.Client, container string) (float64, float64) {
func loadCpuAndMem(client *client.Client, container string) dto.ContainerListStats {
data := dto.ContainerListStats{
ContainerID: container,
}
res, err := client.ContainerStats(context.Background(), container, false)
if err != nil {
return 0, 0
return data
}
body, err := io.ReadAll(res.Body)
if err != nil {
res.Body.Close()
return 0, 0
return data
}
res.Body.Close()
var stats *types.StatsJSON
if err := json.Unmarshal(body, &stats); err != nil {
return 0, 0
return data
}
CPUPercent := calculateCPUPercentUnix(stats)
MemPercent := calculateMemPercentUnix(stats.MemoryStats)
return CPUPercent, MemPercent
data.CPUTotalUsage = stats.CPUStats.CPUUsage.TotalUsage - stats.PreCPUStats.CPUUsage.TotalUsage
data.SystemUsage = stats.CPUStats.SystemUsage - stats.PreCPUStats.SystemUsage
data.CPUPercent = calculateCPUPercentUnix(stats)
data.PercpuUsage = len(stats.CPUStats.CPUUsage.PercpuUsage)
data.MemroyCache = stats.MemoryStats.Stats["cache"]
data.MemoryUsage = stats.MemoryStats.Usage
data.MemoryLimit = stats.MemoryStats.Limit
data.MemoryPercent = calculateMemPercentUnix(stats.MemoryStats)
return data
}
func checkPortStats(ports []dto.PortHelper) (nat.PortMap, error) {

View File

@ -70,7 +70,13 @@ export namespace Container {
}
export interface ContainerListStats {
containerID: string;
cpuTotalUsage: number;
systemUsage: number;
cpuPercent: number;
percpuUsage: number;
memoryCache: number;
memoryUsage: number;
memoryLimit: number;
memoryPercent: number;
}
export interface ContainerStats {

View File

@ -1,9 +1,9 @@
@font-face {
font-family: "panel"; /* Project id 3575356 */
src: url('iconfont.woff2?t=1687338712846') format('woff2'),
url('iconfont.woff?t=1687338712846') format('woff'),
url('iconfont.ttf?t=1687338712846') format('truetype'),
url('iconfont.svg?t=1687338712846#panel') format('svg');
src: url('iconfont.woff2?t=1695287081776') format('woff2'),
url('iconfont.woff?t=1695287081776') format('woff'),
url('iconfont.ttf?t=1695287081776') format('truetype'),
url('iconfont.svg?t=1695287081776#panel') format('svg');
}
.panel {
@ -14,6 +14,10 @@
-moz-osx-font-smoothing: grayscale;
}
.p-xiangqing:before {
content: "\e677";
}
.p-onedrive:before {
content: "\e601";
}

File diff suppressed because one or more lines are too long

View File

@ -5,6 +5,13 @@
"css_prefix_text": "p-",
"description": "",
"glyphs": [
{
"icon_id": "10293150",
"name": "详情",
"font_class": "xiangqing",
"unicode": "e677",
"unicode_decimal": 58999
},
{
"icon_id": "13015332",
"name": "onedrive",

View File

@ -14,6 +14,8 @@
/>
<missing-glyph />
<glyph glyph-name="xiangqing" unicode="&#58999;" d="M512 654.27010918m-77.34417915 0a77.34417915 77.34417915 0 1 1 154.6883583 0 77.34417915 77.34417915 0 1 1-154.6883583 0ZM512 384m-77.34417915 0a77.34417915 77.34417915 0 1 1 154.6883583 0 77.34417915 77.34417915 0 1 1-154.6883583 0ZM512 113.72989082000004m-77.34417915 0a77.34417915 77.34417915 0 1 1 154.6883583 0 77.34417915 77.34417915 0 1 1-154.6883583 0Z" horiz-adv-x="1024" />
<glyph glyph-name="onedrive" unicode="&#58881;" d="M597.333333 320s188.885333 129.152 192.96 128.874667A280.021333 280.021333 0 0 1 285.141333 533.333333h2.858667zM405.674667 499.968A222.869333 222.869333 0 0 1 288 533.333333h-2.858667a224 224 0 0 1-180.885333-352L405.333333 213.333333l188.437334 173.973334zM790.293333 448.874667a180.373333 180.373333 0 0 1-12.288 0.448 181.461333 181.461333 0 0 1-72.149333-14.933334l-112.085333-47.146666L725.333333 234.666667l212.906667-53.696a182.016 182.016 0 0 1-147.946667 267.904zM779.285333 276.181333l-46.464 27.733334-106.538666 63.808-32.512 19.477333-85.738667-36.096-164.266667-69.077333-73.642666-30.933334-165.866667-69.76A223.658667 223.658667 0 0 1 288 85.333333h490.005333a181.994667 181.994667 0 0 1 160.234667 95.637334z" horiz-adv-x="1024" />
<glyph glyph-name="caidan" unicode="&#58909;" d="M896 663.272727h-744.727273a34.909091 34.909091 0 0 0 0 69.818182h744.727273a34.909091 34.909091 0 0 0 0-69.818182zM896 11.636364h-744.727273a34.909091 34.909091 0 0 0 0 69.818181h744.727273a34.909091 34.909091 0 0 0 0-69.818181zM709.818182 337.454545h-558.545455a34.909091 34.909091 0 0 0 0 69.818182h558.545455a34.909091 34.909091 0 0 0 0-69.818182z" horiz-adv-x="1024" />

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

View File

@ -525,6 +525,12 @@ const message = {
'Clearing logs requires restarting the container, and this operation cannot be rolled back. Do you want to continue?',
newName: 'New name',
source: 'Resource rate',
cpuUsage: 'CPU Usage',
cpuTotal: 'CPU Total',
core: 'Core',
memUsage: 'Memory Usage',
memTotal: 'Memory Limit',
memCache: 'Memory Cache',
ip: 'IP address',
cpuShare: 'CPU Share',
cpuShareHelper:

View File

@ -511,6 +511,12 @@ const message = {
cleanLogHelper: '清空日誌需要重啟容器該操作無法回滾是否繼續',
newName: '新名稱',
source: '資源使用率',
cpuUsage: 'CPU 使用',
cpuTotal: 'CPU 總計',
core: '核心數',
memUsage: '內存使用',
memTotal: '內存限額',
memCache: '緩存使用',
ip: 'IP 地址',
cpuShare: 'CPU 權重',
cpuShareHelper: '容器默認份額為 1024 CPU增大可使當前容器獲得更多的 CPU 時間',

View File

@ -511,6 +511,12 @@ const message = {
cleanLogHelper: '清空日志需要重启容器该操作无法回滚是否继续',
newName: '新名称',
source: '资源使用率',
cpuUsage: 'CPU 使用',
cpuTotal: 'CPU 总计',
core: '核心数',
memUsage: '内存使用',
memTotal: '内存限额',
memCache: '缓存使用',
ip: 'IP 地址',
cpuShare: 'CPU 权重',
cpuShareHelper: '容器默认份额为 1024 CPU增大可使当前容器获得更多的 CPU 时间',

View File

@ -92,9 +92,69 @@
<template #default="{ row }">
<div v-if="row.hasLoad">
<div class="source-font">CPU: {{ row.cpuPercent.toFixed(2) }}%</div>
<div class="source-font">
<div class="float-left source-font">
{{ $t('monitor.memory') }}: {{ row.memoryPercent.toFixed(2) }}%
</div>
<el-popover placement="right" width="500px" class="float-right">
<template #reference>
<svg-icon iconName="p-xiangqing" class="svg-icon"></svg-icon>
</template>
<template #default>
<el-row>
<el-col :span="8">
<el-statistic
:title="$t('container.cpuUsage')"
:value="loadCPUValue(row.cpuTotalUsage)"
:precision="2"
>
<template #suffix>{{ loadCPUUnit(row.cpuTotalUsage) }}</template>
</el-statistic>
</el-col>
<el-col :span="8">
<el-statistic
:title="$t('container.cpuTotal')"
:value="loadCPUValue(row.systemUsage)"
:precision="2"
>
<template #suffix>{{ loadCPUUnit(row.systemUsage) }}</template>
</el-statistic>
</el-col>
<el-col :span="8">
<el-statistic :title="$t('container.core')" :value="row.percpuUsage" />
</el-col>
</el-row>
<el-row class="mt-4">
<el-col :span="8">
<el-statistic
:title="$t('container.memUsage')"
:value="loadMemValue(row.memoryUsage)"
:precision="2"
>
<template #suffix>{{ loadMemUnit(row.memoryUsage) }}</template>
</el-statistic>
</el-col>
<el-col :span="8">
<el-statistic
:title="$t('container.memCache')"
:value="loadMemValue(row.memoryCache)"
:precision="2"
>
<template #suffix>{{ loadMemUnit(row.memoryCache) }}</template>
</el-statistic>
</el-col>
<el-col :span="8">
<el-statistic
:title="$t('container.memTotal')"
:value="loadMemValue(row.memoryLimit)"
:precision="2"
>
<template #suffix>{{ loadMemUnit(row.memoryLimit) }}</template>
</el-statistic>
</el-col>
</el-row>
</template>
</el-popover>
</div>
<div v-if="!row.hasLoad">
<el-button link loading></el-button>
@ -314,7 +374,13 @@ const loadStats = async () => {
for (const item of stats) {
if (container.containerID === item.containerID) {
container.hasLoad = true;
container.cpuTotalUsage = item.cpuTotalUsage;
container.systemUsage = item.systemUsage;
container.cpuPercent = item.cpuPercent;
container.percpuUsage = item.percpuUsage;
container.memoryCache = item.memoryCache;
container.memoryUsage = item.memoryUsage;
container.memoryLimit = item.memoryLimit;
container.memoryPercent = item.memoryPercent;
break;
}
@ -322,6 +388,38 @@ const loadStats = async () => {
}
};
const loadCPUUnit = (t: number) => {
const num = 1000;
if (t < num) return ' ns';
if (t < Math.pow(num, 2)) return ' μs';
if (t < Math.pow(num, 3)) return ' ms';
return ' s';
};
function loadCPUValue(t: number) {
const num = 1000;
if (t < num) return t;
if (t < Math.pow(num, 2)) return Number((t / num).toFixed(2));
if (t < Math.pow(num, 3)) return Number((t / Math.pow(num, 2)).toFixed(2));
return Number((t / Math.pow(num, 3)).toFixed(2));
}
const loadMemUnit = (t: number) => {
if (t == 0) {
return '';
}
const num = 1024;
if (t < num) return ' B';
if (t < Math.pow(num, 2)) return ' KiB';
if (t < Math.pow(num, 3)) return ' MiB';
return ' GiB';
};
function loadMemValue(t: number) {
const num = 1024;
if (t < num) return t;
if (t < Math.pow(num, 2)) return Number((t / num).toFixed(2));
if (t < Math.pow(num, 3)) return Number((t / Math.pow(num, 2)).toFixed(2));
return Number((t / Math.pow(num, 3)).toFixed(2));
}
const dialogOperateRef = ref();
const onEdit = async (container: string) => {
const res = await loadContainerInfo(container);
@ -549,4 +647,9 @@ onMounted(() => {
.source-font {
font-size: 12px;
}
.svg-icon {
margin-top: -3px;
font-size: 6px;
cursor: pointer;
}
</style>