Files
YwxAppThink/app/backend/controller/AddonMonitor.php
T

280 lines
8.5 KiB
PHP

<?php
/*
* @Author: YwxApp <ywx@ywxapp.cn>
* @Date: 2026-07-17 17:02:05
* @LastEditors: YwxApp <ywx@ywxapp.cn>
* @LastEditTime: 2026-08-03 13:33:07
* @Description:
* @FilePath: \ywxapp_dev\app\backend\controller\AddonMonitor.php
* @CustomString: Copyright (c) 2026 YwxApp
*/
declare(strict_types=1);
namespace app\backend\controller;
use think\facade\View;
use ywxapp\controller\BackendBase;
use ywxapp\service\AddonPerformanceMonitor;
use ywxapp\service\AddonHotReload;
/**
* AddonMonitor 类
*
* @author ywxapp <admin@ywxapp.cn>
*/
class AddonMonitor extends BackendBase
{
protected $noNeedLogin = [];
protected $noNeedVerify = [];
public function index()
{
if ($this->request->isAjax()) {
$action = $this->request->param('action', 'overview');
switch ($action) {
case 'overview':
return $this->getOverview();
case 'performance':
return $this->getPerformance();
case 'health':
return $this->getHealth();
case 'reload':
return $this->getReloadStats();
case 'reload_addon':
return $this->reloadAddon();
case 'clear_performance':
return $this->clearPerformanceData();
default:
return $this->result->error('未知操作');
}
}
return View::fetch('addon_monitor/index');
}
/**
* 获取概览数据
*/
private function getOverview()
{
$overview = AddonPerformanceMonitor::getAllPerformanceOverview();
$problematic = AddonPerformanceMonitor::getProblematicaddon();
$reloadStats = AddonHotReload::getReloadStatistics();
// 统计数据
$totaladdon = count($overview);
$healthyaddon = 0;
$problematicaddon = count($problematic);
$totalCalls = 0;
$avgExecutionTime = 0;
$avgSuccessRate = 0;
foreach ($overview as $stats) {
if ($stats['success_rate'] > 95 && $stats['avg_execution_time'] < 1.0) {
$healthyaddon++;
}
$totalCalls += $stats['total_calls'];
$avgExecutionTime += $stats['avg_execution_time'];
$avgSuccessRate += $stats['success_rate'];
}
if ($totaladdon > 0) {
$avgExecutionTime = $avgExecutionTime / $totaladdon;
$avgSuccessRate = $avgSuccessRate / $totaladdon;
}
return $this->result->success([
'total_addon' => $totaladdon,
'healthy_addon' => $healthyaddon,
'problematic_addon' => $problematicaddon,
'total_calls' => $totalCalls,
'avg_execution_time' => round($avgExecutionTime * 1000, 2),
'avg_success_rate' => round($avgSuccessRate, 2),
'reload_stats' => $reloadStats
]);
}
/**
* 获取性能详情
*/
private function getPerformance()
{
$addon = $this->request->param('addon', '');
if (empty($addon)) {
// 返回所有插件性能数据
$overview = AddonPerformanceMonitor::getAllPerformanceOverview();
return $this->result->success($overview);
} else {
// 返回指定插件性能数据
$stats = AddonPerformanceMonitor::getPerformanceStats($addon);
return $this->result->success($stats);
}
}
/**
* 获取健康状态
*/
private function getHealth()
{
$problematic = AddonPerformanceMonitor::getProblematicaddon();
$overview = AddonPerformanceMonitor::getAllPerformanceOverview();
// 生成健康报告
$healthReport = [];
foreach ($overview as $addon => $stats) {
$isHealthy = true;
$issues = [];
if ($stats['avg_execution_time'] > AddonPerformanceMonitor::PERFORMANCE_THRESHOLD) {
$isHealthy = false;
$issues[] = '执行时间过长';
}
if ($stats['avg_memory_usage'] > AddonPerformanceMonitor::MEMORY_THRESHOLD) {
$isHealthy = false;
$issues[] = '内存使用过多';
}
if ($stats['success_rate'] < 90) {
$isHealthy = false;
$issues[] = '成功率过低';
}
$healthReport[$addon] = [
'healthy' => $isHealthy,
'issues' => $issues,
'stats' => $stats
];
}
return $this->result->success([
'health_report' => $healthReport,
'problematic_addon' => $problematic
]);
}
/**
* 获取热重载统计
*/
private function getReloadStats()
{
$stats = AddonHotReload::getReloadStatistics();
return $this->result->success($stats);
}
/**
* 重载插件
*/
private function reloadAddon()
{
$addon = $this->request->param('addon', '');
$force = $this->request->param('force', false);
if (empty($addon)) {
return $this->result->error('请指定插件名称');
}
if (!config('app.app_debug')) {
return $this->result->error('热重载功能仅在开发环境可用');
}
try {
$reloaded = AddonHotReload::reloadAddon($addon, $force);
if ($reloaded) {
$status = AddonHotReload::getReloadStatus($addon);
return $this->result->success([
'reloaded' => true,
'status' => $status
], '插件重载成功');
} else {
return $this->result->success([
'reloaded' => false
], '插件无文件变更,无需重载');
}
} catch (\Exception $e) {
return $this->result->error('插件重载失败:' . $e->getMessage());
}
}
/**
* 清除性能数据
*/
private function clearPerformanceData()
{
$addon = $this->request->param('addon', '');
try {
if (empty($addon)) {
AddonPerformanceMonitor::clearPerformanceData();
return $this->result->success([], '已清除所有插件性能数据');
} else {
AddonPerformanceMonitor::clearPerformanceData($addon);
return $this->result->success([], "已清除插件 {$addon} 的性能数据");
}
} catch (\Exception $e) {
return $this->result->error('清除性能数据失败:' . $e->getMessage());
}
}
/**
* 性能图表数据
*/
public function chart()
{
$type = $this->request->param('type', 'execution_time');
$period = $this->request->param('period', 'day'); // day, week, month
$overview = AddonPerformanceMonitor::getAllPerformanceOverview();
$chartData = [];
foreach ($overview as $addon => $stats) {
if ($stats['total_calls'] === 0) {
continue;
}
switch ($type) {
case 'execution_time':
$chartData[] = [
'name' => $addon,
'value' => round($stats['avg_execution_time'] * 1000, 2)
];
break;
case 'memory_usage':
$chartData[] = [
'name' => $addon,
'value' => round($stats['avg_memory_usage'] / 1024, 2)
];
break;
case 'success_rate':
$chartData[] = [
'name' => $addon,
'value' => round($stats['success_rate'], 2)
];
break;
case 'call_count':
$chartData[] = [
'name' => $addon,
'value' => $stats['total_calls']
];
break;
}
}
// 按值排序
usort($chartData, function($a, $b) {
return $b['value'] - $a['value'];
});
// 只返回前10个
$chartData = array_slice($chartData, 0, 10);
return $this->result->success([
'chart_data' => $chartData,
'type' => $type,
'period' => $period
]);
}
}