diff --git a/cmd/edge-api/main.go b/cmd/edge-api/main.go index 55a76ad8..327c4d05 100644 --- a/cmd/edge-api/main.go +++ b/cmd/edge-api/main.go @@ -83,6 +83,20 @@ func main() { } } }) + app.On("debug", func() { + var sock = gosock.NewTmpSock(teaconst.ProcessName) + reply, err := sock.Send(&gosock.Command{Code: "debug"}) + if err != nil { + fmt.Println("[ERROR]" + err.Error()) + } else { + var isDebug = maps.NewMap(reply.Params).GetBool("debug") + if isDebug { + fmt.Println("debug on") + } else { + fmt.Println("debug off") + } + } + }) app.Run(func() { nodes.NewAPINode().Start() }) diff --git a/internal/accesslogs/storage_manager_write.go b/internal/accesslogs/storage_manager_write.go index 1f22f5a3..9710d0a1 100644 --- a/internal/accesslogs/storage_manager_write.go +++ b/internal/accesslogs/storage_manager_write.go @@ -1,7 +1,7 @@ // Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. -//go:build community -// +build community +//go:build !plus +// +build !plus package accesslogs diff --git a/internal/const/build.go b/internal/const/build.go index 71c71807..4afd984b 100644 --- a/internal/const/build.go +++ b/internal/const/build.go @@ -1,5 +1,6 @@ // Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. -// +build community +//go:build !plus +// +build !plus package teaconst diff --git a/internal/const/vars.go b/internal/const/vars.go index bb20feef..91350559 100644 --- a/internal/const/vars.go +++ b/internal/const/vars.go @@ -6,4 +6,5 @@ var ( IsPlus = false MaxNodes int32 = 0 NodeId int64 = 0 + Debug = false ) diff --git a/internal/db/models/api_method_stat_dao.go b/internal/db/models/api_method_stat_dao.go new file mode 100644 index 00000000..7b36e919 --- /dev/null +++ b/internal/db/models/api_method_stat_dao.go @@ -0,0 +1,76 @@ +package models + +import ( + teaconst "github.com/TeaOSLab/EdgeAPI/internal/const" + _ "github.com/go-sql-driver/mysql" + "github.com/iwind/TeaGo/Tea" + "github.com/iwind/TeaGo/dbs" + timeutil "github.com/iwind/TeaGo/utils/time" +) + +type APIMethodStatDAO dbs.DAO + +func NewAPIMethodStatDAO() *APIMethodStatDAO { + return dbs.NewDAO(&APIMethodStatDAO{ + DAOObject: dbs.DAOObject{ + DB: Tea.Env, + Table: "edgeAPIMethodStats", + Model: new(APIMethodStat), + PkName: "id", + }, + }).(*APIMethodStatDAO) +} + +var SharedAPIMethodStatDAO *APIMethodStatDAO + +func init() { + dbs.OnReady(func() { + SharedAPIMethodStatDAO = NewAPIMethodStatDAO() + }) +} + +// CreateStat 记录统计数据 +func (this *APIMethodStatDAO) CreateStat(tx *dbs.Tx, method string, tag string, costMs float64) error { + var day = timeutil.Format("Ymd") + return this.Query(tx). + Param("costMs", costMs). + InsertOrUpdateQuickly(map[string]interface{}{ + "apiNodeId": teaconst.NodeId, + "method": method, + "tag": tag, + "costMs": costMs, + "peekMs": costMs, + "countCalls": 1, + "day": day, + }, map[string]interface{}{ + "costMs": dbs.SQL("(costMs*countCalls+:costMs)/(countCalls+1)"), + "peekMs": dbs.SQL("IF(peekMs>:costMs, peekMs, :costMs)"), + "countCalls": dbs.SQL("countCalls+1"), + }) +} + +// FindAllStatsWithDay 查询当前统计 +func (this *APIMethodStatDAO) FindAllStatsWithDay(tx *dbs.Tx, day string) (result []*APIMethodStat, err error) { + _, err = this.Query(tx). + Attr("day", day). + Slice(&result). + FindAll() + return +} + +// CountAllStatsWithDay 统计当天数量 +func (this *APIMethodStatDAO) CountAllStatsWithDay(tx *dbs.Tx, day string) (int64, error) { + return this.Query(tx). + Attr("day", day). + Count() +} + +// Clean 清理数据 +func (this *APIMethodStatDAO) Clean(tx *dbs.Tx) error { + var day = timeutil.Format("Ymd") + _, err := this.Query(tx). + Param("day", day). + Where("day<:day"). + Delete() + return err +} diff --git a/internal/db/models/api_method_stat_dao_test.go b/internal/db/models/api_method_stat_dao_test.go new file mode 100644 index 00000000..d14a96e6 --- /dev/null +++ b/internal/db/models/api_method_stat_dao_test.go @@ -0,0 +1,19 @@ +package models + +import ( + _ "github.com/go-sql-driver/mysql" + _ "github.com/iwind/TeaGo/bootstrap" + "github.com/iwind/TeaGo/dbs" + "testing" +) + +func TestAPIMethodStatDAO_CreateStat(t *testing.T) { + var dao = NewAPIMethodStatDAO() + var tx *dbs.Tx + + err := dao.CreateStat(tx, "/pb.Hello/World", "tag", 1.123) + if err != nil { + t.Fatal(err) + } + t.Log("ok") +} diff --git a/internal/db/models/api_method_stat_model.go b/internal/db/models/api_method_stat_model.go new file mode 100644 index 00000000..0ecc7ee7 --- /dev/null +++ b/internal/db/models/api_method_stat_model.go @@ -0,0 +1,28 @@ +package models + +// APIMethodStat API方法统计 +type APIMethodStat struct { + Id uint64 `field:"id"` // ID + ApiNodeId uint32 `field:"apiNodeId"` // API节点ID + Method string `field:"method"` // 方法 + Tag string `field:"tag"` // 标签方法 + CostMs float64 `field:"costMs"` // 耗时Ms + PeekMs float64 `field:"peekMs"` // 峰值耗时 + CountCalls uint64 `field:"countCalls"` // 调用次数 + Day string `field:"day"` // 日期 +} + +type APIMethodStatOperator struct { + Id interface{} // ID + ApiNodeId interface{} // API节点ID + Method interface{} // 方法 + Tag interface{} // 标签方法 + CostMs interface{} // 耗时Ms + PeekMs interface{} // 峰值耗时 + CountCalls interface{} // 调用次数 + Day interface{} // 日期 +} + +func NewAPIMethodStatOperator() *APIMethodStatOperator { + return &APIMethodStatOperator{} +} diff --git a/internal/db/models/api_method_stat_model_ext.go b/internal/db/models/api_method_stat_model_ext.go new file mode 100644 index 00000000..2640e7f9 --- /dev/null +++ b/internal/db/models/api_method_stat_model_ext.go @@ -0,0 +1 @@ +package models diff --git a/internal/db/models/api_node_dao.go b/internal/db/models/api_node_dao.go index 98e6b0f6..f52d22ac 100644 --- a/internal/db/models/api_node_dao.go +++ b/internal/db/models/api_node_dao.go @@ -62,7 +62,15 @@ func (this *APINodeDAO) DisableAPINode(tx *dbs.Tx, id int64) error { } // FindEnabledAPINode 查找启用中的条目 -func (this *APINodeDAO) FindEnabledAPINode(tx *dbs.Tx, id int64) (*APINode, error) { +func (this *APINodeDAO) FindEnabledAPINode(tx *dbs.Tx, id int64, cacheMap *utils.CacheMap) (*APINode, error) { + var cacheKey = this.Table + ":FindEnabledAPINode:" + types.String(id) + if cacheMap != nil { + cache, ok := cacheMap.Get(cacheKey) + if ok { + return cache.(*APINode), nil + } + } + result, err := this.Query(tx). Pk(id). Attr("state", APINodeStateEnabled). @@ -70,6 +78,11 @@ func (this *APINodeDAO) FindEnabledAPINode(tx *dbs.Tx, id int64) (*APINode, erro if result == nil { return nil, err } + + if cacheMap != nil { + cacheMap.Put(cacheKey, result) + } + return result.(*APINode), err } diff --git a/internal/db/models/authority/authority_key_dao_community.go b/internal/db/models/authority/authority_key_dao_community.go index d47a1f8a..4c254c2b 100644 --- a/internal/db/models/authority/authority_key_dao_community.go +++ b/internal/db/models/authority/authority_key_dao_community.go @@ -1,6 +1,6 @@ // Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. -//go:build community -// +build community +//go:build !plus +// +build !plus package authority diff --git a/internal/db/models/http_access_log_dao_test.go b/internal/db/models/http_access_log_dao_test.go index a92bd600..4e5c8ef6 100644 --- a/internal/db/models/http_access_log_dao_test.go +++ b/internal/db/models/http_access_log_dao_test.go @@ -53,7 +53,7 @@ func TestHTTPAccessLogDAO_ListAccessLogs(t *testing.T) { t.Fatal(err) } - accessLogs, requestId, hasMore, err := SharedHTTPAccessLogDAO.ListAccessLogs(tx, "", 10, timeutil.Format("Ymd"), 0, false, false, 0, 0, 0, false, 0, "", "", "") + accessLogs, requestId, hasMore, err := SharedHTTPAccessLogDAO.ListAccessLogs(tx, "", 10, timeutil.Format("Ymd"), 0, 0, 0, false, false, 0, 0, 0, false, 0, "", "", "") if err != nil { t.Fatal(err) } @@ -80,7 +80,7 @@ func TestHTTPAccessLogDAO_ListAccessLogs_Page(t *testing.T) { times := 0 // 防止循环次数太多 for { before := time.Now() - accessLogs, requestId, hasMore, err := SharedHTTPAccessLogDAO.ListAccessLogs(tx, lastRequestId, 2, timeutil.Format("Ymd"), 0, false, false, 0, 0, 0, false, 0, "", "", "") + accessLogs, requestId, hasMore, err := SharedHTTPAccessLogDAO.ListAccessLogs(tx, lastRequestId, 2, timeutil.Format("Ymd"), 0, 0, 0, false, false, 0, 0, 0, false, 0, "", "", "") cost := time.Since(before).Seconds() if err != nil { t.Fatal(err) @@ -111,7 +111,7 @@ func TestHTTPAccessLogDAO_ListAccessLogs_Reverse(t *testing.T) { } before := time.Now() - accessLogs, requestId, hasMore, err := SharedHTTPAccessLogDAO.ListAccessLogs(tx, "16023261176446590001000000000000003500000004", 2, timeutil.Format("Ymd"), 0, true, false, 0, 0, 0, false, 0, "", "", "") + accessLogs, requestId, hasMore, err := SharedHTTPAccessLogDAO.ListAccessLogs(tx, "16023261176446590001000000000000003500000004", 2, timeutil.Format("Ymd"), 0, 0, 0, true, false, 0, 0, 0, false, 0, "", "", "") cost := time.Since(before).Seconds() if err != nil { t.Fatal(err) @@ -136,7 +136,7 @@ func TestHTTPAccessLogDAO_ListAccessLogs_Page_NotExists(t *testing.T) { times := 0 // 防止循环次数太多 for { before := time.Now() - accessLogs, requestId, hasMore, err := SharedHTTPAccessLogDAO.ListAccessLogs(tx, lastRequestId, 2, timeutil.Format("Ymd", time.Now().AddDate(0, 0, 1)), 0, false, false, 0, 0, 0, false, 0, "", "", "") + accessLogs, requestId, hasMore, err := SharedHTTPAccessLogDAO.ListAccessLogs(tx, lastRequestId, 2, timeutil.Format("Ymd", time.Now().AddDate(0, 0, 1)), 0, 0, 0, false, false, 0, 0, 0, false, 0, "", "", "") cost := time.Since(before).Seconds() if err != nil { t.Fatal(err) diff --git a/internal/db/models/node_cluster_dao.go b/internal/db/models/node_cluster_dao.go index 4c12db35..ee9b0e73 100644 --- a/internal/db/models/node_cluster_dao.go +++ b/internal/db/models/node_cluster_dao.go @@ -275,7 +275,7 @@ func (this *NodeClusterDAO) FindAllAPINodeAddrsWithCluster(tx *dbs.Tx, clusterId return nil, err } for _, apiNodeId := range apiNodeIds { - apiNode, err := SharedAPINodeDAO.FindEnabledAPINode(tx, apiNodeId) + apiNode, err := SharedAPINodeDAO.FindEnabledAPINode(tx, apiNodeId, nil) if err != nil { return nil, err } diff --git a/internal/nodes/api_node.go b/internal/nodes/api_node.go index 5ec3e6a1..5745e08b 100644 --- a/internal/nodes/api_node.go +++ b/internal/nodes/api_node.go @@ -1,6 +1,7 @@ package nodes import ( + "context" "crypto/tls" "errors" "fmt" @@ -11,6 +12,7 @@ import ( "github.com/TeaOSLab/EdgeAPI/internal/events" "github.com/TeaOSLab/EdgeAPI/internal/goman" "github.com/TeaOSLab/EdgeAPI/internal/remotelogs" + "github.com/TeaOSLab/EdgeAPI/internal/rpc" "github.com/TeaOSLab/EdgeAPI/internal/setup" "github.com/TeaOSLab/EdgeAPI/internal/utils" "github.com/go-yaml/yaml" @@ -214,10 +216,10 @@ func (this *APINode) listenRPC(listener net.Listener, tlsConfig *tls.Config) err var rpcServer *grpc.Server if tlsConfig == nil { remotelogs.Println("API_NODE", "listening GRPC http://"+listener.Addr().String()+" ...") - rpcServer = grpc.NewServer(grpc.MaxRecvMsgSize(128 * 1024 * 1024)) + rpcServer = grpc.NewServer(grpc.MaxRecvMsgSize(128*1024*1024), grpc.UnaryInterceptor(this.unaryInterceptor)) } else { logs.Println("[API_NODE]listening GRPC https://" + listener.Addr().String() + " ...") - rpcServer = grpc.NewServer(grpc.Creds(credentials.NewTLS(tlsConfig)), grpc.MaxRecvMsgSize(128*1024*1024)) + rpcServer = grpc.NewServer(grpc.Creds(credentials.NewTLS(tlsConfig)), grpc.MaxRecvMsgSize(128*1024*1024), grpc.UnaryInterceptor(this.unaryInterceptor)) } this.registerServices(rpcServer) err := rpcServer.Serve(listener) @@ -572,6 +574,11 @@ func (this *APINode) listenSock() error { "result": result, }, }) + case "debug": + teaconst.Debug = !teaconst.Debug + _ = cmd.Reply(&gosock.Command{ + Params: map[string]interface{}{"debug": teaconst.Debug}, + }) } }) @@ -588,3 +595,29 @@ func (this *APINode) listenSock() error { return nil } + +// 服务过滤器 +func (this *APINode) unaryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { + if teaconst.Debug { + var before = time.Now() + var traceCtx = rpc.NewContext(ctx) + resp, err = handler(traceCtx, req) + + var costMs = time.Since(before).Seconds() * 1000 + statErr := models.SharedAPIMethodStatDAO.CreateStat(nil, info.FullMethod, "", costMs) + if statErr != nil { + remotelogs.Error("API_NODE", "create method stat failed: "+statErr.Error()) + } + + var tagMap = traceCtx.TagMap() + for tag, tagCostMs := range tagMap { + statErr = models.SharedAPIMethodStatDAO.CreateStat(nil, info.FullMethod, tag, tagCostMs) + if statErr != nil { + remotelogs.Error("API_NODE", "create method stat failed: "+statErr.Error()) + } + } + + return + } + return handler(ctx, req) +} diff --git a/internal/nodes/api_node_services.go b/internal/nodes/api_node_services.go index ced9c989..54e0cd39 100644 --- a/internal/nodes/api_node_services.go +++ b/internal/nodes/api_node_services.go @@ -63,6 +63,11 @@ func (this *APINode) registerServices(server *grpc.Server) { pb.RegisterAPINodeServiceServer(server, instance) this.rest(instance) } + { + instance := this.serviceInstance(&services.APIMethodStatService{}).(*services.APIMethodStatService) + pb.RegisterAPIMethodStatServiceServer(server, instance) + this.rest(instance) + } { instance := this.serviceInstance(&services.OriginService{}).(*services.OriginService) pb.RegisterOriginServiceServer(server, instance) diff --git a/internal/nodes/api_node_services_hook.go b/internal/nodes/api_node_services_hook.go index 87a40499..46a3e42c 100644 --- a/internal/nodes/api_node_services_hook.go +++ b/internal/nodes/api_node_services_hook.go @@ -1,5 +1,6 @@ // Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. -// +build community +//go:build !plus +// +build !plus package nodes diff --git a/internal/rpc/context.go b/internal/rpc/context.go new file mode 100644 index 00000000..19fe270f --- /dev/null +++ b/internal/rpc/context.go @@ -0,0 +1,46 @@ +// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. + +package rpc + +import ( + "context" + "sync" + "time" +) + +type Context struct { + context.Context + + tagMap map[string]time.Time + costMap map[string]float64 // tag => costMs + locker sync.Mutex +} + +func NewContext(ctx context.Context) *Context { + return &Context{ + Context: ctx, + tagMap: map[string]time.Time{}, + costMap: map[string]float64{}, + } +} + +func (this *Context) Begin(tag string) { + this.locker.Lock() + this.tagMap[tag] = time.Now() + this.locker.Unlock() +} + +func (this *Context) End(tag string) { + this.locker.Lock() + begin, ok := this.tagMap[tag] + if ok { + this.costMap[tag] = time.Since(begin).Seconds() * 1000 + } + this.locker.Unlock() +} + +func (this *Context) TagMap() map[string]float64 { + this.locker.Lock() + defer this.locker.Unlock() + return this.costMap +} diff --git a/internal/rpc/services/service_admin.go b/internal/rpc/services/service_admin.go index b6afe082..2088cb83 100644 --- a/internal/rpc/services/service_admin.go +++ b/internal/rpc/services/service_admin.go @@ -477,7 +477,9 @@ func (this *AdminService) ComposeAdminDashboard(ctx context.Context, req *pb.Com var tx = this.NullTx() // 默认集群 + this.BeginTag(ctx, "SharedNodeClusterDAO.ListEnabledClusters") nodeClusters, err := models.SharedNodeClusterDAO.ListEnabledClusters(tx, "", 0, 1) + this.EndTag(ctx, "SharedNodeClusterDAO.ListEnabledClusters") if err != nil { return nil, err } @@ -486,84 +488,108 @@ func (this *AdminService) ComposeAdminDashboard(ctx context.Context, req *pb.Com } // 集群数 + this.BeginTag(ctx, "SharedNodeClusterDAO.CountAllEnabledClusters") countClusters, err := models.SharedNodeClusterDAO.CountAllEnabledClusters(tx, "") + this.EndTag(ctx, "SharedNodeClusterDAO.CountAllEnabledClusters") if err != nil { return nil, err } result.CountNodeClusters = countClusters // 节点数 + this.BeginTag(ctx, "SharedNodeDAO.CountAllEnabledNodes") countNodes, err := models.SharedNodeDAO.CountAllEnabledNodes(tx) + this.EndTag(ctx, "SharedNodeDAO.CountAllEnabledNodes") if err != nil { return nil, err } result.CountNodes = countNodes // 离线节点 + this.BeginTag(ctx, "SharedNodeDAO.CountAllEnabledOfflineNodes") countOfflineNodes, err := models.SharedNodeDAO.CountAllEnabledOfflineNodes(tx) + this.EndTag(ctx, "SharedNodeDAO.CountAllEnabledOfflineNodes") if err != nil { return nil, err } result.CountOfflineNodes = countOfflineNodes // 服务数 + this.BeginTag(ctx, "SharedServerDAO.CountAllEnabledServers") countServers, err := models.SharedServerDAO.CountAllEnabledServers(tx) + this.EndTag(ctx, "SharedServerDAO.CountAllEnabledServers") if err != nil { return nil, err } result.CountServers = countServers + this.BeginTag(ctx, "SharedServerDAO.CountAllEnabledServersMatch") countAuditingServers, err := models.SharedServerDAO.CountAllEnabledServersMatch(tx, 0, "", 0, 0, configutils.BoolStateYes, nil) + this.EndTag(ctx, "SharedServerDAO.CountAllEnabledServersMatch") if err != nil { return nil, err } result.CountAuditingServers = countAuditingServers // 用户数 + this.BeginTag(ctx, "SharedUserDAO.CountAllEnabledUsers") countUsers, err := models.SharedUserDAO.CountAllEnabledUsers(tx, 0, "", false) + this.EndTag(ctx, "SharedUserDAO.CountAllEnabledUsers") if err != nil { return nil, err } result.CountUsers = countUsers // API节点数 + this.BeginTag(ctx, "SharedAPINodeDAO.CountAllEnabledAndOnAPINodes") countAPINodes, err := models.SharedAPINodeDAO.CountAllEnabledAndOnAPINodes(tx) + this.EndTag(ctx, "SharedAPINodeDAO.CountAllEnabledAndOnAPINodes") if err != nil { return nil, err } result.CountAPINodes = countAPINodes // 离线API节点 + this.BeginTag(ctx, "SharedAPINodeDAO.CountAllEnabledAndOnOfflineAPINodes") countOfflineAPINodes, err := models.SharedAPINodeDAO.CountAllEnabledAndOnOfflineAPINodes(tx) + this.EndTag(ctx, "SharedAPINodeDAO.CountAllEnabledAndOnOfflineAPINodes") if err != nil { return nil, err } result.CountOfflineAPINodes = countOfflineAPINodes // 数据库节点数 + this.BeginTag(ctx, "SharedDBNodeDAO.CountAllEnabledNodes") countDBNodes, err := models.SharedDBNodeDAO.CountAllEnabledNodes(tx) + this.EndTag(ctx, "SharedDBNodeDAO.CountAllEnabledNodes") if err != nil { return nil, err } result.CountDBNodes = countDBNodes // 用户节点数 + this.BeginTag(ctx, "SharedUserNodeDAO.CountAllEnabledAndOnUserNodes") countUserNodes, err := models.SharedUserNodeDAO.CountAllEnabledAndOnUserNodes(tx) + this.EndTag(ctx, "SharedUserNodeDAO.CountAllEnabledAndOnUserNodes") if err != nil { return nil, err } result.CountUserNodes = countUserNodes // 离线用户节点数 + this.BeginTag(ctx, "SharedUserNodeDAO.CountAllEnabledAndOnOfflineNodes") countOfflineUserNodes, err := models.SharedUserNodeDAO.CountAllEnabledAndOnOfflineNodes(tx) + this.EndTag(ctx, "SharedUserNodeDAO.CountAllEnabledAndOnOfflineNodes") if err != nil { return nil, err } result.CountOfflineUserNodes = countOfflineUserNodes // 按日流量统计 + this.BeginTag(ctx, "SharedTrafficDailyStatDAO.FindDailyStats") dayFrom := timeutil.Format("Ymd", time.Now().AddDate(0, 0, -14)) dailyTrafficStats, err := stats.SharedTrafficDailyStatDAO.FindDailyStats(tx, dayFrom, timeutil.Format("Ymd")) + this.EndTag(ctx, "SharedTrafficDailyStatDAO.FindDailyStats") if err != nil { return nil, err } @@ -582,7 +608,9 @@ func (this *AdminService) ComposeAdminDashboard(ctx context.Context, req *pb.Com // 小时流量统计 hourFrom := timeutil.Format("YmdH", time.Now().Add(-23*time.Hour)) hourTo := timeutil.Format("YmdH") + this.BeginTag(ctx, "SharedTrafficHourlyStatDAO.FindHourlyStats") hourlyTrafficStats, err := stats.SharedTrafficHourlyStatDAO.FindHourlyStats(tx, hourFrom, hourTo) + this.EndTag(ctx, "SharedTrafficHourlyStatDAO.FindHourlyStats") if err != nil { return nil, err } @@ -609,7 +637,9 @@ func (this *AdminService) ComposeAdminDashboard(ctx context.Context, req *pb.Com upgradeInfo := &pb.ComposeAdminDashboardResponse_UpgradeInfo{ NewVersion: teaconst.NodeVersion, } + this.BeginTag(ctx, "SharedNodeDAO.CountAllLowerVersionNodes") countNodes, err := models.SharedNodeDAO.CountAllLowerVersionNodes(tx, upgradeInfo.NewVersion) + this.EndTag(ctx, "SharedNodeDAO.CountAllLowerVersionNodes") if err != nil { return nil, err } @@ -622,7 +652,9 @@ func (this *AdminService) ComposeAdminDashboard(ctx context.Context, req *pb.Com upgradeInfo := &pb.ComposeAdminDashboardResponse_UpgradeInfo{ NewVersion: teaconst.MonitorNodeVersion, } + this.BeginTag(ctx, "SharedMonitorNodeDAO.CountAllLowerVersionNodes") countNodes, err := models.SharedMonitorNodeDAO.CountAllLowerVersionNodes(tx, upgradeInfo.NewVersion) + this.EndTag(ctx, "SharedMonitorNodeDAO.CountAllLowerVersionNodes") if err != nil { return nil, err } @@ -635,7 +667,9 @@ func (this *AdminService) ComposeAdminDashboard(ctx context.Context, req *pb.Com upgradeInfo := &pb.ComposeAdminDashboardResponse_UpgradeInfo{ NewVersion: teaconst.AuthorityNodeVersion, } + this.BeginTag(ctx, "SharedAuthorityNodeDAO.CountAllLowerVersionNodes") countNodes, err := authority.SharedAuthorityNodeDAO.CountAllLowerVersionNodes(tx, upgradeInfo.NewVersion) + this.EndTag(ctx, "SharedAuthorityNodeDAO.CountAllLowerVersionNodes") if err != nil { return nil, err } @@ -648,7 +682,9 @@ func (this *AdminService) ComposeAdminDashboard(ctx context.Context, req *pb.Com upgradeInfo := &pb.ComposeAdminDashboardResponse_UpgradeInfo{ NewVersion: teaconst.UserNodeVersion, } + this.BeginTag(ctx, "SharedUserNodeDAO.CountAllLowerVersionNodes") countNodes, err := models.SharedUserNodeDAO.CountAllLowerVersionNodes(tx, upgradeInfo.NewVersion) + this.EndTag(ctx, "SharedUserNodeDAO.CountAllLowerVersionNodes") if err != nil { return nil, err } @@ -665,7 +701,9 @@ func (this *AdminService) ComposeAdminDashboard(ctx context.Context, req *pb.Com upgradeInfo := &pb.ComposeAdminDashboardResponse_UpgradeInfo{ NewVersion: apiVersion, } + this.BeginTag(ctx, "SharedAPINodeDAO.CountAllLowerVersionNodes") countNodes, err := models.SharedAPINodeDAO.CountAllLowerVersionNodes(tx, upgradeInfo.NewVersion) + this.EndTag(ctx, "SharedAPINodeDAO.CountAllLowerVersionNodes") if err != nil { return nil, err } @@ -678,7 +716,9 @@ func (this *AdminService) ComposeAdminDashboard(ctx context.Context, req *pb.Com upgradeInfo := &pb.ComposeAdminDashboardResponse_UpgradeInfo{ NewVersion: teaconst.DNSNodeVersion, } + this.BeginTag(ctx, "SharedNSNodeDAO.CountAllLowerVersionNodes") countNodes, err := models.SharedNSNodeDAO.CountAllLowerVersionNodes(tx, upgradeInfo.NewVersion) + this.EndTag(ctx, "SharedNSNodeDAO.CountAllLowerVersionNodes") if err != nil { return nil, err } @@ -691,7 +731,9 @@ func (this *AdminService) ComposeAdminDashboard(ctx context.Context, req *pb.Com upgradeInfo := &pb.ComposeAdminDashboardResponse_UpgradeInfo{ NewVersion: teaconst.ReportNodeVersion, } + this.BeginTag(ctx, "SharedReportNodeDAO.CountAllLowerVersionNodes") countNodes, err := models.SharedReportNodeDAO.CountAllLowerVersionNodes(tx, upgradeInfo.NewVersion) + this.EndTag(ctx, "SharedReportNodeDAO.CountAllLowerVersionNodes") if err != nil { return nil, err } @@ -700,7 +742,9 @@ func (this *AdminService) ComposeAdminDashboard(ctx context.Context, req *pb.Com } // 域名排行 + this.BeginTag(ctx, "SharedServerDomainHourlyStatDAO.FindTopDomainStats") topDomainStats, err := stats.SharedServerDomainHourlyStatDAO.FindTopDomainStats(tx, hourFrom, hourTo, 10) + this.EndTag(ctx, "SharedServerDomainHourlyStatDAO.FindTopDomainStats") if err != nil { return nil, err } @@ -715,7 +759,9 @@ func (this *AdminService) ComposeAdminDashboard(ctx context.Context, req *pb.Com // 节点排行 if isPlus { + this.BeginTag(ctx, "SharedNodeTrafficHourlyStatDAO.FindTopNodeStats") topNodeStats, err := stats.SharedNodeTrafficHourlyStatDAO.FindTopNodeStats(tx, "node", hourFrom, hourTo, 10) + this.EndTag(ctx, "SharedNodeTrafficHourlyStatDAO.FindTopNodeStats") if err != nil { return nil, err } @@ -738,7 +784,9 @@ func (this *AdminService) ComposeAdminDashboard(ctx context.Context, req *pb.Com // 地区流量排行 if isPlus { + this.BeginTag(ctx, "SharedServerRegionCountryDailyStatDAO.SumDailyTotalBytes") totalCountryBytes, err := stats.SharedServerRegionCountryDailyStatDAO.SumDailyTotalBytes(tx, timeutil.Format("Ymd")) + this.EndTag(ctx, "SharedServerRegionCountryDailyStatDAO.SumDailyTotalBytes") if err != nil { return nil, err } @@ -767,7 +815,9 @@ func (this *AdminService) ComposeAdminDashboard(ctx context.Context, req *pb.Com } // 指标数据 + this.BeginTag(ctx, "findMetricDataCharts") pbCharts, err := this.findMetricDataCharts(tx) + this.EndTag(ctx, "findMetricDataCharts") if err != nil { return nil, err } diff --git a/internal/rpc/services/service_api_method_stat.go b/internal/rpc/services/service_api_method_stat.go new file mode 100644 index 00000000..7862a72a --- /dev/null +++ b/internal/rpc/services/service_api_method_stat.go @@ -0,0 +1,83 @@ +// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. + +package services + +import ( + "context" + "github.com/TeaOSLab/EdgeAPI/internal/db/models" + "github.com/TeaOSLab/EdgeAPI/internal/utils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + timeutil "github.com/iwind/TeaGo/utils/time" +) + +// APIMethodStatService API方法统计服务 +type APIMethodStatService struct { + BaseService +} + +// FindAPIMethodStatsWithDay 查找某天的统计 +func (this *APIMethodStatService) FindAPIMethodStatsWithDay(ctx context.Context, req *pb.FindAPIMethodStatsWithDayRequest) (*pb.FindAPIMethodStatsWithDayResponse, error) { + _, err := this.ValidateAdmin(ctx, 0) + if err != nil { + return nil, err + } + + var day = req.Day + if len(day) == 0 { + day = timeutil.Format("Ymd") + } + var tx = this.NullTx() + stats, err := models.SharedAPIMethodStatDAO.FindAllStatsWithDay(tx, day) + if err != nil { + return nil, err + } + var pbStats = []*pb.APIMethodStat{} + var cacheMap = utils.NewCacheMap() + for _, stat := range stats { + apiNode, err := models.SharedAPINodeDAO.FindEnabledAPINode(tx, int64(stat.ApiNodeId), cacheMap) + if err != nil { + return nil, err + } + if apiNode == nil { + continue + } + + pbStats = append(pbStats, &pb.APIMethodStat{ + Id: int64(stat.Id), + ApiNodeId: int64(stat.ApiNodeId), + Method: stat.Method, + Tag: stat.Tag, + CostMs: float32(stat.CostMs), + PeekMs: float32(stat.PeekMs), + CountCalls: int64(stat.CountCalls), + ApiNode: &pb.APINode{ + Id: int64(apiNode.Id), + Name: apiNode.Name, + }, + }) + } + + return &pb.FindAPIMethodStatsWithDayResponse{ + ApiMethodStats: pbStats, + }, nil +} + +// CountAPIMethodStatsWithDay 检查是否有统计数据 +func (this *APIMethodStatService) CountAPIMethodStatsWithDay(ctx context.Context, req *pb.CountAPIMethodStatsWithDayRequest) (*pb.RPCCountResponse, error) { + _, err := this.ValidateAdmin(ctx, 0) + if err != nil { + return nil, err + } + + var day = req.Day + if len(day) == 0 { + day = timeutil.Format("Ymd") + } + + var tx = this.NullTx() + count, err := models.SharedAPIMethodStatDAO.CountAllStatsWithDay(tx, day) + if err != nil { + return nil, err + } + return this.SuccessCount(count) +} diff --git a/internal/rpc/services/service_api_node.go b/internal/rpc/services/service_api_node.go index da2421d4..c7beb309 100644 --- a/internal/rpc/services/service_api_node.go +++ b/internal/rpc/services/service_api_node.go @@ -189,7 +189,7 @@ func (this *APINodeService) FindEnabledAPINode(ctx context.Context, req *pb.Find tx := this.NullTx() - node, err := models.SharedAPINodeDAO.FindEnabledAPINode(tx, req.ApiNodeId) + node, err := models.SharedAPINodeDAO.FindEnabledAPINode(tx, req.ApiNodeId, nil) if err != nil { return nil, err } @@ -241,7 +241,7 @@ func (this *APINodeService) FindCurrentAPINode(ctx context.Context, req *pb.Find var nodeId = teaconst.NodeId var tx *dbs.Tx - node, err := models.SharedAPINodeDAO.FindEnabledAPINode(tx, nodeId) + node, err := models.SharedAPINodeDAO.FindEnabledAPINode(tx, nodeId, nil) if err != nil { return nil, err } @@ -295,3 +295,14 @@ func (this *APINodeService) CountAllEnabledAPINodesWithSSLCertId(ctx context.Con } return this.SuccessCount(count) } + +// DebugAPINode 修改调试模式状态 +func (this *APINodeService) DebugAPINode(ctx context.Context, req *pb.DebugAPINodeRequest) (*pb.RPCSuccess, error) { + _, err := this.ValidateAdmin(ctx, 0) + if err != nil { + return nil, err + } + + teaconst.Debug = req.Debug + return this.Success() +} diff --git a/internal/rpc/services/service_base.go b/internal/rpc/services/service_base.go index ad07b72f..6bb54d4e 100644 --- a/internal/rpc/services/service_base.go +++ b/internal/rpc/services/service_base.go @@ -9,6 +9,7 @@ import ( "github.com/TeaOSLab/EdgeAPI/internal/db/models/authority" "github.com/TeaOSLab/EdgeAPI/internal/encrypt" "github.com/TeaOSLab/EdgeAPI/internal/errors" + "github.com/TeaOSLab/EdgeAPI/internal/rpc" rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils" "github.com/TeaOSLab/EdgeAPI/internal/utils" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" @@ -236,3 +237,25 @@ func (this *BaseService) RunTx(callback func(tx *dbs.Tx) error) error { } return db.RunTx(callback) } + +// BeginTag 开始标签统计 +func (this *BaseService) BeginTag(ctx context.Context, name string) { + if !teaconst.Debug { + return + } + traceCtx, ok := ctx.(*rpc.Context) + if ok { + traceCtx.Begin(name) + } +} + +// EndTag 结束标签统计 +func (this *BaseService) EndTag(ctx context.Context, name string) { + if !teaconst.Debug { + return + } + traceCtx, ok := ctx.(*rpc.Context) + if ok { + traceCtx.End(name) + } +} diff --git a/internal/rpc/services/service_node_cluster.go b/internal/rpc/services/service_node_cluster.go index 4e2fd70b..88c74233 100644 --- a/internal/rpc/services/service_node_cluster.go +++ b/internal/rpc/services/service_node_cluster.go @@ -197,7 +197,7 @@ func (this *NodeClusterService) FindAPINodesWithNodeCluster(ctx context.Context, if len(apiNodeIds) > 0 { apiNodes := []*pb.APINode{} for _, apiNodeId := range apiNodeIds { - apiNode, err := models.SharedAPINodeDAO.FindEnabledAPINode(tx, apiNodeId) + apiNode, err := models.SharedAPINodeDAO.FindEnabledAPINode(tx, apiNodeId, nil) if err != nil { return nil, err } diff --git a/internal/rpc/services/service_plan_community.go b/internal/rpc/services/service_plan_community.go index f3c43fdb..a00e2fbb 100644 --- a/internal/rpc/services/service_plan_community.go +++ b/internal/rpc/services/service_plan_community.go @@ -1,6 +1,6 @@ // Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. -//go:build community -// +build community +//go:build !plus +// +build !plus package services diff --git a/internal/rpc/services/service_user_plan_community.go b/internal/rpc/services/service_user_plan_community.go index cb2bfe23..c8df2502 100644 --- a/internal/rpc/services/service_user_plan_community.go +++ b/internal/rpc/services/service_user_plan_community.go @@ -1,6 +1,6 @@ // Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. -//go:build community -// +build community +//go:build !plus +// +build !plus package services diff --git a/internal/setup/setup.go b/internal/setup/setup.go index a0c4d968..8677eb62 100644 --- a/internal/setup/setup.go +++ b/internal/setup/setup.go @@ -167,7 +167,7 @@ func (this *Setup) Run() error { apiNodeId = nodeId } - apiNode, err := dao.FindEnabledAPINode(nil, apiNodeId) + apiNode, err := dao.FindEnabledAPINode(nil, apiNodeId, nil) if err != nil { return err }