Browse Source

state

master
zhaodengke 1 year ago
parent
commit
7bb4d00abd
6 changed files with 325 additions and 3 deletions
  1. +12
    -0
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/file/StateController.java
  2. +126
    -0
      ruoyi-file/src/main/java/com/ruoyi/file/object/RuntimeState.java
  3. +1
    -1
      ruoyi-file/src/main/java/com/ruoyi/file/object/StateMachine.java
  4. +9
    -2
      ruoyi-file/src/main/java/com/ruoyi/file/service/StateService.java
  5. +7
    -0
      ruoyi-ui/src/api/file/state.js
  6. +170
    -0
      ruoyi-ui/src/views/file/runtime/index.vue

+ 12
- 0
ruoyi-admin/src/main/java/com/ruoyi/web/controller/file/StateController.java View File

@@ -5,6 +5,7 @@ import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.file.model.FileModel;
import com.ruoyi.file.model.FileSystemFilter;
import com.ruoyi.file.object.ProjectState;
import com.ruoyi.file.object.RuntimeState;
import com.ruoyi.file.object.StateMachine;
import com.ruoyi.file.service.FileSystemService;
import com.ruoyi.file.service.StateService;
@@ -94,4 +95,15 @@ public class StateController extends BaseController
return AjaxResult.success();
}

/**
* 查询jvm信息
*/
@ApiOperation("查询jvm信息")
@PreAuthorize("@ss.hasPermi('admin:state:runtime')")
@GetMapping("/runtime")
public AjaxResult runtime()
{
RuntimeState state = stateService.runtimeState();
return AjaxResult.success(state);
}
}

+ 126
- 0
ruoyi-file/src/main/java/com/ruoyi/file/object/RuntimeState.java View File

@@ -0,0 +1,126 @@
package com.ruoyi.file.object;

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;

import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryPoolMXBean;
import java.lang.management.MemoryUsage;
import java.lang.management.RuntimeMXBean;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Data
public final class RuntimeState
{
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS")
private Date startTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS")
private Date uptime;
private long runDuration;
private String arguments;

private long heapUsed;
private long heapInit;
private long heapMax;
private long heapCommitted;

private long nonHeapUsed;
private long nonHeapInit;
private long nonHeapMax;
private long nonHeapCommitted;

private long threadCount;
private long daemonThreadCount;
private long peakThreadCount;
private long startedThreadCount;
private List<ThreadState> threads;

private List<MemoryPoolState> memoryPools;

@Data
public static class ThreadState
{
private long threadId;
private String threadName;
private String threadState;
private Boolean isCurrent;
}

@Data
public static class MemoryPoolState
{
private String name;
private String type;
private long memoryUsed = -1;
private long memoryInit = -1;
private long memoryMax = -1;
private long memoryCommitted = -1;
}

public static RuntimeState capture()
{
RuntimeState state = new RuntimeState();
RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
long startTime = runtimeMXBean.getStartTime();
long uptime = runtimeMXBean.getUptime();
state.startTime = new Date(startTime);
state.uptime = new Date(startTime + uptime);
state.runDuration = uptime;
state.arguments = String.join(" ", runtimeMXBean.getInputArguments());

MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
MemoryUsage heapMemoryUsage = memoryMXBean.getHeapMemoryUsage();
state.heapUsed = heapMemoryUsage.getUsed();
state.heapMax = heapMemoryUsage.getMax();
state.heapInit = heapMemoryUsage.getInit();
state.heapCommitted = heapMemoryUsage.getCommitted();

MemoryUsage nonHeapMemoryUsage = memoryMXBean.getNonHeapMemoryUsage();
state.nonHeapUsed = nonHeapMemoryUsage.getUsed();
state.nonHeapMax = nonHeapMemoryUsage.getMax();
state.nonHeapInit = nonHeapMemoryUsage.getInit();
state.nonHeapCommitted = nonHeapMemoryUsage.getCommitted();

ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
state.threadCount = threadMXBean.getThreadCount();
state.daemonThreadCount = threadMXBean.getDaemonThreadCount();
state.peakThreadCount = threadMXBean.getPeakThreadCount();
state.startedThreadCount = threadMXBean.getTotalStartedThreadCount();
ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(true, true);
state.threads = new ArrayList<>();
for(ThreadInfo threadInfo : threadInfos)
{
ThreadState t = new ThreadState();
t.threadId = threadInfo.getThreadId();
t.threadName = threadInfo.getThreadName();
t.threadState = threadInfo.getThreadState().name();
t.isCurrent = threadInfo.getThreadId() == Thread.currentThread().getId();
state.threads.add(t);
}

state.memoryPools = new ArrayList<>();
List<MemoryPoolMXBean> memoryPoolMXBeans = ManagementFactory.getMemoryPoolMXBeans();
for(MemoryPoolMXBean memoryPoolMXBean : memoryPoolMXBeans)
{
MemoryPoolState m = new MemoryPoolState();
m.name = memoryPoolMXBean.getName();
m.type = memoryPoolMXBean.getType().name();
MemoryUsage usage = memoryPoolMXBean.getUsage();
if(null != usage)
{
m.memoryUsed = usage.getUsed();
m.memoryMax = usage.getMax();
m.memoryInit = usage.getInit();
m.memoryCommitted = usage.getCommitted();
}
state.memoryPools.add(m);
}

return state;
}
}

+ 1
- 1
ruoyi-file/src/main/java/com/ruoyi/file/object/StateMachine.java View File

@@ -178,7 +178,7 @@ public final class StateMachine

public void GC()
{
System.gc();
//System.gc();
gcCount++;
lastGCTime = new Date();
}


+ 9
- 2
ruoyi-file/src/main/java/com/ruoyi/file/service/StateService.java View File

@@ -5,14 +5,13 @@ import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.file.object.ProjectState;
import com.ruoyi.file.object.RuntimeState;
import com.ruoyi.file.object.StateMachine;
import com.ruoyi.file.utils.ProjectUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.Date;
import java.util.List;
import java.util.Map;

@@ -32,9 +31,17 @@ public class StateService
return StateMachine.INSTANCE.GetStates();
}

public RuntimeState runtimeState()
{
return RuntimeState.capture();
}

public long gc()
{
StateMachine.INSTANCE.GC();
dump();
System.gc();
init();
return StateMachine.INSTANCE.gcCount;
}



+ 7
- 0
ruoyi-ui/src/api/file/state.js View File

@@ -34,3 +34,10 @@ export function dump() {
method: 'post',
})
}

export function runtimeState() {
return request({
url: '/state/runtime',
method: 'get',
})
}

+ 170
- 0
ruoyi-ui/src/views/file/runtime/index.vue View File

@@ -0,0 +1,170 @@
<template>
<div class="app-container">
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="gc" v-hasPermi="['admin:state:gc']">GC</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="refresh"></right-toolbar>
</el-row>

<el-divider content-position="left">JVM</el-divider>
<Descriptions>
<el-descriptions-item label="启动时间">{{state.startTime}}</el-descriptions-item>
<el-descriptions-item label="当前时间">{{state.uptime}}</el-descriptions-item>
<el-descriptions-item label="运行时长(s)">{{state.runDuration / 1000}}</el-descriptions-item>
<el-descriptions-item label="启动参数">{{state.arguments}}</el-descriptions-item>
</Descriptions>
<el-divider content-position="left">堆内存</el-divider>
<Descriptions>
<el-descriptions-item label="初始分配">{{state.heapInit | formatFileSize}}</el-descriptions-item>
<el-descriptions-item label="最大">{{state.heapMax | formatFileSize}}</el-descriptions-item>
<el-descriptions-item label="已使用">{{state.heapUsed | formatFileSize}}</el-descriptions-item>
<el-descriptions-item label="已提交">{{state.heapCommitted | formatFileSize}}</el-descriptions-item>
</Descriptions>
<el-divider content-position="left">非堆内存</el-divider>
<Descriptions>
<el-descriptions-item label="初始分配">{{state.nonHeapInit | formatFileSize}}</el-descriptions-item>
<el-descriptions-item label="最大">{{state.nonHeapMax | formatFileSize}}</el-descriptions-item>
<el-descriptions-item label="已使用">{{state.nonHeapUsed | formatFileSize}}</el-descriptions-item>
<el-descriptions-item label="已提交">{{state.nonHeapCommitted | formatFileSize}}</el-descriptions-item>
</Descriptions>
<el-divider content-position="left">内存池</el-divider>
<el-table :data="state.memoryPools || []">
<el-table-column type="index" label="序号" width="50" align="center" />
<el-table-column label="名称" align="left" header-align="center" prop="name" />
<el-table-column label="类型" align="center" prop="type"/>
<el-table-column label="初始分配" align="center" prop="memoryInit" :formatter="fileSizeFormatter"/>
<el-table-column label="最大" align="center" prop="memoryMax" :formatter="fileSizeFormatter"/>
<el-table-column label="已使用" align="center" prop="memoryUsed" :formatter="fileSizeFormatter"/>
<el-table-column label="已提交" align="center" prop="memoryCommitted" :formatter="fileSizeFormatter"/>
</el-table>
<el-divider content-position="left">线程</el-divider>
<Descriptions>
<el-descriptions-item label="前后台活动线程数">{{state.threadCount}}</el-descriptions-item>
<el-descriptions-item label="后台活动线程数">{{state.daemonThreadCount}}</el-descriptions-item>
<el-descriptions-item label="实时线程数">{{state.peakThreadCount}}</el-descriptions-item>
<el-descriptions-item label="最多线程数">{{state.startedThreadCount}}</el-descriptions-item>
</Descriptions>
<el-table :data="state.threads || []" :row-style="threadRowStyle">
<el-table-column type="index" label="序号" width="50" align="center" />
<el-table-column label="线程ID" align="center" prop="threadId" sortable/>
<el-table-column label="线程名" align="left" header-align="center" prop="threadName" />
<el-table-column label="线程状态" align="center" prop="threadState" sortable/>
</el-table>
</div>
</template>

<script>
import DeptSelect from "@/components/common/DeptSelect.vue";
import ServerFileChooser from "@/components/ServerFileChooser.vue";
import FullscreenDialog from "@/components/FullscreenDialog.vue";
import ProjectState from "@/views/file/state/ProjectState.vue";
import {stateList, gc, stateMachine, dump, runtimeState} from "@/api/file/state";
import Descriptions from "@/components/common/Descriptions.vue";
import {formatFileSize} from "@/utils/file";


export default {
name: "State",
components: {
Descriptions,
ProjectState,
FullscreenDialog,
ServerFileChooser,
DeptSelect
},
dicts: ['sys_bool'],
data() {
return {
// 遮罩层
loading: false,
// 遮罩按钮新增点击状态
diglogStatus: true,
// 导出遮罩层
exportLoading: false,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 默认隐藏搜索条件
showSearch: false,
// 总条数
total: 0,
// 项目表格数据
stateList: [],
// 弹出层标题
title: "",
// 是否禁用 字典 sys_bool字典
disabledOptions: [],
// 查询参数
queryParams: {
// 分页
pageNum: 1,
pageSize: 10,
// 查询排序
//orderByColumn: "id",
//isAsc: "desc",
// 翻译字典
//translate_dict: "1",
},
// 表单参数
form: {},
// 详情组件列数
descColumn: 2,
// 详情组件Label所占百分比, 最大={100 / descColumn}. 内容所占百分比={100 / descColumn - descLabelWidth}
descLabelWidth: 15,
// 对话框显示只读的详情
projectToken: null,
state: {},
};
},
created() {
this.getRuntimeState();
},
methods: {
// 取消按钮
cancel() {
this.reset();
},
// 表单重置
reset() {
this.form = {
};
},
refresh() {
this.getRuntimeState();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
gc() {
gc().then((resp) => {
this.$message.success('成功');
this.getRuntimeState();
});
},
getRuntimeState() {
this.state = {};
runtimeState().then((resp) => {
this.state = resp.data;
});
},
fileSizeFormatter(row, col, val) {
return formatFileSize(val);
},
threadRowStyle({row}) {
let style = {};
if(row.isCurrent)
style['background-color'] = '#67C23A';
return style;
},
},
filters: {
formatFileSize,
},
};
</script>

Loading…
Cancel
Save