feat: DevTools调试工具 + 前端样式修复 + 管理员登录系统
DevTools (新增): - 进程管理器: 启动/停止/重启/编译 + 端口自动释放 - 服务接管 (tryAdopt): 检测已运行服务,健康检查通过则直接接管 - 一键启动 (startAllSequential): 按 ai-core→gateway→frontend 顺序启动 - 日志布局切换: 标签页模式 ↔ 三栏并列模式 - 性能监控: CPU/内存采样 + SVG 折线图 - Web UI + WebSocket 实时推送 前端修复: - tailwind.config.ts: 修复空配置导致 CSS 不加载 (增加 content/colors/fontFamily) - postcss.config.js: 新建缺失的 PostCSS 配置 - App.tsx: 移除注册功能,仅保留管理员登录 (admin / cyrene-dev-admin) 后端新增: - config.go: AdminUsername/AdminPassword/RegistrationEnabled 环境变量 - auth_handler.go: 管理员登录 + 注册邮箱验证码 + 注册开关控制 - 管理员凭据: admin / cyrene-dev-admin (默认) 其他: - .gitignore: 新增 devtools/node_modules/ devtools/logs/ devtools/package-lock.json - devtools.sh: DevTools 一键启动脚本
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* 性能监控模块
|
||||
* 监控各服务进程的 CPU、内存使用情况
|
||||
*/
|
||||
|
||||
import pidusage from 'pidusage';
|
||||
import { processManager } from './process-manager.js';
|
||||
import { SERVICES } from './config.js';
|
||||
|
||||
class PerformanceMonitor {
|
||||
constructor() {
|
||||
/** @type {Map<string, Array<{ts: number, cpu: number, mem: number}>>} */
|
||||
this.history = new Map();
|
||||
this.interval = null;
|
||||
|
||||
for (const id of Object.keys(SERVICES)) {
|
||||
this.history.set(id, []);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始定期采样 (每3秒)
|
||||
*/
|
||||
start() {
|
||||
if (this.interval) return;
|
||||
this.interval = setInterval(() => this.sample(), 3000);
|
||||
this.interval.unref(); // 不阻止进程退出
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止采样
|
||||
*/
|
||||
stop() {
|
||||
if (this.interval) {
|
||||
clearInterval(this.interval);
|
||||
this.interval = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 采样一次
|
||||
*/
|
||||
async sample() {
|
||||
for (const [id, info] of processManager.processes) {
|
||||
if (!info.pid) continue;
|
||||
try {
|
||||
const stats = await pidusage(info.pid);
|
||||
const history = this.history.get(id);
|
||||
history.push({
|
||||
ts: Date.now(),
|
||||
cpu: Math.round(stats.cpu * 100) / 100,
|
||||
mem: Math.round(stats.memory / 1024 / 1024 * 100) / 100, // MB
|
||||
});
|
||||
// 保留最近300条 (约15分钟)
|
||||
if (history.length > 300) {
|
||||
history.splice(0, history.length - 300);
|
||||
}
|
||||
} catch {
|
||||
// 进程可能已退出
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前性能快照
|
||||
*/
|
||||
async getSnapshot() {
|
||||
const result = {};
|
||||
for (const [id, info] of processManager.processes) {
|
||||
if (!info.pid) {
|
||||
result[id] = { pid: null, cpu: 0, mem: 0 };
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
const stats = await pidusage(info.pid);
|
||||
result[id] = {
|
||||
pid: info.pid,
|
||||
cpu: Math.round(stats.cpu * 100) / 100,
|
||||
mem: Math.round(stats.memory / 1024 / 1024 * 100) / 100,
|
||||
elapsed: stats.elapsed,
|
||||
};
|
||||
} catch {
|
||||
result[id] = { pid: info.pid, cpu: 0, mem: 0 };
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取历史数据
|
||||
*/
|
||||
getHistory(serviceId) {
|
||||
return this.history.get(serviceId) || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有服务的历史数据
|
||||
*/
|
||||
getAllHistory() {
|
||||
const result = {};
|
||||
for (const id of this.history.keys()) {
|
||||
result[id] = this.history.get(id);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
export const performanceMonitor = new PerformanceMonitor();
|
||||
Reference in New Issue
Block a user