feat(admin): XHProf 函数监控规则与命中记录

This commit is contained in:
augushong
2026-08-15 07:02:37 +08:00
parent e57b186126
commit c980ebdff0
23 changed files with 901 additions and 1 deletions

View File

@@ -0,0 +1,11 @@
var init = {
tableElem: '#currentTable',
tableRenderId: 'currentTableRenderId',
indexUrl: 'xhprof.run_watch/index',
addUrl: '',
editUrl: '',
readUrl: 'xhprof.run_watch/read',
deleteUrl: '',
exportUrl: '',
modifyUrl: '',
};

View File

@@ -0,0 +1,44 @@
<div class="layuimini-container">
<form id="app-form" class="layui-form layuimini-form">
<div class="layui-form-item">
<label class="layui-form-label">采样记录IDul_xhprof_run.id</label>
<div class="layui-input-block">
<input type="text" name="run_id" class="layui-input" placeholder="请输入采样记录IDul_xhprof_run.id" value="{$Request.param.run_id|default='0'}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">监控规则IDul_xhprof_watch.id</label>
<div class="layui-input-block">
<input type="text" name="watch_id" class="layui-input" placeholder="请输入监控规则IDul_xhprof_watch.id" value="{$Request.param.watch_id|default='0'}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">命中边次数和</label>
<div class="layui-input-block">
<input type="text" name="ct" class="layui-input" placeholder="请输入命中边次数和" value="{$Request.param.ct|default='0'}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">命中耗时合计(微秒)</label>
<div class="layui-input-block">
<input type="text" name="wt_sum" class="layui-input" placeholder="请输入命中耗时合计(微秒)" value="{$Request.param.wt_sum|default='0'}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">命中单次最大耗时(微秒)</label>
<div class="layui-input-block">
<input type="text" name="wt_max" class="layui-input" placeholder="请输入命中单次最大耗时(微秒)" value="{$Request.param.wt_max|default='0'}">
</div>
</div>
<div class="hr-line"></div>
<div class="layui-form-item text-center">
{notempty name='$Request.param.backTagId'}
<div class="layui-btn layui-btn-sm page-back-button" layuimini-content-href="{$Request.param.backTagId}" data-back="1">返回</div>
{/notempty}
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit>确认</button>
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">重置</button>
</div>
</form>
</div>

View File

@@ -0,0 +1,3 @@
$(function(){
ua.listen();
})

View File

@@ -0,0 +1,44 @@
<div class="layuimini-container">
<form id="app-form" class="layui-form layuimini-form">
<div class="layui-form-item">
<label class="layui-form-label">采样记录IDul_xhprof_run.id</label>
<div class="layui-input-block">
<input type="text" name="run_id" class="layui-input" placeholder="请输入采样记录IDul_xhprof_run.id" value="{$row.run_id|default=''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">监控规则IDul_xhprof_watch.id</label>
<div class="layui-input-block">
<input type="text" name="watch_id" class="layui-input" placeholder="请输入监控规则IDul_xhprof_watch.id" value="{$row.watch_id|default=''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">命中边次数和</label>
<div class="layui-input-block">
<input type="text" name="ct" class="layui-input" placeholder="请输入命中边次数和" value="{$row.ct|default=''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">命中耗时合计(微秒)</label>
<div class="layui-input-block">
<input type="text" name="wt_sum" class="layui-input" placeholder="请输入命中耗时合计(微秒)" value="{$row.wt_sum|default=''}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">命中单次最大耗时(微秒)</label>
<div class="layui-input-block">
<input type="text" name="wt_max" class="layui-input" placeholder="请输入命中单次最大耗时(微秒)" value="{$row.wt_max|default=''}">
</div>
</div>
<div class="hr-line"></div>
<div class="layui-form-item text-center">
{notempty name='$Request.param.backTagId'}
<div class="layui-btn layui-btn-sm page-back-button" layuimini-content-href="{$Request.param.backTagId}" data-back="1">返回</div>
{/notempty}
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit>确认</button>
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">重置</button>
</div>
</form>
</div>

View File

@@ -0,0 +1,3 @@
$(function(){
ua.listen();
})

View File

@@ -0,0 +1,9 @@
<div class="layuimini-container">
<div class="layuimini-main">
<table id="currentTable" class="layui-table layui-hide"
data-auth-index="{:auth('xhprof.run_watch/index')}"
data-auth-read="{:auth('xhprof.run_watch/read')}"
lay-filter="currentTable">
</table>
</div>
</div>

View File

@@ -0,0 +1,62 @@
$(function(){
ua.table.render({
init: init,
toolbar: [],
defaultToolbar: ['filter'],
cols: [[
{field: 'id', title: 'ID', width: 80, sort: true},
{field: 'watch_id', title: '监控规则', width: 160, search: 'select', searchOp: '=', selectList: ua.getDataBrage('select_list_watch'), templet: function(d) {
return d.watch && d.watch.name ? d.watch.name : ('#' + d.watch_id);
}},
{field: 'run.url', title: '请求 URL', minWidth: 220, search: false, templet: function(d) {
if (!d.run || !d.run.url) {
return '<span class="layui-text-em">#' + d.run_id + '</span>';
}
var esc = String(d.run.url).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
return '<span title="' + esc + '">' + esc + '</span>';
}},
{field: 'run.request_time', title: '请求时间', width: 170, search: 'range', templet: function(d) {
if (!d.run || !d.run.request_time) {
return '-';
}
var ts = parseFloat(d.run.request_time);
if (isNaN(ts) || ts <= 0) {
return '-';
}
return window.UA_CORE.util.toDateString(ts * 1000, 'yyyy-MM-dd HH:mm:ss');
}},
{field: 'ct', title: '命中次数', width: 100, search: 'number_limit'},
{field: 'wt_sum', title: '耗时合计(ms)', width: 140, search: 'number_limit', templet: function(d) {
var ms = parseFloat(d.wt_sum) / 1000;
var threshold = d.watch ? parseInt(d.watch.threshold_ms, 10) : 0;
var text = (isNaN(ms) ? 0 : ms).toFixed(3) + ' ms';
if (threshold > 0 && ms > threshold) {
return '<span class="layui-badge layui-bg-red">' + text + '(超阈值 ' + threshold + 'ms</span>';
}
return text;
}},
{field: 'wt_max', title: '单次最大(ms)', width: 130, search: 'number_limit', templet: function(d) {
var ms = parseFloat(d.wt_max) / 1000;
return (isNaN(ms) ? 0 : ms).toFixed(3) + ' ms';
}},
{field: 'create_time', title: '入库时间', width: 170, search: false, templet: ua.table.date},
{
width: 100, title: '操作', templet: ua.table.tool, fixed: 'right', operat: [
[{
class: 'layui-btn layui-btn-primary layui-btn-xs',
method: 'tab',
field: 'id',
text: '详情',
title: '查看详情',
auth: 'read',
url: init.readUrl,
icon: ''
}]
]
},
]],
});
ua.listen();
})

View File

@@ -0,0 +1,97 @@
<div class="layuimini-container detail-container">
<div class="layuimini-main">
<div class="layui-card detail-card">
<div class="layui-card-header detail-header">
<div class="layui-row">
<div class="layui-col-md9">
<h2 class="detail-title">#{$row.id} {$title}</h2>
<div class="detail-id">ID: {$row.id}</div>
</div>
<div class="layui-col-md3 text-right detail-actions">
<button class="layui-btn layui-btn-primary" layuimini-content-href="{$Request.param.backTagId}" data-back="1">返回</button>
</div>
</div>
</div>
<div class="layui-card-body detail-content">
<div class="layui-row layui-col-space12">
<!-- 左侧主体内容 -->
<div class="layui-col-md8 detail-main">
<div class="detail-field-group">
<div class="detail-field-item">
<div class="detail-field-label">监控规则</div>
<div class="detail-field-value">
{notempty name="row.watch.name"}
{$row.watch.name}#{$row.watch_id}
{else/}
<span class="layui-text-em">#{$row.watch_id}</span>
{/notempty}
</div>
</div>
<div class="detail-field-item">
<div class="detail-field-label">命中次数(边数和)</div>
<div class="detail-field-value">
{$row.ct}
</div>
</div>
<div class="detail-field-item">
<div class="detail-field-label">耗时合计</div>
<div class="detail-field-value">
{$row.wt_sum} μs = {:number_format($row['wt_sum'] / 1000, 3)} ms
{if condition="$row['watch']['threshold_ms'] > 0 && ($row['wt_sum'] / 1000) > $row['watch']['threshold_ms']"}
<span class="layui-badge layui-bg-red">超阈值 {$row.watch.threshold_ms}ms</span>
{/if}
</div>
</div>
<div class="detail-field-item">
<div class="detail-field-label">单次最大耗时</div>
<div class="detail-field-value">
{$row.wt_max} μs = {:number_format($row['wt_max'] / 1000, 3)} ms
</div>
</div>
</div>
</div>
<!-- 右侧基础信息 -->
<div class="layui-col-md4 detail-side">
<h3 class="detail-side-title">关联采样</h3>
<div class="detail-field-group">
<div class="detail-field-item">
<div class="detail-field-label">采样记录ID</div>
<div class="detail-field-value">#{$row.run_id}</div>
</div>
<div class="detail-field-item">
<div class="detail-field-label">请求 URL</div>
<div class="detail-field-value">
{notempty name="row.run.url"}
{$row.run.url}
{else/}
<span class="layui-text-em">暂无数据</span>
{/notempty}
</div>
</div>
<div class="detail-field-item">
<div class="detail-field-label">请求时间</div>
<div class="detail-field-value">
{notempty name="row.run.request_time"}
{:date('Y-m-d H:i:s', intval($row['run']['request_time']))}
{else/}
<span class="layui-text-em">暂无数据</span>
{/notempty}
</div>
</div>
<div class="detail-field-item">
<div class="detail-field-label">入库时间</div>
<div class="detail-field-value">
{notempty name="row.create_time"}
{$row.create_time|date="Y-m-d H:i:s"}
{else/}
<span class="layui-text-em">暂无数据</span>
{/notempty}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,22 @@
$(function(){
// 删除数据
window.deleteData = function(id) {
layer.confirm('确定要删除这条数据吗?', {
icon: 3,
title: '提示'
}, function(index) {
$.post('{{:url("delete")}}', {id: id}, function(res) {
if (res.code == 0) {
layer.msg('删除成功', {icon: 1}, function() {
location.href = '{{:url("index")}}';
});
} else {
layer.msg(res.msg, {icon: 2});
}
}, 'json');
layer.close(index);
});
};
ua.listen();
})