mirror of
https://github.com/TeaOSLab/EdgeAdmin.git
synced 2025-11-10 17:30:29 +08:00
增加API方法调用耗时统计
This commit is contained in:
@@ -161,6 +161,10 @@ func (this *RPCClient) APINodeRPC() pb.APINodeServiceClient {
|
|||||||
return pb.NewAPINodeServiceClient(this.pickConn())
|
return pb.NewAPINodeServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *RPCClient) APIMethodStatRPC() pb.APIMethodStatServiceClient {
|
||||||
|
return pb.NewAPIMethodStatServiceClient(this.pickConn())
|
||||||
|
}
|
||||||
|
|
||||||
func (this *RPCClient) UserNodeRPC() pb.UserNodeServiceClient {
|
func (this *RPCClient) UserNodeRPC() pb.UserNodeServiceClient {
|
||||||
return pb.NewUserNodeServiceClient(this.pickConn())
|
return pb.NewUserNodeServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/iwind/TeaGo/logs"
|
"github.com/iwind/TeaGo/logs"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -26,11 +27,11 @@ func (this *IndexAction) RunGet(params struct{}) {
|
|||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
count := countResp.Count
|
var count = countResp.Count
|
||||||
page := this.NewPage(count)
|
var page = this.NewPage(count)
|
||||||
this.Data["page"] = page.AsHTML()
|
this.Data["page"] = page.AsHTML()
|
||||||
|
|
||||||
nodeMaps := []maps.Map{}
|
var nodeMaps = []maps.Map{}
|
||||||
if count > 0 {
|
if count > 0 {
|
||||||
nodesResp, err := this.RPC().APINodeRPC().ListEnabledAPINodes(this.AdminContext(), &pb.ListEnabledAPINodesRequest{
|
nodesResp, err := this.RPC().APINodeRPC().ListEnabledAPINodes(this.AdminContext(), &pb.ListEnabledAPINodesRequest{
|
||||||
Offset: page.Offset,
|
Offset: page.Offset,
|
||||||
@@ -106,5 +107,13 @@ func (this *IndexAction) RunGet(params struct{}) {
|
|||||||
}
|
}
|
||||||
this.Data["nodes"] = nodeMaps
|
this.Data["nodes"] = nodeMaps
|
||||||
|
|
||||||
|
// 检查是否有调试数据
|
||||||
|
countMethodStatsResp, err := this.RPC().APIMethodStatRPC().CountAPIMethodStatsWithDay(this.AdminContext(), &pb.CountAPIMethodStatsWithDayRequest{Day: timeutil.Format("Ymd")})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.Data["hasMethodStats"] = countMethodStatsResp.Count > 0
|
||||||
|
|
||||||
this.Show()
|
this.Show()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ func init() {
|
|||||||
Helper(settingutils.NewAdvancedHelper("apiNodes")).
|
Helper(settingutils.NewAdvancedHelper("apiNodes")).
|
||||||
Prefix("/api").
|
Prefix("/api").
|
||||||
Get("", new(IndexAction)).
|
Get("", new(IndexAction)).
|
||||||
|
Get("/methodStats", new(MethodStatsAction)).
|
||||||
GetPost("/node/createPopup", new(node.CreatePopupAction)).
|
GetPost("/node/createPopup", new(node.CreatePopupAction)).
|
||||||
Post("/delete", new(DeleteAction)).
|
Post("/delete", new(DeleteAction)).
|
||||||
EndAll()
|
EndAll()
|
||||||
|
|||||||
78
internal/web/actions/default/api/methodStats.go
Normal file
78
internal/web/actions/default/api/methodStats.go
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MethodStatsAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *MethodStatsAction) Init() {
|
||||||
|
this.Nav("", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *MethodStatsAction) RunGet(params struct {
|
||||||
|
Order string
|
||||||
|
Method string
|
||||||
|
Tag string
|
||||||
|
}) {
|
||||||
|
this.Data["order"] = params.Order
|
||||||
|
this.Data["method"] = params.Method
|
||||||
|
this.Data["tag"] = params.Tag
|
||||||
|
|
||||||
|
statsResp, err := this.RPC().APIMethodStatRPC().FindAPIMethodStatsWithDay(this.AdminContext(), &pb.FindAPIMethodStatsWithDayRequest{Day: timeutil.Format("Ymd")})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var pbStats = statsResp.ApiMethodStats
|
||||||
|
|
||||||
|
switch params.Order {
|
||||||
|
case "method":
|
||||||
|
sort.Slice(pbStats, func(i, j int) bool {
|
||||||
|
return pbStats[i].Method < pbStats[j].Method
|
||||||
|
})
|
||||||
|
case "costMs.desc":
|
||||||
|
sort.Slice(pbStats, func(i, j int) bool {
|
||||||
|
return pbStats[i].CostMs > pbStats[j].CostMs
|
||||||
|
})
|
||||||
|
case "peekMs.desc":
|
||||||
|
sort.Slice(pbStats, func(i, j int) bool {
|
||||||
|
return pbStats[i].PeekMs > pbStats[j].PeekMs
|
||||||
|
})
|
||||||
|
case "calls.desc":
|
||||||
|
sort.Slice(pbStats, func(i, j int) bool {
|
||||||
|
return pbStats[i].CountCalls > pbStats[j].CountCalls
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var statMaps = []maps.Map{}
|
||||||
|
for _, stat := range pbStats {
|
||||||
|
if len(params.Method) > 0 && !strings.Contains(strings.ToLower(stat.Method), strings.ToLower(params.Method)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(params.Tag) > 0 && !strings.Contains(strings.ToLower(stat.Tag), strings.ToLower(params.Tag)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
statMaps = append(statMaps, maps.Map{
|
||||||
|
"id": stat.Id,
|
||||||
|
"method": stat.Method,
|
||||||
|
"tag": stat.Tag,
|
||||||
|
"costMs": stat.CostMs,
|
||||||
|
"peekMs": stat.PeekMs,
|
||||||
|
"countCalls": stat.CountCalls,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["stats"] = statMaps
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
<first-menu>
|
<first-menu>
|
||||||
<a href="" class="item" @click.prevent="createNode()">[添加节点]</a>
|
<a href="" class="item" @click.prevent="createNode()">[添加节点]</a>
|
||||||
|
<a href="/api/methodStats" class="item" v-if="hasMethodStats">用时统计</a>
|
||||||
</first-menu>
|
</first-menu>
|
||||||
|
|
||||||
<p class="comment" v-if="nodes.length == 0">暂时还没有节点。</p>
|
<p class="comment" v-if="nodes.length == 0">暂时还没有节点。</p>
|
||||||
|
|||||||
46
web/views/@default/api/methodStats.html
Normal file
46
web/views/@default/api/methodStats.html
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
{$layout}
|
||||||
|
|
||||||
|
<div class="margin"></div>
|
||||||
|
<form method="get" action="/api/methodStats" class="ui form">
|
||||||
|
<div class="ui fields inline">
|
||||||
|
<div class="ui field">
|
||||||
|
<input type="text" name="method" v-model="method" placeholder="方法"/>
|
||||||
|
</div>
|
||||||
|
<div class="ui field">
|
||||||
|
<input type="text" name="tag" v-model="tag" placeholder="标签"/>
|
||||||
|
</div>
|
||||||
|
<div class="ui field">
|
||||||
|
<select class="ui dropdown auto-width" name="order" v-model="order">
|
||||||
|
<option value="">[排序]</option>
|
||||||
|
<option value="method">方法</option>
|
||||||
|
<option value="costMs.desc">平均耗时</option>
|
||||||
|
<option value="peekMs.desc">峰值耗时</option>
|
||||||
|
<option value="calls.desc">调用次数</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="ui field">
|
||||||
|
<button class="ui button" type="submit">搜索</button>
|
||||||
|
|
||||||
|
<a href="/api/methodStats" v-if="method.length > 0 || tag.length > 0 || order.length > 0">清除条件</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<table class="ui table selectable celled">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>方法</th>
|
||||||
|
<th>标签</th>
|
||||||
|
<th>平均耗时</th>
|
||||||
|
<th>峰值耗时</th>
|
||||||
|
<td>调用次数</td>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr v-for="stat in stats">
|
||||||
|
<td>{{stat.method}}</td>
|
||||||
|
<td>{{stat.tag}}</td>
|
||||||
|
<td>{{stat.costMs}}ms</td>
|
||||||
|
<td>{{stat.peekMs}}ms</td>
|
||||||
|
<td>{{stat.countCalls}}次</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
Reference in New Issue
Block a user