diff --git a/.gitignore b/.gitignore index 73043de..7730c7e 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ go.work *.o *.a *.so +*.db # OS General Thumbs.db diff --git a/README.ZH.md b/README.ZH.md index 785c672..9ee232b 100644 --- a/README.ZH.md +++ b/README.ZH.md @@ -39,13 +39,13 @@ 1. 从 [GitHub Releases](https://github.com/toheart/goanalysis/releases) 下载 2. 解压并运行: ```bash - # Linux + # Linux - 使用默认配置启动 ./goanalysis-linux-v* server - # Windows + # Windows - 使用默认配置启动 goanalysis-windows-v*.exe server ``` -3. 打开 http://localhost:8000 +3. 打开 http://localhost:8001 ### 从源码构建 @@ -60,117 +60,147 @@ make build ## ⚙️ 配置说明 -编辑 `configs/config.yaml`: +### 🎯 推荐方式:命令行参数(无需配置文件) -```yaml -server: - http: - addr: 0.0.0.0:8000 - grpc: - addr: 0.0.0.0:9000 +GoAnalysis 现在支持通过命令行参数直接配置,无需创建配置文件: -data: - dbpath: ./goanalysis.db +```bash +# 使用默认配置启动 +./goanalysis server -biz: - gitlab: - token: "${GITLAB_TOKEN}" - url: "${GITLAB_API_URL}" -``` +# 自定义端口和日志级别 +./goanalysis server --http-addr=0.0.0.0:8080 --log-level=info -## 📡 API接口 +# 自定义数据库路径 +./goanalysis server --db-path=./my-database.db -| 接口地址 | 方法 | 描述 | -|----------|------|------| -| `/api/gids` | GET | 获取goroutine ID | -| `/api/functions` | GET | 列出追踪函数 | -| `/api/traces/{gid}` | GET | 获取追踪详情 | -| `/api/traces/{gid}/mermaid` | GET | 获取图表数据 | +# 设置GitLab配置 +./goanalysis server --gitlab-token="your-token" --gitlab-url="https://gitlab.com/api/v4" +``` -## 🔧 使用方法 +### 📋 所有可用参数 -### 基础追踪 ```bash -./goanalysis server -./goanalysis rewrite -d /path/to/project +# 查看所有可用参数 +./goanalysis server --help ``` -### Git分析 -```bash -export GITLAB_TOKEN="your-token" -./goanalysis gitanalysis --project=123 --mr=45 -``` +**服务器配置:** +- `--http-addr` - HTTP服务地址 (默认: 0.0.0.0:8001) +- `--grpc-addr` - gRPC服务地址 (默认: 0.0.0.0:9000) +- `--http-timeout` - HTTP超时时间 (默认: 1s) +- `--grpc-timeout` - gRPC超时时间 (默认: 1s) -## 📂 项目结构 +**日志配置:** +- `--log-level` - 日志级别 (默认: debug) +- `--log-file` - 日志文件路径 (默认: ./logs/app.log) +- `--log-console` - 是否输出到控制台 (默认: true) -``` -├── api/ # API定义 -├── cmd/ # CLI命令 -├── internal/ # 核心逻辑 -├── web/ # 前端文件 -└── configs/ # 配置文件 -``` +**GitLab配置:** +- `--gitlab-token` - GitLab访问令牌 +- `--gitlab-url` - GitLab API地址 +- `--gitlab-clone-dir` - 克隆目录 (默认: ./data) + +**OpenAI配置:** +- `--openai-api-key` - OpenAI API密钥 +- `--openai-api-base` - OpenAI API地址 +- `--openai-model` - OpenAI模型名称 + +**存储路径:** +- `--static-store-path` - 静态存储路径 (默认: ./data/static) +- `--runtime-store-path` - 运行时存储路径 (默认: ./data/runtime) +- `--file-storage-path` - 文件存储路径 (默认: ./data/files) -## 🏗️ 部署 +**数据配置:** +- `--db-path` - 数据库路径 (默认: ./goanalysis.db) + +### 🔐 环境变量支持 + +敏感信息也可以通过环境变量设置: -### Docker ```bash -docker run -p 8000:8000 -p 9000:9000 \ - ghcr.io/toheart/goanalysis:latest +export GITLAB_TOKEN="your-gitlab-token" +export GITLAB_API_URL="https://gitlab.com/api/v4" +export OPENAI_API_KEY="your-openai-key" +export OPENAI_API_BASE="https://api.openai.com/v1" +export OPENAI_MODEL="gpt-3.5-turbo" + +./goanalysis server ``` -### 构建 +### 📄 传统方式:配置文件 + +仍然支持传统的配置文件方式: + ```bash -make package-linux -make package-windows +# 生成默认配置文件 +./goanalysis config + +# 使用配置文件启动 +./goanalysis server --conf=configs/config.yaml ``` -## 🔧 故障排除 +配置文件示例: + +```yaml +server: + http: + addr: 0.0.0.0:8001 + grpc: + addr: 0.0.0.0:9000 + +logger: + level: debug + file_path: ./logs/app.log + console: true -| 问题 | 解决方案 | -|------|----------| -| 端口被占用 | `lsof -i :8000; kill -9 ` | -| 数据库锁定 | `rm -f goanalysis.db-*` | -| 前端缺失 | `make sync-frontend` | +biz: + gitlab: + token: "${GITLAB_TOKEN}" + url: "${GITLAB_API_URL}" + clone_dir: ./data + openai: + api_key: "${OPENAI_API_KEY}" + api_base: "${OPENAI_API_BASE}" + model: "${OPENAI_MODEL}" -## 🤝 贡献指南 +data: + dbpath: ./goanalysis.db +``` -1. Fork仓库 -2. 创建功能分支 -3. 提交更改和测试 -4. 提交Pull Request +### 🔄 配置优先级 -遵循 [约定式提交](https://www.conventionalcommits.org/zh-hans/)。 +配置优先级从高到低: +1. **命令行参数** - 最高优先级 +2. **环境变量** - 用于敏感信息 +3. **配置文件** - 传统方式 +4. **默认值** - 最低优先级 -## 📜 版本历史 -| 版本 | 日期 | 变更 | -|------|------|------| -| v1.1.4 | 2024-12-16 | GitLab集成 | -| v1.1.0 | 2024-12-01 | Vue3升级 | -| v1.0.0 | 2024-11-15 | 首个稳定版 | +## 🔧 使用方法 -## 📄 许可证 +### 基础追踪 +```bash +# 使用默认配置启动 +./goanalysis server -MIT许可证 - 查看 [LICENSE](LICENSE) 文件。 +# 自定义配置启动 +./goanalysis server --http-addr=0.0.0.0:8080 --log-level=info -## 📞 支持 +# 代码重写 +./goanalysis rewrite -d /path/to/project +``` -- **🐛 问题**: [GitHub Issues](https://github.com/toheart/goanalysis/issues) -- **💬 讨论**: [GitHub Discussions](https://github.com/toheart/goanalysis/discussions) -- **📖 文档**: [Wiki](https://github.com/toheart/goanalysis/wiki) -- **📱 微信**: 关注"小唐的技术日志"获取更新 +### Git分析 +```bash +# 设置GitLab配置 +export GITLAB_TOKEN="your-token" +export GITLAB_API_URL="https://gitlab.com/api/v4" -
-

📱 关注微信公众号

-

小唐的技术日志

- 微信公众号二维码 -

扫描获取最新资讯

-
+# 启动服务 +./goanalysis server +``` ---- +## 📂 项目结构 -
-

GoAnalysis - 为Go开发者赋能

-

⭐ 在GitHub上给我们一个Star!

-
\ No newline at end of file +``` \ No newline at end of file diff --git a/README.md b/README.md index 4908971..74b6450 100644 --- a/README.md +++ b/README.md @@ -39,13 +39,13 @@ Professional Go function tracing analysis tool with advanced visualization. Buil 1. Download from [GitHub Releases](https://github.com/toheart/goanalysis/releases) 2. Extract and run: ```bash - # Linux + # Linux - Start with default configuration ./goanalysis-linux-v* server - # Windows + # Windows - Start with default configuration goanalysis-windows-v*.exe server ``` -3. Open http://localhost:8000 +3. Open http://localhost:8001 ### Building from Source @@ -60,45 +60,146 @@ make build ## ⚙️ Configuration -Edit `configs/config.yaml`: +### 🎯 Recommended: Command Line Arguments (No Config File Required) + +GoAnalysis now supports direct configuration via command line arguments without creating config files: + +```bash +# Start with default configuration +./goanalysis server + +# Customize port and log level +./goanalysis server --http-addr=0.0.0.0:8080 --log-level=info + +# Customize database path +./goanalysis server --db-path=./my-database.db + +# Set GitLab configuration +./goanalysis server --gitlab-token="your-token" --gitlab-url="https://gitlab.com/api/v4" +``` + +### 📋 All Available Parameters + +```bash +# View all available parameters +./goanalysis server --help +``` + +**Server Configuration:** +- `--http-addr` - HTTP server address (default: 0.0.0.0:8001) +- `--grpc-addr` - gRPC server address (default: 0.0.0.0:9000) +- `--http-timeout` - HTTP timeout (default: 1s) +- `--grpc-timeout` - gRPC timeout (default: 1s) + +**Logging Configuration:** +- `--log-level` - Log level (default: debug) +- `--log-file` - Log file path (default: ./logs/app.log) +- `--log-console` - Output to console (default: true) + +**GitLab Configuration:** +- `--gitlab-token` - GitLab access token +- `--gitlab-url` - GitLab API URL +- `--gitlab-clone-dir` - Clone directory (default: ./data) + +**OpenAI Configuration:** +- `--openai-api-key` - OpenAI API key +- `--openai-api-base` - OpenAI API base URL +- `--openai-model` - OpenAI model name + +**Storage Paths:** +- `--static-store-path` - Static storage path (default: ./data/static) +- `--runtime-store-path` - Runtime storage path (default: ./data/runtime) +- `--file-storage-path` - File storage path (default: ./data/files) + +**Data Configuration:** +- `--db-path` - Database path (default: ./goanalysis.db) + +### 🔐 Environment Variables Support + +Sensitive information can also be set via environment variables: + +```bash +export GITLAB_TOKEN="your-gitlab-token" +export GITLAB_API_URL="https://gitlab.com/api/v4" +export OPENAI_API_KEY="your-openai-key" +export OPENAI_API_BASE="https://api.openai.com/v1" +export OPENAI_MODEL="gpt-3.5-turbo" + +./goanalysis server +``` + +### 📄 Traditional: Configuration File + +Still supports traditional configuration file approach: + +```bash +# Generate default configuration file +./goanalysis config + +# Start with configuration file +./goanalysis server --conf=configs/config.yaml +``` + +Configuration file example: ```yaml server: http: - addr: 0.0.0.0:8000 + addr: 0.0.0.0:8001 grpc: addr: 0.0.0.0:9000 -data: - dbpath: ./goanalysis.db +logger: + level: debug + file_path: ./logs/app.log + console: true biz: gitlab: token: "${GITLAB_TOKEN}" url: "${GITLAB_API_URL}" + clone_dir: ./data + openai: + api_key: "${OPENAI_API_KEY}" + api_base: "${OPENAI_API_BASE}" + model: "${OPENAI_MODEL}" + +data: + dbpath: ./goanalysis.db ``` -## 📡 API Endpoints +### 🔄 Configuration Priority + +Configuration priority from high to low: +1. **Command Line Arguments** - Highest priority +2. **Environment Variables** - For sensitive information +3. **Configuration File** - Traditional approach +4. **Default Values** - Lowest priority + -| Endpoint | Method | Description | -|----------|--------|-------------| -| `/api/gids` | GET | Get goroutine IDs | -| `/api/functions` | GET | List traced functions | -| `/api/traces/{gid}` | GET | Get trace details | -| `/api/traces/{gid}/mermaid` | GET | Get diagram data | ## 🔧 Usage ### Basic Tracing ```bash +# Start with default configuration ./goanalysis server + +# Start with custom configuration +./goanalysis server --http-addr=0.0.0.0:8080 --log-level=info + +# Code rewriting ./goanalysis rewrite -d /path/to/project ``` ### Git Analysis ```bash +# Set GitLab configuration export GITLAB_TOKEN="your-token" -./goanalysis gitanalysis --project=123 --mr=45 +export GITLAB_API_URL="https://gitlab.com/api/v4" + +# Start server +./goanalysis server ``` ## 📂 Project Structure diff --git a/api/analysis/v1/analysis.pb.go b/api/analysis/v1/analysis.pb.go index 9d166ca..1cbbf62 100644 --- a/api/analysis/v1/analysis.pb.go +++ b/api/analysis/v1/analysis.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.36.6 -// protoc v6.31.1 +// protoc v6.30.2 // source: analysis/v1/analysis.proto package v1 @@ -3075,6 +3075,279 @@ func (x *SearchFunctionsReply) GetTotal() int32 { return 0 } +// GetFunctionInfoInGoroutineReq 获取函数在指定Goroutine中的信息请求 +type GetFunctionInfoInGoroutineReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + Dbpath string `protobuf:"bytes,1,opt,name=dbpath,proto3" json:"dbpath,omitempty"` // 数据库路径 + Gid uint64 `protobuf:"varint,2,opt,name=gid,proto3" json:"gid,omitempty"` // Goroutine ID + FunctionId int64 `protobuf:"varint,3,opt,name=functionId,proto3" json:"functionId,omitempty"` // 目标函数ID + CurrentDepth int32 `protobuf:"varint,4,opt,name=currentDepth,proto3" json:"currentDepth,omitempty"` // 当前显示深度 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetFunctionInfoInGoroutineReq) Reset() { + *x = GetFunctionInfoInGoroutineReq{} + mi := &file_analysis_v1_analysis_proto_msgTypes[55] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetFunctionInfoInGoroutineReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetFunctionInfoInGoroutineReq) ProtoMessage() {} + +func (x *GetFunctionInfoInGoroutineReq) ProtoReflect() protoreflect.Message { + mi := &file_analysis_v1_analysis_proto_msgTypes[55] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetFunctionInfoInGoroutineReq.ProtoReflect.Descriptor instead. +func (*GetFunctionInfoInGoroutineReq) Descriptor() ([]byte, []int) { + return file_analysis_v1_analysis_proto_rawDescGZIP(), []int{55} +} + +func (x *GetFunctionInfoInGoroutineReq) GetDbpath() string { + if x != nil { + return x.Dbpath + } + return "" +} + +func (x *GetFunctionInfoInGoroutineReq) GetGid() uint64 { + if x != nil { + return x.Gid + } + return 0 +} + +func (x *GetFunctionInfoInGoroutineReq) GetFunctionId() int64 { + if x != nil { + return x.FunctionId + } + return 0 +} + +func (x *GetFunctionInfoInGoroutineReq) GetCurrentDepth() int32 { + if x != nil { + return x.CurrentDepth + } + return 0 +} + +// ParentInfo 父函数信息 +type ParentInfo struct { + state protoimpl.MessageState `protogen:"open.v1"` + ParentId int64 `protobuf:"varint,1,opt,name=parentId,proto3" json:"parentId,omitempty"` // 父函数ID + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // 父函数名称 + Depth int32 `protobuf:"varint,3,opt,name=depth,proto3" json:"depth,omitempty"` // 深度 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ParentInfo) Reset() { + *x = ParentInfo{} + mi := &file_analysis_v1_analysis_proto_msgTypes[56] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ParentInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ParentInfo) ProtoMessage() {} + +func (x *ParentInfo) ProtoReflect() protoreflect.Message { + mi := &file_analysis_v1_analysis_proto_msgTypes[56] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ParentInfo.ProtoReflect.Descriptor instead. +func (*ParentInfo) Descriptor() ([]byte, []int) { + return file_analysis_v1_analysis_proto_rawDescGZIP(), []int{56} +} + +func (x *ParentInfo) GetParentId() int64 { + if x != nil { + return x.ParentId + } + return 0 +} + +func (x *ParentInfo) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ParentInfo) GetDepth() int32 { + if x != nil { + return x.Depth + } + return 0 +} + +// GetFunctionInfoInGoroutineReply 获取函数在指定Goroutine中的信息响应 +type GetFunctionInfoInGoroutineReply struct { + state protoimpl.MessageState `protogen:"open.v1"` + FunctionInfo *GetFunctionInfoInGoroutineReply_FunctionInfo `protobuf:"bytes,1,opt,name=functionInfo,proto3" json:"functionInfo,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetFunctionInfoInGoroutineReply) Reset() { + *x = GetFunctionInfoInGoroutineReply{} + mi := &file_analysis_v1_analysis_proto_msgTypes[57] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetFunctionInfoInGoroutineReply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetFunctionInfoInGoroutineReply) ProtoMessage() {} + +func (x *GetFunctionInfoInGoroutineReply) ProtoReflect() protoreflect.Message { + mi := &file_analysis_v1_analysis_proto_msgTypes[57] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetFunctionInfoInGoroutineReply.ProtoReflect.Descriptor instead. +func (*GetFunctionInfoInGoroutineReply) Descriptor() ([]byte, []int) { + return file_analysis_v1_analysis_proto_rawDescGZIP(), []int{57} +} + +func (x *GetFunctionInfoInGoroutineReply) GetFunctionInfo() *GetFunctionInfoInGoroutineReply_FunctionInfo { + if x != nil { + return x.FunctionInfo + } + return nil +} + +// GetModuleNamesReq 获取模块名称请求 +type GetModuleNamesReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + Dbpath string `protobuf:"bytes,1,opt,name=dbpath,proto3" json:"dbpath,omitempty"` // 数据库路径 + MaxSamples int32 `protobuf:"varint,2,opt,name=maxSamples,proto3" json:"maxSamples,omitempty"` // 最大采样数量,默认5000 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetModuleNamesReq) Reset() { + *x = GetModuleNamesReq{} + mi := &file_analysis_v1_analysis_proto_msgTypes[58] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetModuleNamesReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetModuleNamesReq) ProtoMessage() {} + +func (x *GetModuleNamesReq) ProtoReflect() protoreflect.Message { + mi := &file_analysis_v1_analysis_proto_msgTypes[58] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetModuleNamesReq.ProtoReflect.Descriptor instead. +func (*GetModuleNamesReq) Descriptor() ([]byte, []int) { + return file_analysis_v1_analysis_proto_rawDescGZIP(), []int{58} +} + +func (x *GetModuleNamesReq) GetDbpath() string { + if x != nil { + return x.Dbpath + } + return "" +} + +func (x *GetModuleNamesReq) GetMaxSamples() int32 { + if x != nil { + return x.MaxSamples + } + return 0 +} + +// GetModuleNamesReply 获取模块名称响应 +type GetModuleNamesReply struct { + state protoimpl.MessageState `protogen:"open.v1"` + ModuleNames []string `protobuf:"bytes,1,rep,name=moduleNames,proto3" json:"moduleNames,omitempty"` // 前5个最频繁的模块名称(按频率排序) + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetModuleNamesReply) Reset() { + *x = GetModuleNamesReply{} + mi := &file_analysis_v1_analysis_proto_msgTypes[59] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetModuleNamesReply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetModuleNamesReply) ProtoMessage() {} + +func (x *GetModuleNamesReply) ProtoReflect() protoreflect.Message { + mi := &file_analysis_v1_analysis_proto_msgTypes[59] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetModuleNamesReply.ProtoReflect.Descriptor instead. +func (*GetModuleNamesReply) Descriptor() ([]byte, []int) { + return file_analysis_v1_analysis_proto_rawDescGZIP(), []int{59} +} + +func (x *GetModuleNamesReply) GetModuleNames() []string { + if x != nil { + return x.ModuleNames + } + return nil +} + type GetGidsByFunctionNameReply_Body struct { state protoimpl.MessageState `protogen:"open.v1"` Gid uint64 `protobuf:"varint,1,opt,name=gid,proto3" json:"gid,omitempty"` @@ -3082,13 +3355,14 @@ type GetGidsByFunctionNameReply_Body struct { Depth int32 `protobuf:"varint,3,opt,name=depth,proto3" json:"depth,omitempty"` // 调用深度 ExecutionTime string `protobuf:"bytes,4,opt,name=executionTime,proto3" json:"executionTime,omitempty"` // 执行时间 IsFinished bool `protobuf:"varint,5,opt,name=isFinished,proto3" json:"isFinished,omitempty"` // 是否完成 + FunctionId int64 `protobuf:"varint,6,opt,name=functionId,proto3" json:"functionId,omitempty"` // 函数ID unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *GetGidsByFunctionNameReply_Body) Reset() { *x = GetGidsByFunctionNameReply_Body{} - mi := &file_analysis_v1_analysis_proto_msgTypes[55] + mi := &file_analysis_v1_analysis_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3100,7 +3374,7 @@ func (x *GetGidsByFunctionNameReply_Body) String() string { func (*GetGidsByFunctionNameReply_Body) ProtoMessage() {} func (x *GetGidsByFunctionNameReply_Body) ProtoReflect() protoreflect.Message { - mi := &file_analysis_v1_analysis_proto_msgTypes[55] + mi := &file_analysis_v1_analysis_proto_msgTypes[60] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3151,6 +3425,13 @@ func (x *GetGidsByFunctionNameReply_Body) GetIsFinished() bool { return false } +func (x *GetGidsByFunctionNameReply_Body) GetFunctionId() int64 { + if x != nil { + return x.FunctionId + } + return 0 +} + type AnalysisByGIDReply_TraceData struct { state protoimpl.MessageState `protogen:"open.v1"` Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` @@ -3168,7 +3449,7 @@ type AnalysisByGIDReply_TraceData struct { func (x *AnalysisByGIDReply_TraceData) Reset() { *x = AnalysisByGIDReply_TraceData{} - mi := &file_analysis_v1_analysis_proto_msgTypes[56] + mi := &file_analysis_v1_analysis_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3180,7 +3461,7 @@ func (x *AnalysisByGIDReply_TraceData) String() string { func (*AnalysisByGIDReply_TraceData) ProtoMessage() {} func (x *AnalysisByGIDReply_TraceData) ProtoReflect() protoreflect.Message { - mi := &file_analysis_v1_analysis_proto_msgTypes[56] + mi := &file_analysis_v1_analysis_proto_msgTypes[61] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3272,7 +3553,7 @@ type GetAllGIDsReply_Body struct { func (x *GetAllGIDsReply_Body) Reset() { *x = GetAllGIDsReply_Body{} - mi := &file_analysis_v1_analysis_proto_msgTypes[57] + mi := &file_analysis_v1_analysis_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3284,7 +3565,7 @@ func (x *GetAllGIDsReply_Body) String() string { func (*GetAllGIDsReply_Body) ProtoMessage() {} func (x *GetAllGIDsReply_Body) ProtoReflect() protoreflect.Message { - mi := &file_analysis_v1_analysis_proto_msgTypes[57] + mi := &file_analysis_v1_analysis_proto_msgTypes[62] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3352,7 +3633,7 @@ type GetTracesByParentFuncReply_TraceData struct { func (x *GetTracesByParentFuncReply_TraceData) Reset() { *x = GetTracesByParentFuncReply_TraceData{} - mi := &file_analysis_v1_analysis_proto_msgTypes[58] + mi := &file_analysis_v1_analysis_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3364,7 +3645,7 @@ func (x *GetTracesByParentFuncReply_TraceData) String() string { func (*GetTracesByParentFuncReply_TraceData) ProtoMessage() {} func (x *GetTracesByParentFuncReply_TraceData) ProtoReflect() protoreflect.Message { - mi := &file_analysis_v1_analysis_proto_msgTypes[58] + mi := &file_analysis_v1_analysis_proto_msgTypes[63] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3457,7 +3738,7 @@ type GetFunctionAnalysisReply_FunctionNode struct { func (x *GetFunctionAnalysisReply_FunctionNode) Reset() { *x = GetFunctionAnalysisReply_FunctionNode{} - mi := &file_analysis_v1_analysis_proto_msgTypes[59] + mi := &file_analysis_v1_analysis_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3469,7 +3750,7 @@ func (x *GetFunctionAnalysisReply_FunctionNode) String() string { func (*GetFunctionAnalysisReply_FunctionNode) ProtoMessage() {} func (x *GetFunctionAnalysisReply_FunctionNode) ProtoReflect() protoreflect.Message { - mi := &file_analysis_v1_analysis_proto_msgTypes[59] + mi := &file_analysis_v1_analysis_proto_msgTypes[64] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3540,7 +3821,7 @@ type GetHotFunctionsReply_HotFunction struct { func (x *GetHotFunctionsReply_HotFunction) Reset() { *x = GetHotFunctionsReply_HotFunction{} - mi := &file_analysis_v1_analysis_proto_msgTypes[61] + mi := &file_analysis_v1_analysis_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3552,7 +3833,7 @@ func (x *GetHotFunctionsReply_HotFunction) String() string { func (*GetHotFunctionsReply_HotFunction) ProtoMessage() {} func (x *GetHotFunctionsReply_HotFunction) ProtoReflect() protoreflect.Message { - mi := &file_analysis_v1_analysis_proto_msgTypes[61] + mi := &file_analysis_v1_analysis_proto_msgTypes[66] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3605,17 +3886,15 @@ func (x *GetHotFunctionsReply_HotFunction) GetAvgTime() string { type SearchFunctionsReply_FunctionInfo struct { state protoimpl.MessageState `protogen:"open.v1"` - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` // 函数名称 - Package string `protobuf:"bytes,2,opt,name=package,proto3" json:"package,omitempty"` // 包名 - CallCount int32 `protobuf:"varint,3,opt,name=callCount,proto3" json:"callCount,omitempty"` // 调用次数 - AvgTime string `protobuf:"bytes,4,opt,name=avgTime,proto3" json:"avgTime,omitempty"` // 平均执行时间 + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` // 函数名称 + Package string `protobuf:"bytes,2,opt,name=package,proto3" json:"package,omitempty"` // 包名 unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *SearchFunctionsReply_FunctionInfo) Reset() { *x = SearchFunctionsReply_FunctionInfo{} - mi := &file_analysis_v1_analysis_proto_msgTypes[62] + mi := &file_analysis_v1_analysis_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3627,7 +3906,7 @@ func (x *SearchFunctionsReply_FunctionInfo) String() string { func (*SearchFunctionsReply_FunctionInfo) ProtoMessage() {} func (x *SearchFunctionsReply_FunctionInfo) ProtoReflect() protoreflect.Message { - mi := &file_analysis_v1_analysis_proto_msgTypes[62] + mi := &file_analysis_v1_analysis_proto_msgTypes[67] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3657,20 +3936,74 @@ func (x *SearchFunctionsReply_FunctionInfo) GetPackage() string { return "" } -func (x *SearchFunctionsReply_FunctionInfo) GetCallCount() int32 { +type GetFunctionInfoInGoroutineReply_FunctionInfo struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` // 函数ID + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // 函数名称 + Depth int32 `protobuf:"varint,3,opt,name=depth,proto3" json:"depth,omitempty"` // 函数在调用链中的实际深度 + ParentIds []*ParentInfo `protobuf:"bytes,4,rep,name=parentIds,proto3" json:"parentIds,omitempty"` // 父函数ID+深度列表(去重) + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetFunctionInfoInGoroutineReply_FunctionInfo) Reset() { + *x = GetFunctionInfoInGoroutineReply_FunctionInfo{} + mi := &file_analysis_v1_analysis_proto_msgTypes[68] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetFunctionInfoInGoroutineReply_FunctionInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetFunctionInfoInGoroutineReply_FunctionInfo) ProtoMessage() {} + +func (x *GetFunctionInfoInGoroutineReply_FunctionInfo) ProtoReflect() protoreflect.Message { + mi := &file_analysis_v1_analysis_proto_msgTypes[68] if x != nil { - return x.CallCount + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetFunctionInfoInGoroutineReply_FunctionInfo.ProtoReflect.Descriptor instead. +func (*GetFunctionInfoInGoroutineReply_FunctionInfo) Descriptor() ([]byte, []int) { + return file_analysis_v1_analysis_proto_rawDescGZIP(), []int{57, 0} +} + +func (x *GetFunctionInfoInGoroutineReply_FunctionInfo) GetId() int64 { + if x != nil { + return x.Id } return 0 } -func (x *SearchFunctionsReply_FunctionInfo) GetAvgTime() string { +func (x *GetFunctionInfoInGoroutineReply_FunctionInfo) GetName() string { if x != nil { - return x.AvgTime + return x.Name } return "" } +func (x *GetFunctionInfoInGoroutineReply_FunctionInfo) GetDepth() int32 { + if x != nil { + return x.Depth + } + return 0 +} + +func (x *GetFunctionInfoInGoroutineReply_FunctionInfo) GetParentIds() []*ParentInfo { + if x != nil { + return x.ParentIds + } + return nil +} + var File_analysis_v1_analysis_proto protoreflect.FileDescriptor const file_analysis_v1_analysis_proto_rawDesc = "" + @@ -3683,10 +4016,10 @@ const file_analysis_v1_analysis_proto_rawDesc = "" + "\x18GetGidsByFunctionNameReq\x12\"\n" + "\ffunctionName\x18\x01 \x01(\tR\ffunctionName\x12\x12\n" + "\x04path\x18\x02 \x01(\tR\x04path\x12&\n" + - "\x0eincludeMetrics\x18\x03 \x01(\bR\x0eincludeMetrics\"\x8d\x02\n" + + "\x0eincludeMetrics\x18\x03 \x01(\bR\x0eincludeMetrics\"\xad\x02\n" + "\x1aGetGidsByFunctionNameReply\x12@\n" + "\x04body\x18\x01 \x03(\v2,.analysis.v1.GetGidsByFunctionNameReply.BodyR\x04body\x12\x14\n" + - "\x05total\x18\x02 \x01(\x05R\x05total\x1a\x96\x01\n" + + "\x05total\x18\x02 \x01(\x05R\x05total\x1a\xb6\x01\n" + "\x04Body\x12\x10\n" + "\x03gid\x18\x01 \x01(\x04R\x03gid\x12 \n" + "\vinitialFunc\x18\x02 \x01(\tR\vinitialFunc\x12\x14\n" + @@ -3694,7 +4027,10 @@ const file_analysis_v1_analysis_proto_rawDesc = "" + "\rexecutionTime\x18\x04 \x01(\tR\rexecutionTime\x12\x1e\n" + "\n" + "isFinished\x18\x05 \x01(\bR\n" + - "isFinished\"/\n" + + "isFinished\x12\x1e\n" + + "\n" + + "functionId\x18\x06 \x01(\x03R\n" + + "functionId\"/\n" + "\x15GetAllFunctionNameReq\x12\x16\n" + "\x06dbpath\x18\x01 \x01(\tR\x06dbpath\"?\n" + "\x17GetAllFunctionNameReply\x12$\n" + @@ -3924,22 +4260,46 @@ const file_analysis_v1_analysis_proto_rawDesc = "" + "\x12SearchFunctionsReq\x12\x16\n" + "\x06dbpath\x18\x01 \x01(\tR\x06dbpath\x12\x14\n" + "\x05query\x18\x02 \x01(\tR\x05query\x12\x14\n" + - "\x05limit\x18\x03 \x01(\x05R\x05limit\"\xf0\x01\n" + + "\x05limit\x18\x03 \x01(\x05R\x05limit\"\xb8\x01\n" + "\x14SearchFunctionsReply\x12L\n" + "\tfunctions\x18\x01 \x03(\v2..analysis.v1.SearchFunctionsReply.FunctionInfoR\tfunctions\x12\x14\n" + - "\x05total\x18\x02 \x01(\x05R\x05total\x1at\n" + + "\x05total\x18\x02 \x01(\x05R\x05total\x1a<\n" + "\fFunctionInfo\x12\x12\n" + "\x04name\x18\x01 \x01(\tR\x04name\x12\x18\n" + - "\apackage\x18\x02 \x01(\tR\apackage\x12\x1c\n" + - "\tcallCount\x18\x03 \x01(\x05R\tcallCount\x12\x18\n" + - "\aavgTime\x18\x04 \x01(\tR\aavgTime2\xcd\x13\n" + + "\apackage\x18\x02 \x01(\tR\apackage\"\x8d\x01\n" + + "\x1dGetFunctionInfoInGoroutineReq\x12\x16\n" + + "\x06dbpath\x18\x01 \x01(\tR\x06dbpath\x12\x10\n" + + "\x03gid\x18\x02 \x01(\x04R\x03gid\x12\x1e\n" + + "\n" + + "functionId\x18\x03 \x01(\x03R\n" + + "functionId\x12\"\n" + + "\fcurrentDepth\x18\x04 \x01(\x05R\fcurrentDepth\"R\n" + + "\n" + + "ParentInfo\x12\x1a\n" + + "\bparentId\x18\x01 \x01(\x03R\bparentId\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12\x14\n" + + "\x05depth\x18\x03 \x01(\x05R\x05depth\"\x81\x02\n" + + "\x1fGetFunctionInfoInGoroutineReply\x12]\n" + + "\ffunctionInfo\x18\x01 \x01(\v29.analysis.v1.GetFunctionInfoInGoroutineReply.FunctionInfoR\ffunctionInfo\x1a\x7f\n" + + "\fFunctionInfo\x12\x0e\n" + + "\x02id\x18\x01 \x01(\x03R\x02id\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12\x14\n" + + "\x05depth\x18\x03 \x01(\x05R\x05depth\x125\n" + + "\tparentIds\x18\x04 \x03(\v2\x17.analysis.v1.ParentInfoR\tparentIds\"K\n" + + "\x11GetModuleNamesReq\x12\x16\n" + + "\x06dbpath\x18\x01 \x01(\tR\x06dbpath\x12\x1e\n" + + "\n" + + "maxSamples\x18\x02 \x01(\x05R\n" + + "maxSamples\"7\n" + + "\x13GetModuleNamesReply\x12 \n" + + "\vmoduleNames\x18\x01 \x03(\tR\vmoduleNames2\xbb\x10\n" + "\bAnalysis\x12d\n" + - "\vGetAnalysis\x12\x1c.analysis.v1.AnalysisRequest\x1a\x1a.analysis.v1.AnalysisReply\"\x1b\x82\xd3\xe4\x93\x02\x15:\x01*\"\x10/analysis/{name}\x12|\n" + + "\vGetAnalysis\x12\x1c.analysis.v1.AnalysisRequest\x1a\x1a.analysis.v1.AnalysisReply\"\x1b\x82\xd3\xe4\x93\x02\x15:\x01*\"\x10/analysis/{name}\x12\x7f\n" + + "\x11InstrumentProject\x12!.analysis.v1.InstrumentProjectReq\x1a#.analysis.v1.InstrumentProjectReply\"\"\x82\xd3\xe4\x93\x02\x1c:\x01*\"\x17/api/runtime/instrument\x12|\n" + "\x10GetAnalysisByGID\x12!.analysis.v1.AnalysisByGIDRequest\x1a\x1f.analysis.v1.AnalysisByGIDReply\"$\x82\xd3\xe4\x93\x02\x1e:\x01*\"\x19/api/runtime/traces/{gid}\x12d\n" + "\n" + "GetAllGIDs\x12\x1a.analysis.v1.GetAllGIDsReq\x1a\x1c.analysis.v1.GetAllGIDsReply\"\x1c\x82\xd3\xe4\x93\x02\x16:\x01*\"\x11/api/runtime/gids\x12t\n" + - "\rGetParamsByID\x12\x1d.analysis.v1.GetParamsByIDReq\x1a\x1f.analysis.v1.GetParamsByIDReply\"#\x82\xd3\xe4\x93\x02\x1d:\x01*\"\x18/api/runtime/params/{id}\x12\x81\x01\n" + - "\x12GetAllFunctionName\x12\".analysis.v1.GetAllFunctionNameReq\x1a$.analysis.v1.GetAllFunctionNameReply\"!\x82\xd3\xe4\x93\x02\x1b:\x01*\"\x16/api/runtime/functions\x12\x8e\x01\n" + + "\rGetParamsByID\x12\x1d.analysis.v1.GetParamsByIDReq\x1a\x1f.analysis.v1.GetParamsByIDReply\"#\x82\xd3\xe4\x93\x02\x1d:\x01*\"\x18/api/runtime/params/{id}\x12\x8e\x01\n" + "\x15GetGidsByFunctionName\x12%.analysis.v1.GetGidsByFunctionNameReq\x1a'.analysis.v1.GetGidsByFunctionNameReply\"%\x82\xd3\xe4\x93\x02\x1f:\x01*\"\x1a/api/runtime/gids/function\x12\x80\x01\n" + "\x11VerifyProjectPath\x12!.analysis.v1.VerifyProjectPathReq\x1a#.analysis.v1.VerifyProjectPathReply\"#\x82\xd3\xe4\x93\x02\x1d:\x01*\"\x18/api/runtime/verify/path\x12\x99\x01\n" + "\x15GetTracesByParentFunc\x12%.analysis.v1.GetTracesByParentFuncReq\x1a'.analysis.v1.GetTracesByParentFuncReply\"0\x82\xd3\xe4\x93\x02*:\x01*\"%/api/runtime/traces/parent/{parentId}\x12\x89\x01\n" + @@ -3947,13 +4307,10 @@ const file_analysis_v1_analysis_proto_rawDesc = "" + "\x11GetChildFunctions\x12!.analysis.v1.GetChildFunctionsReq\x1a#.analysis.v1.GetChildFunctionsReply\"*\x82\xd3\xe4\x93\x02$:\x01*\"\x1f/api/runtime/functions/children\x12|\n" + "\x0fGetHotFunctions\x12\x1f.analysis.v1.GetHotFunctionsReq\x1a!.analysis.v1.GetHotFunctionsReply\"%\x82\xd3\xe4\x93\x02\x1f:\x01*\"\x1a/api/runtime/hot-functions\x12\x84\x01\n" + "\x11GetGoroutineStats\x12!.analysis.v1.GetGoroutineStatsReq\x1a#.analysis.v1.GetGoroutineStatsReply\"'\x82\xd3\xe4\x93\x02!:\x01*\"\x1c/api/runtime/goroutine-stats\x12\x8c\x01\n" + - "\x13GetFunctionAnalysis\x12#.analysis.v1.GetFunctionAnalysisReq\x1a%.analysis.v1.GetFunctionAnalysisReply\")\x82\xd3\xe4\x93\x02#:\x01*\"\x1e/api/runtime/function/analysis\x12\x7f\n" + - "\x11InstrumentProject\x12!.analysis.v1.InstrumentProjectReq\x1a#.analysis.v1.InstrumentProjectReply\"\"\x82\xd3\xe4\x93\x02\x1c:\x01*\"\x17/api/runtime/instrument\x12p\n" + - "\fGetTreeGraph\x12\x1c.analysis.v1.GetTreeGraphReq\x1a\x1e.analysis.v1.GetTreeGraphReply\"\"\x82\xd3\xe4\x93\x02\x1c:\x01*\"\x17/api/runtime/tree-graph\x12\x83\x01\n" + - "\x11GetTreeGraphByGID\x12!.analysis.v1.GetTreeGraphByGIDReq\x1a#.analysis.v1.GetTreeGraphByGIDReply\"&\x82\xd3\xe4\x93\x02 :\x01*\"\x1b/api/runtime/tree-graph/gid\x12\x8c\x01\n" + - "\x14GetFunctionCallStats\x12$.analysis.v1.GetFunctionCallStatsReq\x1a&.analysis.v1.GetFunctionCallStatsReply\"&\x82\xd3\xe4\x93\x02 :\x01*\"\x1b/api/runtime/function/stats\x12\x99\x01\n" + - "\x17GetPerformanceAnomalies\x12'.analysis.v1.GetPerformanceAnomaliesReq\x1a).analysis.v1.GetPerformanceAnomaliesReply\"*\x82\xd3\xe4\x93\x02$:\x01*\"\x1f/api/runtime/function/anomalies\x12\x7f\n" + - "\x0fSearchFunctions\x12\x1f.analysis.v1.SearchFunctionsReq\x1a!.analysis.v1.SearchFunctionsReply\"(\x82\xd3\xe4\x93\x02\":\x01*\"\x1d/api/runtime/functions/searchB2Z0github.com/toheart/goanalysis/api/analysis/v1;v1b\x06proto3" + "\x14GetFunctionCallStats\x12$.analysis.v1.GetFunctionCallStatsReq\x1a&.analysis.v1.GetFunctionCallStatsReply\"&\x82\xd3\xe4\x93\x02 :\x01*\"\x1b/api/runtime/function/stats\x12\x7f\n" + + "\x0fSearchFunctions\x12\x1f.analysis.v1.SearchFunctionsReq\x1a!.analysis.v1.SearchFunctionsReply\"(\x82\xd3\xe4\x93\x02\":\x01*\"\x1d/api/runtime/functions/search\x12\x9d\x01\n" + + "\x1aGetFunctionInfoInGoroutine\x12*.analysis.v1.GetFunctionInfoInGoroutineReq\x1a,.analysis.v1.GetFunctionInfoInGoroutineReply\"%\x82\xd3\xe4\x93\x02\x1f:\x01*\"\x1a/api/runtime/function/info\x12s\n" + + "\x0eGetModuleNames\x12\x1e.analysis.v1.GetModuleNamesReq\x1a .analysis.v1.GetModuleNamesReply\"\x1f\x82\xd3\xe4\x93\x02\x19:\x01*\"\x14/api/runtime/modulesB2Z0github.com/toheart/goanalysis/api/analysis/v1;v1b\x06proto3" var ( file_analysis_v1_analysis_proto_rawDescOnce sync.Once @@ -3967,7 +4324,7 @@ func file_analysis_v1_analysis_proto_rawDescGZIP() []byte { return file_analysis_v1_analysis_proto_rawDescData } -var file_analysis_v1_analysis_proto_msgTypes = make([]protoimpl.MessageInfo, 63) +var file_analysis_v1_analysis_proto_msgTypes = make([]protoimpl.MessageInfo, 69) var file_analysis_v1_analysis_proto_goTypes = []any{ (*VerifyProjectPathReq)(nil), // 0: analysis.v1.VerifyProjectPathReq (*VerifyProjectPathReply)(nil), // 1: analysis.v1.VerifyProjectPathReply @@ -4024,82 +4381,84 @@ var file_analysis_v1_analysis_proto_goTypes = []any{ (*GetHotFunctionsReply)(nil), // 52: analysis.v1.GetHotFunctionsReply (*SearchFunctionsReq)(nil), // 53: analysis.v1.SearchFunctionsReq (*SearchFunctionsReply)(nil), // 54: analysis.v1.SearchFunctionsReply - (*GetGidsByFunctionNameReply_Body)(nil), // 55: analysis.v1.GetGidsByFunctionNameReply.Body - (*AnalysisByGIDReply_TraceData)(nil), // 56: analysis.v1.AnalysisByGIDReply.TraceData - (*GetAllGIDsReply_Body)(nil), // 57: analysis.v1.GetAllGIDsReply.Body - (*GetTracesByParentFuncReply_TraceData)(nil), // 58: analysis.v1.GetTracesByParentFuncReply.TraceData - (*GetFunctionAnalysisReply_FunctionNode)(nil), // 59: analysis.v1.GetFunctionAnalysisReply.FunctionNode - nil, // 60: analysis.v1.PerformanceAnomaly.DetailsEntry - (*GetHotFunctionsReply_HotFunction)(nil), // 61: analysis.v1.GetHotFunctionsReply.HotFunction - (*SearchFunctionsReply_FunctionInfo)(nil), // 62: analysis.v1.SearchFunctionsReply.FunctionInfo + (*GetFunctionInfoInGoroutineReq)(nil), // 55: analysis.v1.GetFunctionInfoInGoroutineReq + (*ParentInfo)(nil), // 56: analysis.v1.ParentInfo + (*GetFunctionInfoInGoroutineReply)(nil), // 57: analysis.v1.GetFunctionInfoInGoroutineReply + (*GetModuleNamesReq)(nil), // 58: analysis.v1.GetModuleNamesReq + (*GetModuleNamesReply)(nil), // 59: analysis.v1.GetModuleNamesReply + (*GetGidsByFunctionNameReply_Body)(nil), // 60: analysis.v1.GetGidsByFunctionNameReply.Body + (*AnalysisByGIDReply_TraceData)(nil), // 61: analysis.v1.AnalysisByGIDReply.TraceData + (*GetAllGIDsReply_Body)(nil), // 62: analysis.v1.GetAllGIDsReply.Body + (*GetTracesByParentFuncReply_TraceData)(nil), // 63: analysis.v1.GetTracesByParentFuncReply.TraceData + (*GetFunctionAnalysisReply_FunctionNode)(nil), // 64: analysis.v1.GetFunctionAnalysisReply.FunctionNode + nil, // 65: analysis.v1.PerformanceAnomaly.DetailsEntry + (*GetHotFunctionsReply_HotFunction)(nil), // 66: analysis.v1.GetHotFunctionsReply.HotFunction + (*SearchFunctionsReply_FunctionInfo)(nil), // 67: analysis.v1.SearchFunctionsReply.FunctionInfo + (*GetFunctionInfoInGoroutineReply_FunctionInfo)(nil), // 68: analysis.v1.GetFunctionInfoInGoroutineReply.FunctionInfo } var file_analysis_v1_analysis_proto_depIdxs = []int32{ - 55, // 0: analysis.v1.GetGidsByFunctionNameReply.body:type_name -> analysis.v1.GetGidsByFunctionNameReply.Body - 56, // 1: analysis.v1.AnalysisByGIDReply.traceData:type_name -> analysis.v1.AnalysisByGIDReply.TraceData - 57, // 2: analysis.v1.GetAllGIDsReply.body:type_name -> analysis.v1.GetAllGIDsReply.Body + 60, // 0: analysis.v1.GetGidsByFunctionNameReply.body:type_name -> analysis.v1.GetGidsByFunctionNameReply.Body + 61, // 1: analysis.v1.AnalysisByGIDReply.traceData:type_name -> analysis.v1.AnalysisByGIDReply.TraceData + 62, // 2: analysis.v1.GetAllGIDsReply.body:type_name -> analysis.v1.GetAllGIDsReply.Body 11, // 3: analysis.v1.GetParamsByIDReply.params:type_name -> analysis.v1.TraceParams 17, // 4: analysis.v1.GetTraceGraphReply.nodes:type_name -> analysis.v1.GraphNode 18, // 5: analysis.v1.GetTraceGraphReply.edges:type_name -> analysis.v1.GraphEdge - 58, // 6: analysis.v1.GetTracesByParentFuncReply.traceData:type_name -> analysis.v1.GetTracesByParentFuncReply.TraceData + 63, // 6: analysis.v1.GetTracesByParentFuncReply.traceData:type_name -> analysis.v1.GetTracesByParentFuncReply.TraceData 24, // 7: analysis.v1.GetParentFunctionsReply.functions:type_name -> analysis.v1.FunctionNode 24, // 8: analysis.v1.GetChildFunctionsReply.functions:type_name -> analysis.v1.FunctionNode - 59, // 9: analysis.v1.GetFunctionAnalysisReply.callData:type_name -> analysis.v1.GetFunctionAnalysisReply.FunctionNode + 64, // 9: analysis.v1.GetFunctionAnalysisReply.callData:type_name -> analysis.v1.GetFunctionAnalysisReply.FunctionNode 35, // 10: analysis.v1.AnalyzeDbFileResponse.packageDependencies:type_name -> analysis.v1.PackageDependency 36, // 11: analysis.v1.AnalyzeDbFileResponse.hotFunctions:type_name -> analysis.v1.HotFunction 41, // 12: analysis.v1.TreeNode.children:type_name -> analysis.v1.TreeNode 41, // 13: analysis.v1.GetTreeGraphReply.trees:type_name -> analysis.v1.TreeNode 41, // 14: analysis.v1.GetTreeGraphByGIDReply.trees:type_name -> analysis.v1.TreeNode 46, // 15: analysis.v1.GetFunctionCallStatsReply.stats:type_name -> analysis.v1.FunctionCallStats - 60, // 16: analysis.v1.PerformanceAnomaly.details:type_name -> analysis.v1.PerformanceAnomaly.DetailsEntry + 65, // 16: analysis.v1.PerformanceAnomaly.details:type_name -> analysis.v1.PerformanceAnomaly.DetailsEntry 49, // 17: analysis.v1.GetPerformanceAnomaliesReply.anomalies:type_name -> analysis.v1.PerformanceAnomaly - 61, // 18: analysis.v1.GetHotFunctionsReply.functions:type_name -> analysis.v1.GetHotFunctionsReply.HotFunction - 62, // 19: analysis.v1.SearchFunctionsReply.functions:type_name -> analysis.v1.SearchFunctionsReply.FunctionInfo - 11, // 20: analysis.v1.AnalysisByGIDReply.TraceData.params:type_name -> analysis.v1.TraceParams - 11, // 21: analysis.v1.GetTracesByParentFuncReply.TraceData.params:type_name -> analysis.v1.TraceParams - 59, // 22: analysis.v1.GetFunctionAnalysisReply.FunctionNode.children:type_name -> analysis.v1.GetFunctionAnalysisReply.FunctionNode - 8, // 23: analysis.v1.Analysis.GetAnalysis:input_type -> analysis.v1.AnalysisRequest - 10, // 24: analysis.v1.Analysis.GetAnalysisByGID:input_type -> analysis.v1.AnalysisByGIDRequest - 13, // 25: analysis.v1.Analysis.GetAllGIDs:input_type -> analysis.v1.GetAllGIDsReq - 15, // 26: analysis.v1.Analysis.GetParamsByID:input_type -> analysis.v1.GetParamsByIDReq - 4, // 27: analysis.v1.Analysis.GetAllFunctionName:input_type -> analysis.v1.GetAllFunctionNameReq - 2, // 28: analysis.v1.Analysis.GetGidsByFunctionName:input_type -> analysis.v1.GetGidsByFunctionNameReq - 0, // 29: analysis.v1.Analysis.VerifyProjectPath:input_type -> analysis.v1.VerifyProjectPathReq - 21, // 30: analysis.v1.Analysis.GetTracesByParentFunc:input_type -> analysis.v1.GetTracesByParentFuncReq - 23, // 31: analysis.v1.Analysis.GetParentFunctions:input_type -> analysis.v1.GetParentFunctionsReq - 26, // 32: analysis.v1.Analysis.GetChildFunctions:input_type -> analysis.v1.GetChildFunctionsReq - 51, // 33: analysis.v1.Analysis.GetHotFunctions:input_type -> analysis.v1.GetHotFunctionsReq - 28, // 34: analysis.v1.Analysis.GetGoroutineStats:input_type -> analysis.v1.GetGoroutineStatsReq - 30, // 35: analysis.v1.Analysis.GetFunctionAnalysis:input_type -> analysis.v1.GetFunctionAnalysisReq - 38, // 36: analysis.v1.Analysis.InstrumentProject:input_type -> analysis.v1.InstrumentProjectReq - 40, // 37: analysis.v1.Analysis.GetTreeGraph:input_type -> analysis.v1.GetTreeGraphReq - 43, // 38: analysis.v1.Analysis.GetTreeGraphByGID:input_type -> analysis.v1.GetTreeGraphByGIDReq - 45, // 39: analysis.v1.Analysis.GetFunctionCallStats:input_type -> analysis.v1.GetFunctionCallStatsReq - 48, // 40: analysis.v1.Analysis.GetPerformanceAnomalies:input_type -> analysis.v1.GetPerformanceAnomaliesReq - 53, // 41: analysis.v1.Analysis.SearchFunctions:input_type -> analysis.v1.SearchFunctionsReq - 9, // 42: analysis.v1.Analysis.GetAnalysis:output_type -> analysis.v1.AnalysisReply + 66, // 18: analysis.v1.GetHotFunctionsReply.functions:type_name -> analysis.v1.GetHotFunctionsReply.HotFunction + 67, // 19: analysis.v1.SearchFunctionsReply.functions:type_name -> analysis.v1.SearchFunctionsReply.FunctionInfo + 68, // 20: analysis.v1.GetFunctionInfoInGoroutineReply.functionInfo:type_name -> analysis.v1.GetFunctionInfoInGoroutineReply.FunctionInfo + 11, // 21: analysis.v1.AnalysisByGIDReply.TraceData.params:type_name -> analysis.v1.TraceParams + 11, // 22: analysis.v1.GetTracesByParentFuncReply.TraceData.params:type_name -> analysis.v1.TraceParams + 64, // 23: analysis.v1.GetFunctionAnalysisReply.FunctionNode.children:type_name -> analysis.v1.GetFunctionAnalysisReply.FunctionNode + 56, // 24: analysis.v1.GetFunctionInfoInGoroutineReply.FunctionInfo.parentIds:type_name -> analysis.v1.ParentInfo + 8, // 25: analysis.v1.Analysis.GetAnalysis:input_type -> analysis.v1.AnalysisRequest + 38, // 26: analysis.v1.Analysis.InstrumentProject:input_type -> analysis.v1.InstrumentProjectReq + 10, // 27: analysis.v1.Analysis.GetAnalysisByGID:input_type -> analysis.v1.AnalysisByGIDRequest + 13, // 28: analysis.v1.Analysis.GetAllGIDs:input_type -> analysis.v1.GetAllGIDsReq + 15, // 29: analysis.v1.Analysis.GetParamsByID:input_type -> analysis.v1.GetParamsByIDReq + 2, // 30: analysis.v1.Analysis.GetGidsByFunctionName:input_type -> analysis.v1.GetGidsByFunctionNameReq + 0, // 31: analysis.v1.Analysis.VerifyProjectPath:input_type -> analysis.v1.VerifyProjectPathReq + 21, // 32: analysis.v1.Analysis.GetTracesByParentFunc:input_type -> analysis.v1.GetTracesByParentFuncReq + 23, // 33: analysis.v1.Analysis.GetParentFunctions:input_type -> analysis.v1.GetParentFunctionsReq + 26, // 34: analysis.v1.Analysis.GetChildFunctions:input_type -> analysis.v1.GetChildFunctionsReq + 51, // 35: analysis.v1.Analysis.GetHotFunctions:input_type -> analysis.v1.GetHotFunctionsReq + 28, // 36: analysis.v1.Analysis.GetGoroutineStats:input_type -> analysis.v1.GetGoroutineStatsReq + 45, // 37: analysis.v1.Analysis.GetFunctionCallStats:input_type -> analysis.v1.GetFunctionCallStatsReq + 53, // 38: analysis.v1.Analysis.SearchFunctions:input_type -> analysis.v1.SearchFunctionsReq + 55, // 39: analysis.v1.Analysis.GetFunctionInfoInGoroutine:input_type -> analysis.v1.GetFunctionInfoInGoroutineReq + 58, // 40: analysis.v1.Analysis.GetModuleNames:input_type -> analysis.v1.GetModuleNamesReq + 9, // 41: analysis.v1.Analysis.GetAnalysis:output_type -> analysis.v1.AnalysisReply + 39, // 42: analysis.v1.Analysis.InstrumentProject:output_type -> analysis.v1.InstrumentProjectReply 12, // 43: analysis.v1.Analysis.GetAnalysisByGID:output_type -> analysis.v1.AnalysisByGIDReply 14, // 44: analysis.v1.Analysis.GetAllGIDs:output_type -> analysis.v1.GetAllGIDsReply 16, // 45: analysis.v1.Analysis.GetParamsByID:output_type -> analysis.v1.GetParamsByIDReply - 5, // 46: analysis.v1.Analysis.GetAllFunctionName:output_type -> analysis.v1.GetAllFunctionNameReply - 3, // 47: analysis.v1.Analysis.GetGidsByFunctionName:output_type -> analysis.v1.GetGidsByFunctionNameReply - 1, // 48: analysis.v1.Analysis.VerifyProjectPath:output_type -> analysis.v1.VerifyProjectPathReply - 22, // 49: analysis.v1.Analysis.GetTracesByParentFunc:output_type -> analysis.v1.GetTracesByParentFuncReply - 25, // 50: analysis.v1.Analysis.GetParentFunctions:output_type -> analysis.v1.GetParentFunctionsReply - 27, // 51: analysis.v1.Analysis.GetChildFunctions:output_type -> analysis.v1.GetChildFunctionsReply - 52, // 52: analysis.v1.Analysis.GetHotFunctions:output_type -> analysis.v1.GetHotFunctionsReply - 29, // 53: analysis.v1.Analysis.GetGoroutineStats:output_type -> analysis.v1.GetGoroutineStatsReply - 31, // 54: analysis.v1.Analysis.GetFunctionAnalysis:output_type -> analysis.v1.GetFunctionAnalysisReply - 39, // 55: analysis.v1.Analysis.InstrumentProject:output_type -> analysis.v1.InstrumentProjectReply - 42, // 56: analysis.v1.Analysis.GetTreeGraph:output_type -> analysis.v1.GetTreeGraphReply - 44, // 57: analysis.v1.Analysis.GetTreeGraphByGID:output_type -> analysis.v1.GetTreeGraphByGIDReply - 47, // 58: analysis.v1.Analysis.GetFunctionCallStats:output_type -> analysis.v1.GetFunctionCallStatsReply - 50, // 59: analysis.v1.Analysis.GetPerformanceAnomalies:output_type -> analysis.v1.GetPerformanceAnomaliesReply - 54, // 60: analysis.v1.Analysis.SearchFunctions:output_type -> analysis.v1.SearchFunctionsReply - 42, // [42:61] is the sub-list for method output_type - 23, // [23:42] is the sub-list for method input_type - 23, // [23:23] is the sub-list for extension type_name - 23, // [23:23] is the sub-list for extension extendee - 0, // [0:23] is the sub-list for field type_name + 3, // 46: analysis.v1.Analysis.GetGidsByFunctionName:output_type -> analysis.v1.GetGidsByFunctionNameReply + 1, // 47: analysis.v1.Analysis.VerifyProjectPath:output_type -> analysis.v1.VerifyProjectPathReply + 22, // 48: analysis.v1.Analysis.GetTracesByParentFunc:output_type -> analysis.v1.GetTracesByParentFuncReply + 25, // 49: analysis.v1.Analysis.GetParentFunctions:output_type -> analysis.v1.GetParentFunctionsReply + 27, // 50: analysis.v1.Analysis.GetChildFunctions:output_type -> analysis.v1.GetChildFunctionsReply + 52, // 51: analysis.v1.Analysis.GetHotFunctions:output_type -> analysis.v1.GetHotFunctionsReply + 29, // 52: analysis.v1.Analysis.GetGoroutineStats:output_type -> analysis.v1.GetGoroutineStatsReply + 47, // 53: analysis.v1.Analysis.GetFunctionCallStats:output_type -> analysis.v1.GetFunctionCallStatsReply + 54, // 54: analysis.v1.Analysis.SearchFunctions:output_type -> analysis.v1.SearchFunctionsReply + 57, // 55: analysis.v1.Analysis.GetFunctionInfoInGoroutine:output_type -> analysis.v1.GetFunctionInfoInGoroutineReply + 59, // 56: analysis.v1.Analysis.GetModuleNames:output_type -> analysis.v1.GetModuleNamesReply + 41, // [41:57] is the sub-list for method output_type + 25, // [25:41] is the sub-list for method input_type + 25, // [25:25] is the sub-list for extension type_name + 25, // [25:25] is the sub-list for extension extendee + 0, // [0:25] is the sub-list for field type_name } func init() { file_analysis_v1_analysis_proto_init() } @@ -4113,7 +4472,7 @@ func file_analysis_v1_analysis_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_analysis_v1_analysis_proto_rawDesc), len(file_analysis_v1_analysis_proto_rawDesc)), NumEnums: 0, - NumMessages: 63, + NumMessages: 69, NumExtensions: 0, NumServices: 1, }, diff --git a/api/analysis/v1/analysis.pb.gw.go b/api/analysis/v1/analysis.pb.gw.go index 253d334..919d6e3 100644 --- a/api/analysis/v1/analysis.pb.gw.go +++ b/api/analysis/v1/analysis.pb.gw.go @@ -77,6 +77,30 @@ func local_request_Analysis_GetAnalysis_0(ctx context.Context, marshaler runtime return msg, metadata, err } +func request_Analysis_InstrumentProject_0(ctx context.Context, marshaler runtime.Marshaler, client AnalysisClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq InstrumentProjectReq + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := client.InstrumentProject(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_Analysis_InstrumentProject_0(ctx context.Context, marshaler runtime.Marshaler, server AnalysisServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq InstrumentProjectReq + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := server.InstrumentProject(ctx, &protoReq) + return msg, metadata, err +} + func request_Analysis_GetAnalysisByGID_0(ctx context.Context, marshaler runtime.Marshaler, client AnalysisClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var ( protoReq AnalysisByGIDRequest @@ -185,30 +209,6 @@ func local_request_Analysis_GetParamsByID_0(ctx context.Context, marshaler runti return msg, metadata, err } -func request_Analysis_GetAllFunctionName_0(ctx context.Context, marshaler runtime.Marshaler, client AnalysisClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var ( - protoReq GetAllFunctionNameReq - metadata runtime.ServerMetadata - ) - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - msg, err := client.GetAllFunctionName(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err -} - -func local_request_Analysis_GetAllFunctionName_0(ctx context.Context, marshaler runtime.Marshaler, server AnalysisServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var ( - protoReq GetAllFunctionNameReq - metadata runtime.ServerMetadata - ) - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - msg, err := server.GetAllFunctionName(ctx, &protoReq) - return msg, metadata, err -} - func request_Analysis_GetGidsByFunctionName_0(ctx context.Context, marshaler runtime.Marshaler, client AnalysisClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var ( protoReq GetGidsByFunctionNameReq @@ -395,171 +395,99 @@ func local_request_Analysis_GetGoroutineStats_0(ctx context.Context, marshaler r return msg, metadata, err } -func request_Analysis_GetFunctionAnalysis_0(ctx context.Context, marshaler runtime.Marshaler, client AnalysisClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var ( - protoReq GetFunctionAnalysisReq - metadata runtime.ServerMetadata - ) - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - msg, err := client.GetFunctionAnalysis(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err -} - -func local_request_Analysis_GetFunctionAnalysis_0(ctx context.Context, marshaler runtime.Marshaler, server AnalysisServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var ( - protoReq GetFunctionAnalysisReq - metadata runtime.ServerMetadata - ) - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - msg, err := server.GetFunctionAnalysis(ctx, &protoReq) - return msg, metadata, err -} - -func request_Analysis_InstrumentProject_0(ctx context.Context, marshaler runtime.Marshaler, client AnalysisClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var ( - protoReq InstrumentProjectReq - metadata runtime.ServerMetadata - ) - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - msg, err := client.InstrumentProject(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err -} - -func local_request_Analysis_InstrumentProject_0(ctx context.Context, marshaler runtime.Marshaler, server AnalysisServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var ( - protoReq InstrumentProjectReq - metadata runtime.ServerMetadata - ) - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - msg, err := server.InstrumentProject(ctx, &protoReq) - return msg, metadata, err -} - -func request_Analysis_GetTreeGraph_0(ctx context.Context, marshaler runtime.Marshaler, client AnalysisClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var ( - protoReq GetTreeGraphReq - metadata runtime.ServerMetadata - ) - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - msg, err := client.GetTreeGraph(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err -} - -func local_request_Analysis_GetTreeGraph_0(ctx context.Context, marshaler runtime.Marshaler, server AnalysisServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var ( - protoReq GetTreeGraphReq - metadata runtime.ServerMetadata - ) - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - msg, err := server.GetTreeGraph(ctx, &protoReq) - return msg, metadata, err -} - -func request_Analysis_GetTreeGraphByGID_0(ctx context.Context, marshaler runtime.Marshaler, client AnalysisClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { +func request_Analysis_GetFunctionCallStats_0(ctx context.Context, marshaler runtime.Marshaler, client AnalysisClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var ( - protoReq GetTreeGraphByGIDReq + protoReq GetFunctionCallStatsReq metadata runtime.ServerMetadata ) if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := client.GetTreeGraphByGID(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + msg, err := client.GetFunctionCallStats(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } -func local_request_Analysis_GetTreeGraphByGID_0(ctx context.Context, marshaler runtime.Marshaler, server AnalysisServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { +func local_request_Analysis_GetFunctionCallStats_0(ctx context.Context, marshaler runtime.Marshaler, server AnalysisServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var ( - protoReq GetTreeGraphByGIDReq + protoReq GetFunctionCallStatsReq metadata runtime.ServerMetadata ) if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := server.GetTreeGraphByGID(ctx, &protoReq) + msg, err := server.GetFunctionCallStats(ctx, &protoReq) return msg, metadata, err } -func request_Analysis_GetFunctionCallStats_0(ctx context.Context, marshaler runtime.Marshaler, client AnalysisClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { +func request_Analysis_SearchFunctions_0(ctx context.Context, marshaler runtime.Marshaler, client AnalysisClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var ( - protoReq GetFunctionCallStatsReq + protoReq SearchFunctionsReq metadata runtime.ServerMetadata ) if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := client.GetFunctionCallStats(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + msg, err := client.SearchFunctions(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } -func local_request_Analysis_GetFunctionCallStats_0(ctx context.Context, marshaler runtime.Marshaler, server AnalysisServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { +func local_request_Analysis_SearchFunctions_0(ctx context.Context, marshaler runtime.Marshaler, server AnalysisServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var ( - protoReq GetFunctionCallStatsReq + protoReq SearchFunctionsReq metadata runtime.ServerMetadata ) if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := server.GetFunctionCallStats(ctx, &protoReq) + msg, err := server.SearchFunctions(ctx, &protoReq) return msg, metadata, err } -func request_Analysis_GetPerformanceAnomalies_0(ctx context.Context, marshaler runtime.Marshaler, client AnalysisClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { +func request_Analysis_GetFunctionInfoInGoroutine_0(ctx context.Context, marshaler runtime.Marshaler, client AnalysisClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var ( - protoReq GetPerformanceAnomaliesReq + protoReq GetFunctionInfoInGoroutineReq metadata runtime.ServerMetadata ) if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := client.GetPerformanceAnomalies(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + msg, err := client.GetFunctionInfoInGoroutine(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } -func local_request_Analysis_GetPerformanceAnomalies_0(ctx context.Context, marshaler runtime.Marshaler, server AnalysisServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { +func local_request_Analysis_GetFunctionInfoInGoroutine_0(ctx context.Context, marshaler runtime.Marshaler, server AnalysisServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var ( - protoReq GetPerformanceAnomaliesReq + protoReq GetFunctionInfoInGoroutineReq metadata runtime.ServerMetadata ) if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := server.GetPerformanceAnomalies(ctx, &protoReq) + msg, err := server.GetFunctionInfoInGoroutine(ctx, &protoReq) return msg, metadata, err } -func request_Analysis_SearchFunctions_0(ctx context.Context, marshaler runtime.Marshaler, client AnalysisClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { +func request_Analysis_GetModuleNames_0(ctx context.Context, marshaler runtime.Marshaler, client AnalysisClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var ( - protoReq SearchFunctionsReq + protoReq GetModuleNamesReq metadata runtime.ServerMetadata ) if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := client.SearchFunctions(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + msg, err := client.GetModuleNames(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } -func local_request_Analysis_SearchFunctions_0(ctx context.Context, marshaler runtime.Marshaler, server AnalysisServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { +func local_request_Analysis_GetModuleNames_0(ctx context.Context, marshaler runtime.Marshaler, server AnalysisServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var ( - protoReq SearchFunctionsReq + protoReq GetModuleNamesReq metadata runtime.ServerMetadata ) if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := server.SearchFunctions(ctx, &protoReq) + msg, err := server.GetModuleNames(ctx, &protoReq) return msg, metadata, err } @@ -589,85 +517,85 @@ func RegisterAnalysisHandlerServer(ctx context.Context, mux *runtime.ServeMux, s } forward_Analysis_GetAnalysis_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle(http.MethodPost, pattern_Analysis_GetAnalysisByGID_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle(http.MethodPost, pattern_Analysis_InstrumentProject_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/analysis.v1.Analysis/GetAnalysisByGID", runtime.WithHTTPPathPattern("/api/runtime/traces/{gid}")) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/analysis.v1.Analysis/InstrumentProject", runtime.WithHTTPPathPattern("/api/runtime/instrument")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_Analysis_GetAnalysisByGID_0(annotatedContext, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_Analysis_InstrumentProject_0(annotatedContext, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_Analysis_GetAnalysisByGID_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Analysis_InstrumentProject_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle(http.MethodPost, pattern_Analysis_GetAllGIDs_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle(http.MethodPost, pattern_Analysis_GetAnalysisByGID_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/analysis.v1.Analysis/GetAllGIDs", runtime.WithHTTPPathPattern("/api/runtime/gids")) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/analysis.v1.Analysis/GetAnalysisByGID", runtime.WithHTTPPathPattern("/api/runtime/traces/{gid}")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_Analysis_GetAllGIDs_0(annotatedContext, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_Analysis_GetAnalysisByGID_0(annotatedContext, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_Analysis_GetAllGIDs_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Analysis_GetAnalysisByGID_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle(http.MethodPost, pattern_Analysis_GetParamsByID_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle(http.MethodPost, pattern_Analysis_GetAllGIDs_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/analysis.v1.Analysis/GetParamsByID", runtime.WithHTTPPathPattern("/api/runtime/params/{id}")) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/analysis.v1.Analysis/GetAllGIDs", runtime.WithHTTPPathPattern("/api/runtime/gids")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_Analysis_GetParamsByID_0(annotatedContext, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_Analysis_GetAllGIDs_0(annotatedContext, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_Analysis_GetParamsByID_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Analysis_GetAllGIDs_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle(http.MethodPost, pattern_Analysis_GetAllFunctionName_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle(http.MethodPost, pattern_Analysis_GetParamsByID_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/analysis.v1.Analysis/GetAllFunctionName", runtime.WithHTTPPathPattern("/api/runtime/functions")) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/analysis.v1.Analysis/GetParamsByID", runtime.WithHTTPPathPattern("/api/runtime/params/{id}")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_Analysis_GetAllFunctionName_0(annotatedContext, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_Analysis_GetParamsByID_0(annotatedContext, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_Analysis_GetAllFunctionName_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Analysis_GetParamsByID_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) mux.Handle(http.MethodPost, pattern_Analysis_GetGidsByFunctionName_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) @@ -809,145 +737,85 @@ func RegisterAnalysisHandlerServer(ctx context.Context, mux *runtime.ServeMux, s } forward_Analysis_GetGoroutineStats_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle(http.MethodPost, pattern_Analysis_GetFunctionAnalysis_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/analysis.v1.Analysis/GetFunctionAnalysis", runtime.WithHTTPPathPattern("/api/runtime/function/analysis")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_Analysis_GetFunctionAnalysis_0(annotatedContext, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - forward_Analysis_GetFunctionAnalysis_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - }) - mux.Handle(http.MethodPost, pattern_Analysis_InstrumentProject_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/analysis.v1.Analysis/InstrumentProject", runtime.WithHTTPPathPattern("/api/runtime/instrument")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_Analysis_InstrumentProject_0(annotatedContext, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - forward_Analysis_InstrumentProject_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - }) - mux.Handle(http.MethodPost, pattern_Analysis_GetTreeGraph_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/analysis.v1.Analysis/GetTreeGraph", runtime.WithHTTPPathPattern("/api/runtime/tree-graph")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_Analysis_GetTreeGraph_0(annotatedContext, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - forward_Analysis_GetTreeGraph_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - }) - mux.Handle(http.MethodPost, pattern_Analysis_GetTreeGraphByGID_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle(http.MethodPost, pattern_Analysis_GetFunctionCallStats_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/analysis.v1.Analysis/GetTreeGraphByGID", runtime.WithHTTPPathPattern("/api/runtime/tree-graph/gid")) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/analysis.v1.Analysis/GetFunctionCallStats", runtime.WithHTTPPathPattern("/api/runtime/function/stats")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_Analysis_GetTreeGraphByGID_0(annotatedContext, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_Analysis_GetFunctionCallStats_0(annotatedContext, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_Analysis_GetTreeGraphByGID_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Analysis_GetFunctionCallStats_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle(http.MethodPost, pattern_Analysis_GetFunctionCallStats_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle(http.MethodPost, pattern_Analysis_SearchFunctions_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/analysis.v1.Analysis/GetFunctionCallStats", runtime.WithHTTPPathPattern("/api/runtime/function/stats")) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/analysis.v1.Analysis/SearchFunctions", runtime.WithHTTPPathPattern("/api/runtime/functions/search")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_Analysis_GetFunctionCallStats_0(annotatedContext, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_Analysis_SearchFunctions_0(annotatedContext, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_Analysis_GetFunctionCallStats_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Analysis_SearchFunctions_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle(http.MethodPost, pattern_Analysis_GetPerformanceAnomalies_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle(http.MethodPost, pattern_Analysis_GetFunctionInfoInGoroutine_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/analysis.v1.Analysis/GetPerformanceAnomalies", runtime.WithHTTPPathPattern("/api/runtime/function/anomalies")) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/analysis.v1.Analysis/GetFunctionInfoInGoroutine", runtime.WithHTTPPathPattern("/api/runtime/function/info")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_Analysis_GetPerformanceAnomalies_0(annotatedContext, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_Analysis_GetFunctionInfoInGoroutine_0(annotatedContext, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_Analysis_GetPerformanceAnomalies_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Analysis_GetFunctionInfoInGoroutine_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle(http.MethodPost, pattern_Analysis_SearchFunctions_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle(http.MethodPost, pattern_Analysis_GetModuleNames_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/analysis.v1.Analysis/SearchFunctions", runtime.WithHTTPPathPattern("/api/runtime/functions/search")) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/analysis.v1.Analysis/GetModuleNames", runtime.WithHTTPPathPattern("/api/runtime/modules")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_Analysis_SearchFunctions_0(annotatedContext, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_Analysis_GetModuleNames_0(annotatedContext, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_Analysis_SearchFunctions_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Analysis_GetModuleNames_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) return nil @@ -1006,73 +874,73 @@ func RegisterAnalysisHandlerClient(ctx context.Context, mux *runtime.ServeMux, c } forward_Analysis_GetAnalysis_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle(http.MethodPost, pattern_Analysis_GetAnalysisByGID_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle(http.MethodPost, pattern_Analysis_InstrumentProject_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/analysis.v1.Analysis/GetAnalysisByGID", runtime.WithHTTPPathPattern("/api/runtime/traces/{gid}")) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/analysis.v1.Analysis/InstrumentProject", runtime.WithHTTPPathPattern("/api/runtime/instrument")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_Analysis_GetAnalysisByGID_0(annotatedContext, inboundMarshaler, client, req, pathParams) + resp, md, err := request_Analysis_InstrumentProject_0(annotatedContext, inboundMarshaler, client, req, pathParams) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_Analysis_GetAnalysisByGID_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Analysis_InstrumentProject_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle(http.MethodPost, pattern_Analysis_GetAllGIDs_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle(http.MethodPost, pattern_Analysis_GetAnalysisByGID_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/analysis.v1.Analysis/GetAllGIDs", runtime.WithHTTPPathPattern("/api/runtime/gids")) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/analysis.v1.Analysis/GetAnalysisByGID", runtime.WithHTTPPathPattern("/api/runtime/traces/{gid}")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_Analysis_GetAllGIDs_0(annotatedContext, inboundMarshaler, client, req, pathParams) + resp, md, err := request_Analysis_GetAnalysisByGID_0(annotatedContext, inboundMarshaler, client, req, pathParams) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_Analysis_GetAllGIDs_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Analysis_GetAnalysisByGID_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle(http.MethodPost, pattern_Analysis_GetParamsByID_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle(http.MethodPost, pattern_Analysis_GetAllGIDs_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/analysis.v1.Analysis/GetParamsByID", runtime.WithHTTPPathPattern("/api/runtime/params/{id}")) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/analysis.v1.Analysis/GetAllGIDs", runtime.WithHTTPPathPattern("/api/runtime/gids")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_Analysis_GetParamsByID_0(annotatedContext, inboundMarshaler, client, req, pathParams) + resp, md, err := request_Analysis_GetAllGIDs_0(annotatedContext, inboundMarshaler, client, req, pathParams) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_Analysis_GetParamsByID_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Analysis_GetAllGIDs_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle(http.MethodPost, pattern_Analysis_GetAllFunctionName_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle(http.MethodPost, pattern_Analysis_GetParamsByID_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/analysis.v1.Analysis/GetAllFunctionName", runtime.WithHTTPPathPattern("/api/runtime/functions")) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/analysis.v1.Analysis/GetParamsByID", runtime.WithHTTPPathPattern("/api/runtime/params/{id}")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_Analysis_GetAllFunctionName_0(annotatedContext, inboundMarshaler, client, req, pathParams) + resp, md, err := request_Analysis_GetParamsByID_0(annotatedContext, inboundMarshaler, client, req, pathParams) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_Analysis_GetAllFunctionName_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Analysis_GetParamsByID_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) mux.Handle(http.MethodPost, pattern_Analysis_GetGidsByFunctionName_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) @@ -1193,168 +1061,111 @@ func RegisterAnalysisHandlerClient(ctx context.Context, mux *runtime.ServeMux, c } forward_Analysis_GetGoroutineStats_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle(http.MethodPost, pattern_Analysis_GetFunctionAnalysis_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/analysis.v1.Analysis/GetFunctionAnalysis", runtime.WithHTTPPathPattern("/api/runtime/function/analysis")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Analysis_GetFunctionAnalysis_0(annotatedContext, inboundMarshaler, client, req, pathParams) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - forward_Analysis_GetFunctionAnalysis_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - }) - mux.Handle(http.MethodPost, pattern_Analysis_InstrumentProject_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/analysis.v1.Analysis/InstrumentProject", runtime.WithHTTPPathPattern("/api/runtime/instrument")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Analysis_InstrumentProject_0(annotatedContext, inboundMarshaler, client, req, pathParams) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - forward_Analysis_InstrumentProject_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - }) - mux.Handle(http.MethodPost, pattern_Analysis_GetTreeGraph_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/analysis.v1.Analysis/GetTreeGraph", runtime.WithHTTPPathPattern("/api/runtime/tree-graph")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Analysis_GetTreeGraph_0(annotatedContext, inboundMarshaler, client, req, pathParams) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - forward_Analysis_GetTreeGraph_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - }) - mux.Handle(http.MethodPost, pattern_Analysis_GetTreeGraphByGID_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle(http.MethodPost, pattern_Analysis_GetFunctionCallStats_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/analysis.v1.Analysis/GetTreeGraphByGID", runtime.WithHTTPPathPattern("/api/runtime/tree-graph/gid")) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/analysis.v1.Analysis/GetFunctionCallStats", runtime.WithHTTPPathPattern("/api/runtime/function/stats")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_Analysis_GetTreeGraphByGID_0(annotatedContext, inboundMarshaler, client, req, pathParams) + resp, md, err := request_Analysis_GetFunctionCallStats_0(annotatedContext, inboundMarshaler, client, req, pathParams) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_Analysis_GetTreeGraphByGID_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Analysis_GetFunctionCallStats_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle(http.MethodPost, pattern_Analysis_GetFunctionCallStats_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle(http.MethodPost, pattern_Analysis_SearchFunctions_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/analysis.v1.Analysis/GetFunctionCallStats", runtime.WithHTTPPathPattern("/api/runtime/function/stats")) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/analysis.v1.Analysis/SearchFunctions", runtime.WithHTTPPathPattern("/api/runtime/functions/search")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_Analysis_GetFunctionCallStats_0(annotatedContext, inboundMarshaler, client, req, pathParams) + resp, md, err := request_Analysis_SearchFunctions_0(annotatedContext, inboundMarshaler, client, req, pathParams) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_Analysis_GetFunctionCallStats_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Analysis_SearchFunctions_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle(http.MethodPost, pattern_Analysis_GetPerformanceAnomalies_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle(http.MethodPost, pattern_Analysis_GetFunctionInfoInGoroutine_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/analysis.v1.Analysis/GetPerformanceAnomalies", runtime.WithHTTPPathPattern("/api/runtime/function/anomalies")) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/analysis.v1.Analysis/GetFunctionInfoInGoroutine", runtime.WithHTTPPathPattern("/api/runtime/function/info")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_Analysis_GetPerformanceAnomalies_0(annotatedContext, inboundMarshaler, client, req, pathParams) + resp, md, err := request_Analysis_GetFunctionInfoInGoroutine_0(annotatedContext, inboundMarshaler, client, req, pathParams) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_Analysis_GetPerformanceAnomalies_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Analysis_GetFunctionInfoInGoroutine_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle(http.MethodPost, pattern_Analysis_SearchFunctions_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle(http.MethodPost, pattern_Analysis_GetModuleNames_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/analysis.v1.Analysis/SearchFunctions", runtime.WithHTTPPathPattern("/api/runtime/functions/search")) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/analysis.v1.Analysis/GetModuleNames", runtime.WithHTTPPathPattern("/api/runtime/modules")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_Analysis_SearchFunctions_0(annotatedContext, inboundMarshaler, client, req, pathParams) + resp, md, err := request_Analysis_GetModuleNames_0(annotatedContext, inboundMarshaler, client, req, pathParams) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_Analysis_SearchFunctions_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Analysis_GetModuleNames_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) return nil } var ( - pattern_Analysis_GetAnalysis_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1}, []string{"analysis", "name"}, "")) - pattern_Analysis_GetAnalysisByGID_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "runtime", "traces", "gid"}, "")) - pattern_Analysis_GetAllGIDs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "runtime", "gids"}, "")) - pattern_Analysis_GetParamsByID_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "runtime", "params", "id"}, "")) - pattern_Analysis_GetAllFunctionName_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "runtime", "functions"}, "")) - pattern_Analysis_GetGidsByFunctionName_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "runtime", "gids", "function"}, "")) - pattern_Analysis_VerifyProjectPath_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "runtime", "verify", "path"}, "")) - pattern_Analysis_GetTracesByParentFunc_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"api", "runtime", "traces", "parent", "parentId"}, "")) - pattern_Analysis_GetParentFunctions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "runtime", "functions", "parents"}, "")) - pattern_Analysis_GetChildFunctions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "runtime", "functions", "children"}, "")) - pattern_Analysis_GetHotFunctions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "runtime", "hot-functions"}, "")) - pattern_Analysis_GetGoroutineStats_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "runtime", "goroutine-stats"}, "")) - pattern_Analysis_GetFunctionAnalysis_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "runtime", "function", "analysis"}, "")) - pattern_Analysis_InstrumentProject_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "runtime", "instrument"}, "")) - pattern_Analysis_GetTreeGraph_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "runtime", "tree-graph"}, "")) - pattern_Analysis_GetTreeGraphByGID_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "runtime", "tree-graph", "gid"}, "")) - pattern_Analysis_GetFunctionCallStats_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "runtime", "function", "stats"}, "")) - pattern_Analysis_GetPerformanceAnomalies_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "runtime", "function", "anomalies"}, "")) - pattern_Analysis_SearchFunctions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "runtime", "functions", "search"}, "")) + pattern_Analysis_GetAnalysis_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1}, []string{"analysis", "name"}, "")) + pattern_Analysis_InstrumentProject_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "runtime", "instrument"}, "")) + pattern_Analysis_GetAnalysisByGID_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "runtime", "traces", "gid"}, "")) + pattern_Analysis_GetAllGIDs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "runtime", "gids"}, "")) + pattern_Analysis_GetParamsByID_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "runtime", "params", "id"}, "")) + pattern_Analysis_GetGidsByFunctionName_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "runtime", "gids", "function"}, "")) + pattern_Analysis_VerifyProjectPath_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "runtime", "verify", "path"}, "")) + pattern_Analysis_GetTracesByParentFunc_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"api", "runtime", "traces", "parent", "parentId"}, "")) + pattern_Analysis_GetParentFunctions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "runtime", "functions", "parents"}, "")) + pattern_Analysis_GetChildFunctions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "runtime", "functions", "children"}, "")) + pattern_Analysis_GetHotFunctions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "runtime", "hot-functions"}, "")) + pattern_Analysis_GetGoroutineStats_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "runtime", "goroutine-stats"}, "")) + pattern_Analysis_GetFunctionCallStats_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "runtime", "function", "stats"}, "")) + pattern_Analysis_SearchFunctions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "runtime", "functions", "search"}, "")) + pattern_Analysis_GetFunctionInfoInGoroutine_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "runtime", "function", "info"}, "")) + pattern_Analysis_GetModuleNames_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "runtime", "modules"}, "")) ) var ( - forward_Analysis_GetAnalysis_0 = runtime.ForwardResponseMessage - forward_Analysis_GetAnalysisByGID_0 = runtime.ForwardResponseMessage - forward_Analysis_GetAllGIDs_0 = runtime.ForwardResponseMessage - forward_Analysis_GetParamsByID_0 = runtime.ForwardResponseMessage - forward_Analysis_GetAllFunctionName_0 = runtime.ForwardResponseMessage - forward_Analysis_GetGidsByFunctionName_0 = runtime.ForwardResponseMessage - forward_Analysis_VerifyProjectPath_0 = runtime.ForwardResponseMessage - forward_Analysis_GetTracesByParentFunc_0 = runtime.ForwardResponseMessage - forward_Analysis_GetParentFunctions_0 = runtime.ForwardResponseMessage - forward_Analysis_GetChildFunctions_0 = runtime.ForwardResponseMessage - forward_Analysis_GetHotFunctions_0 = runtime.ForwardResponseMessage - forward_Analysis_GetGoroutineStats_0 = runtime.ForwardResponseMessage - forward_Analysis_GetFunctionAnalysis_0 = runtime.ForwardResponseMessage - forward_Analysis_InstrumentProject_0 = runtime.ForwardResponseMessage - forward_Analysis_GetTreeGraph_0 = runtime.ForwardResponseMessage - forward_Analysis_GetTreeGraphByGID_0 = runtime.ForwardResponseMessage - forward_Analysis_GetFunctionCallStats_0 = runtime.ForwardResponseMessage - forward_Analysis_GetPerformanceAnomalies_0 = runtime.ForwardResponseMessage - forward_Analysis_SearchFunctions_0 = runtime.ForwardResponseMessage + forward_Analysis_GetAnalysis_0 = runtime.ForwardResponseMessage + forward_Analysis_InstrumentProject_0 = runtime.ForwardResponseMessage + forward_Analysis_GetAnalysisByGID_0 = runtime.ForwardResponseMessage + forward_Analysis_GetAllGIDs_0 = runtime.ForwardResponseMessage + forward_Analysis_GetParamsByID_0 = runtime.ForwardResponseMessage + forward_Analysis_GetGidsByFunctionName_0 = runtime.ForwardResponseMessage + forward_Analysis_VerifyProjectPath_0 = runtime.ForwardResponseMessage + forward_Analysis_GetTracesByParentFunc_0 = runtime.ForwardResponseMessage + forward_Analysis_GetParentFunctions_0 = runtime.ForwardResponseMessage + forward_Analysis_GetChildFunctions_0 = runtime.ForwardResponseMessage + forward_Analysis_GetHotFunctions_0 = runtime.ForwardResponseMessage + forward_Analysis_GetGoroutineStats_0 = runtime.ForwardResponseMessage + forward_Analysis_GetFunctionCallStats_0 = runtime.ForwardResponseMessage + forward_Analysis_SearchFunctions_0 = runtime.ForwardResponseMessage + forward_Analysis_GetFunctionInfoInGoroutine_0 = runtime.ForwardResponseMessage + forward_Analysis_GetModuleNames_0 = runtime.ForwardResponseMessage ) diff --git a/api/analysis/v1/analysis.proto b/api/analysis/v1/analysis.proto index 986a0ac..bddea6f 100644 --- a/api/analysis/v1/analysis.proto +++ b/api/analysis/v1/analysis.proto @@ -16,6 +16,14 @@ service Analysis { }; } + // InstrumentProject 对项目进行插桩 + rpc InstrumentProject(InstrumentProjectReq) returns (InstrumentProjectReply) { + option (google.api.http) = { + post: "/api/runtime/instrument" + body: "*" + }; + } + rpc GetAnalysisByGID (AnalysisByGIDRequest) returns (AnalysisByGIDReply) { option (google.api.http) = { post: "/api/runtime/traces/{gid}" @@ -36,12 +44,6 @@ service Analysis { }; } - rpc GetAllFunctionName (GetAllFunctionNameReq) returns (GetAllFunctionNameReply) { - option (google.api.http) = { - post: "/api/runtime/functions" - body: "*" - }; - } rpc GetGidsByFunctionName (GetGidsByFunctionNameReq) returns (GetGidsByFunctionNameReply) { option (google.api.http) = { post: "/api/runtime/gids/function" @@ -96,63 +98,36 @@ service Analysis { }; } - // GetFunctionAnalysis 获取函数调用关系分析 - rpc GetFunctionAnalysis(GetFunctionAnalysisReq) returns (GetFunctionAnalysisReply) { - option (google.api.http) = { - post: "/api/runtime/function/analysis" - body: "*" - }; - } - - - // InstrumentProject 对项目进行插桩 - rpc InstrumentProject(InstrumentProjectReq) returns (InstrumentProjectReply) { + + // GetFunctionCallStats 获取函数调用统计分析 + rpc GetFunctionCallStats(GetFunctionCallStatsReq) returns (GetFunctionCallStatsReply) { option (google.api.http) = { - post: "/api/runtime/instrument" + post: "/api/runtime/function/stats" body: "*" }; } - - - // 获取运行时树状图数据 - rpc GetTreeGraph (GetTreeGraphReq) returns (GetTreeGraphReply) { + // SearchFunctions 搜索函数 + rpc SearchFunctions(SearchFunctionsReq) returns (SearchFunctionsReply) { option (google.api.http) = { - post: "/api/runtime/tree-graph" + post: "/api/runtime/functions/search" body: "*" }; } - // 根据GID获取多棵树状图数据 - rpc GetTreeGraphByGID (GetTreeGraphByGIDReq) returns (GetTreeGraphByGIDReply) { - option (google.api.http) = { - post: "/api/runtime/tree-graph/gid" - body: "*" - }; - } - - - // GetFunctionCallStats 获取函数调用统计分析 - rpc GetFunctionCallStats(GetFunctionCallStatsReq) returns (GetFunctionCallStatsReply) { - option (google.api.http) = { - post: "/api/runtime/function/stats" - body: "*" - }; - } - - // GetPerformanceAnomalies 获取性能异常检测结果 - rpc GetPerformanceAnomalies(GetPerformanceAnomaliesReq) returns (GetPerformanceAnomaliesReply) { + // GetFunctionInfoInGoroutine 获取函数在指定Goroutine中的信息 + rpc GetFunctionInfoInGoroutine(GetFunctionInfoInGoroutineReq) returns (GetFunctionInfoInGoroutineReply) { option (google.api.http) = { - post: "/api/runtime/function/anomalies" + post: "/api/runtime/function/info" body: "*" }; } - // SearchFunctions 搜索函数 - rpc SearchFunctions(SearchFunctionsReq) returns (SearchFunctionsReply) { + // GetModuleNames 获取数据库中的模块名称列表 + rpc GetModuleNames(GetModuleNamesReq) returns (GetModuleNamesReply) { option (google.api.http) = { - post: "/api/runtime/functions/search" + post: "/api/runtime/modules" body: "*" }; } @@ -180,6 +155,7 @@ message GetGidsByFunctionNameReply { int32 depth = 3; // 调用深度 string executionTime = 4; // 执行时间 bool isFinished = 5; // 是否完成 + int64 functionId = 6; // 函数ID } repeated Body body = 1; int32 total = 2; // 总的 GID 数量 @@ -542,9 +518,44 @@ message SearchFunctionsReply { message FunctionInfo { string name = 1; // 函数名称 string package = 2; // 包名 - int32 callCount = 3; // 调用次数 - string avgTime = 4; // 平均执行时间 } repeated FunctionInfo functions = 1; // 搜索到的函数列表 int32 total = 2; // 总匹配数量 } + +// GetFunctionInfoInGoroutineReq 获取函数在指定Goroutine中的信息请求 +message GetFunctionInfoInGoroutineReq { + string dbpath = 1; // 数据库路径 + uint64 gid = 2; // Goroutine ID + int64 functionId = 3; // 目标函数ID + int32 currentDepth = 4; // 当前显示深度 +} + +// ParentInfo 父函数信息 +message ParentInfo { + int64 parentId = 1; // 父函数ID + string name = 2; // 父函数名称 + int32 depth = 3; // 深度 +} + +// GetFunctionInfoInGoroutineReply 获取函数在指定Goroutine中的信息响应 +message GetFunctionInfoInGoroutineReply { + message FunctionInfo { + int64 id = 1; // 函数ID + string name = 2; // 函数名称 + int32 depth = 3; // 函数在调用链中的实际深度 + repeated ParentInfo parentIds = 4; // 父函数ID+深度列表(去重) + } + FunctionInfo functionInfo = 1; +} + +// GetModuleNamesReq 获取模块名称请求 +message GetModuleNamesReq { + string dbpath = 1; // 数据库路径 + int32 maxSamples = 2; // 最大采样数量,默认5000 +} + +// GetModuleNamesReply 获取模块名称响应 +message GetModuleNamesReply { + repeated string moduleNames = 1; // 前5个最频繁的模块名称(按频率排序) +} diff --git a/api/analysis/v1/analysis_grpc.pb.go b/api/analysis/v1/analysis_grpc.pb.go index e17e1f3..aa2a3ac 100644 --- a/api/analysis/v1/analysis_grpc.pb.go +++ b/api/analysis/v1/analysis_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.5.1 -// - protoc v6.31.1 +// - protoc v6.30.2 // source: analysis/v1/analysis.proto package v1 @@ -19,25 +19,22 @@ import ( const _ = grpc.SupportPackageIsVersion9 const ( - Analysis_GetAnalysis_FullMethodName = "/analysis.v1.Analysis/GetAnalysis" - Analysis_GetAnalysisByGID_FullMethodName = "/analysis.v1.Analysis/GetAnalysisByGID" - Analysis_GetAllGIDs_FullMethodName = "/analysis.v1.Analysis/GetAllGIDs" - Analysis_GetParamsByID_FullMethodName = "/analysis.v1.Analysis/GetParamsByID" - Analysis_GetAllFunctionName_FullMethodName = "/analysis.v1.Analysis/GetAllFunctionName" - Analysis_GetGidsByFunctionName_FullMethodName = "/analysis.v1.Analysis/GetGidsByFunctionName" - Analysis_VerifyProjectPath_FullMethodName = "/analysis.v1.Analysis/VerifyProjectPath" - Analysis_GetTracesByParentFunc_FullMethodName = "/analysis.v1.Analysis/GetTracesByParentFunc" - Analysis_GetParentFunctions_FullMethodName = "/analysis.v1.Analysis/GetParentFunctions" - Analysis_GetChildFunctions_FullMethodName = "/analysis.v1.Analysis/GetChildFunctions" - Analysis_GetHotFunctions_FullMethodName = "/analysis.v1.Analysis/GetHotFunctions" - Analysis_GetGoroutineStats_FullMethodName = "/analysis.v1.Analysis/GetGoroutineStats" - Analysis_GetFunctionAnalysis_FullMethodName = "/analysis.v1.Analysis/GetFunctionAnalysis" - Analysis_InstrumentProject_FullMethodName = "/analysis.v1.Analysis/InstrumentProject" - Analysis_GetTreeGraph_FullMethodName = "/analysis.v1.Analysis/GetTreeGraph" - Analysis_GetTreeGraphByGID_FullMethodName = "/analysis.v1.Analysis/GetTreeGraphByGID" - Analysis_GetFunctionCallStats_FullMethodName = "/analysis.v1.Analysis/GetFunctionCallStats" - Analysis_GetPerformanceAnomalies_FullMethodName = "/analysis.v1.Analysis/GetPerformanceAnomalies" - Analysis_SearchFunctions_FullMethodName = "/analysis.v1.Analysis/SearchFunctions" + Analysis_GetAnalysis_FullMethodName = "/analysis.v1.Analysis/GetAnalysis" + Analysis_InstrumentProject_FullMethodName = "/analysis.v1.Analysis/InstrumentProject" + Analysis_GetAnalysisByGID_FullMethodName = "/analysis.v1.Analysis/GetAnalysisByGID" + Analysis_GetAllGIDs_FullMethodName = "/analysis.v1.Analysis/GetAllGIDs" + Analysis_GetParamsByID_FullMethodName = "/analysis.v1.Analysis/GetParamsByID" + Analysis_GetGidsByFunctionName_FullMethodName = "/analysis.v1.Analysis/GetGidsByFunctionName" + Analysis_VerifyProjectPath_FullMethodName = "/analysis.v1.Analysis/VerifyProjectPath" + Analysis_GetTracesByParentFunc_FullMethodName = "/analysis.v1.Analysis/GetTracesByParentFunc" + Analysis_GetParentFunctions_FullMethodName = "/analysis.v1.Analysis/GetParentFunctions" + Analysis_GetChildFunctions_FullMethodName = "/analysis.v1.Analysis/GetChildFunctions" + Analysis_GetHotFunctions_FullMethodName = "/analysis.v1.Analysis/GetHotFunctions" + Analysis_GetGoroutineStats_FullMethodName = "/analysis.v1.Analysis/GetGoroutineStats" + Analysis_GetFunctionCallStats_FullMethodName = "/analysis.v1.Analysis/GetFunctionCallStats" + Analysis_SearchFunctions_FullMethodName = "/analysis.v1.Analysis/SearchFunctions" + Analysis_GetFunctionInfoInGoroutine_FullMethodName = "/analysis.v1.Analysis/GetFunctionInfoInGoroutine" + Analysis_GetModuleNames_FullMethodName = "/analysis.v1.Analysis/GetModuleNames" ) // AnalysisClient is the client API for Analysis service. @@ -48,10 +45,11 @@ const ( type AnalysisClient interface { // Sends a greeting GetAnalysis(ctx context.Context, in *AnalysisRequest, opts ...grpc.CallOption) (*AnalysisReply, error) + // InstrumentProject 对项目进行插桩 + InstrumentProject(ctx context.Context, in *InstrumentProjectReq, opts ...grpc.CallOption) (*InstrumentProjectReply, error) GetAnalysisByGID(ctx context.Context, in *AnalysisByGIDRequest, opts ...grpc.CallOption) (*AnalysisByGIDReply, error) GetAllGIDs(ctx context.Context, in *GetAllGIDsReq, opts ...grpc.CallOption) (*GetAllGIDsReply, error) GetParamsByID(ctx context.Context, in *GetParamsByIDReq, opts ...grpc.CallOption) (*GetParamsByIDReply, error) - GetAllFunctionName(ctx context.Context, in *GetAllFunctionNameReq, opts ...grpc.CallOption) (*GetAllFunctionNameReply, error) GetGidsByFunctionName(ctx context.Context, in *GetGidsByFunctionNameReq, opts ...grpc.CallOption) (*GetGidsByFunctionNameReply, error) // 将VerifyProjectPath重定向到CheckDatabase VerifyProjectPath(ctx context.Context, in *VerifyProjectPathReq, opts ...grpc.CallOption) (*VerifyProjectPathReply, error) @@ -65,20 +63,14 @@ type AnalysisClient interface { GetHotFunctions(ctx context.Context, in *GetHotFunctionsReq, opts ...grpc.CallOption) (*GetHotFunctionsReply, error) // GetGoroutineStats 获取Goroutine统计信息 GetGoroutineStats(ctx context.Context, in *GetGoroutineStatsReq, opts ...grpc.CallOption) (*GetGoroutineStatsReply, error) - // GetFunctionAnalysis 获取函数调用关系分析 - GetFunctionAnalysis(ctx context.Context, in *GetFunctionAnalysisReq, opts ...grpc.CallOption) (*GetFunctionAnalysisReply, error) - // InstrumentProject 对项目进行插桩 - InstrumentProject(ctx context.Context, in *InstrumentProjectReq, opts ...grpc.CallOption) (*InstrumentProjectReply, error) - // 获取运行时树状图数据 - GetTreeGraph(ctx context.Context, in *GetTreeGraphReq, opts ...grpc.CallOption) (*GetTreeGraphReply, error) - // 根据GID获取多棵树状图数据 - GetTreeGraphByGID(ctx context.Context, in *GetTreeGraphByGIDReq, opts ...grpc.CallOption) (*GetTreeGraphByGIDReply, error) // GetFunctionCallStats 获取函数调用统计分析 GetFunctionCallStats(ctx context.Context, in *GetFunctionCallStatsReq, opts ...grpc.CallOption) (*GetFunctionCallStatsReply, error) - // GetPerformanceAnomalies 获取性能异常检测结果 - GetPerformanceAnomalies(ctx context.Context, in *GetPerformanceAnomaliesReq, opts ...grpc.CallOption) (*GetPerformanceAnomaliesReply, error) // SearchFunctions 搜索函数 SearchFunctions(ctx context.Context, in *SearchFunctionsReq, opts ...grpc.CallOption) (*SearchFunctionsReply, error) + // GetFunctionInfoInGoroutine 获取函数在指定Goroutine中的信息 + GetFunctionInfoInGoroutine(ctx context.Context, in *GetFunctionInfoInGoroutineReq, opts ...grpc.CallOption) (*GetFunctionInfoInGoroutineReply, error) + // GetModuleNames 获取数据库中的模块名称列表 + GetModuleNames(ctx context.Context, in *GetModuleNamesReq, opts ...grpc.CallOption) (*GetModuleNamesReply, error) } type analysisClient struct { @@ -99,6 +91,16 @@ func (c *analysisClient) GetAnalysis(ctx context.Context, in *AnalysisRequest, o return out, nil } +func (c *analysisClient) InstrumentProject(ctx context.Context, in *InstrumentProjectReq, opts ...grpc.CallOption) (*InstrumentProjectReply, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(InstrumentProjectReply) + err := c.cc.Invoke(ctx, Analysis_InstrumentProject_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *analysisClient) GetAnalysisByGID(ctx context.Context, in *AnalysisByGIDRequest, opts ...grpc.CallOption) (*AnalysisByGIDReply, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(AnalysisByGIDReply) @@ -129,16 +131,6 @@ func (c *analysisClient) GetParamsByID(ctx context.Context, in *GetParamsByIDReq return out, nil } -func (c *analysisClient) GetAllFunctionName(ctx context.Context, in *GetAllFunctionNameReq, opts ...grpc.CallOption) (*GetAllFunctionNameReply, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(GetAllFunctionNameReply) - err := c.cc.Invoke(ctx, Analysis_GetAllFunctionName_FullMethodName, in, out, cOpts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *analysisClient) GetGidsByFunctionName(ctx context.Context, in *GetGidsByFunctionNameReq, opts ...grpc.CallOption) (*GetGidsByFunctionNameReply, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetGidsByFunctionNameReply) @@ -209,70 +201,40 @@ func (c *analysisClient) GetGoroutineStats(ctx context.Context, in *GetGoroutine return out, nil } -func (c *analysisClient) GetFunctionAnalysis(ctx context.Context, in *GetFunctionAnalysisReq, opts ...grpc.CallOption) (*GetFunctionAnalysisReply, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(GetFunctionAnalysisReply) - err := c.cc.Invoke(ctx, Analysis_GetFunctionAnalysis_FullMethodName, in, out, cOpts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *analysisClient) InstrumentProject(ctx context.Context, in *InstrumentProjectReq, opts ...grpc.CallOption) (*InstrumentProjectReply, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(InstrumentProjectReply) - err := c.cc.Invoke(ctx, Analysis_InstrumentProject_FullMethodName, in, out, cOpts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *analysisClient) GetTreeGraph(ctx context.Context, in *GetTreeGraphReq, opts ...grpc.CallOption) (*GetTreeGraphReply, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(GetTreeGraphReply) - err := c.cc.Invoke(ctx, Analysis_GetTreeGraph_FullMethodName, in, out, cOpts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *analysisClient) GetTreeGraphByGID(ctx context.Context, in *GetTreeGraphByGIDReq, opts ...grpc.CallOption) (*GetTreeGraphByGIDReply, error) { +func (c *analysisClient) GetFunctionCallStats(ctx context.Context, in *GetFunctionCallStatsReq, opts ...grpc.CallOption) (*GetFunctionCallStatsReply, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(GetTreeGraphByGIDReply) - err := c.cc.Invoke(ctx, Analysis_GetTreeGraphByGID_FullMethodName, in, out, cOpts...) + out := new(GetFunctionCallStatsReply) + err := c.cc.Invoke(ctx, Analysis_GetFunctionCallStats_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } -func (c *analysisClient) GetFunctionCallStats(ctx context.Context, in *GetFunctionCallStatsReq, opts ...grpc.CallOption) (*GetFunctionCallStatsReply, error) { +func (c *analysisClient) SearchFunctions(ctx context.Context, in *SearchFunctionsReq, opts ...grpc.CallOption) (*SearchFunctionsReply, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(GetFunctionCallStatsReply) - err := c.cc.Invoke(ctx, Analysis_GetFunctionCallStats_FullMethodName, in, out, cOpts...) + out := new(SearchFunctionsReply) + err := c.cc.Invoke(ctx, Analysis_SearchFunctions_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } -func (c *analysisClient) GetPerformanceAnomalies(ctx context.Context, in *GetPerformanceAnomaliesReq, opts ...grpc.CallOption) (*GetPerformanceAnomaliesReply, error) { +func (c *analysisClient) GetFunctionInfoInGoroutine(ctx context.Context, in *GetFunctionInfoInGoroutineReq, opts ...grpc.CallOption) (*GetFunctionInfoInGoroutineReply, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(GetPerformanceAnomaliesReply) - err := c.cc.Invoke(ctx, Analysis_GetPerformanceAnomalies_FullMethodName, in, out, cOpts...) + out := new(GetFunctionInfoInGoroutineReply) + err := c.cc.Invoke(ctx, Analysis_GetFunctionInfoInGoroutine_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } -func (c *analysisClient) SearchFunctions(ctx context.Context, in *SearchFunctionsReq, opts ...grpc.CallOption) (*SearchFunctionsReply, error) { +func (c *analysisClient) GetModuleNames(ctx context.Context, in *GetModuleNamesReq, opts ...grpc.CallOption) (*GetModuleNamesReply, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(SearchFunctionsReply) - err := c.cc.Invoke(ctx, Analysis_SearchFunctions_FullMethodName, in, out, cOpts...) + out := new(GetModuleNamesReply) + err := c.cc.Invoke(ctx, Analysis_GetModuleNames_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -287,10 +249,11 @@ func (c *analysisClient) SearchFunctions(ctx context.Context, in *SearchFunction type AnalysisServer interface { // Sends a greeting GetAnalysis(context.Context, *AnalysisRequest) (*AnalysisReply, error) + // InstrumentProject 对项目进行插桩 + InstrumentProject(context.Context, *InstrumentProjectReq) (*InstrumentProjectReply, error) GetAnalysisByGID(context.Context, *AnalysisByGIDRequest) (*AnalysisByGIDReply, error) GetAllGIDs(context.Context, *GetAllGIDsReq) (*GetAllGIDsReply, error) GetParamsByID(context.Context, *GetParamsByIDReq) (*GetParamsByIDReply, error) - GetAllFunctionName(context.Context, *GetAllFunctionNameReq) (*GetAllFunctionNameReply, error) GetGidsByFunctionName(context.Context, *GetGidsByFunctionNameReq) (*GetGidsByFunctionNameReply, error) // 将VerifyProjectPath重定向到CheckDatabase VerifyProjectPath(context.Context, *VerifyProjectPathReq) (*VerifyProjectPathReply, error) @@ -304,20 +267,14 @@ type AnalysisServer interface { GetHotFunctions(context.Context, *GetHotFunctionsReq) (*GetHotFunctionsReply, error) // GetGoroutineStats 获取Goroutine统计信息 GetGoroutineStats(context.Context, *GetGoroutineStatsReq) (*GetGoroutineStatsReply, error) - // GetFunctionAnalysis 获取函数调用关系分析 - GetFunctionAnalysis(context.Context, *GetFunctionAnalysisReq) (*GetFunctionAnalysisReply, error) - // InstrumentProject 对项目进行插桩 - InstrumentProject(context.Context, *InstrumentProjectReq) (*InstrumentProjectReply, error) - // 获取运行时树状图数据 - GetTreeGraph(context.Context, *GetTreeGraphReq) (*GetTreeGraphReply, error) - // 根据GID获取多棵树状图数据 - GetTreeGraphByGID(context.Context, *GetTreeGraphByGIDReq) (*GetTreeGraphByGIDReply, error) // GetFunctionCallStats 获取函数调用统计分析 GetFunctionCallStats(context.Context, *GetFunctionCallStatsReq) (*GetFunctionCallStatsReply, error) - // GetPerformanceAnomalies 获取性能异常检测结果 - GetPerformanceAnomalies(context.Context, *GetPerformanceAnomaliesReq) (*GetPerformanceAnomaliesReply, error) // SearchFunctions 搜索函数 SearchFunctions(context.Context, *SearchFunctionsReq) (*SearchFunctionsReply, error) + // GetFunctionInfoInGoroutine 获取函数在指定Goroutine中的信息 + GetFunctionInfoInGoroutine(context.Context, *GetFunctionInfoInGoroutineReq) (*GetFunctionInfoInGoroutineReply, error) + // GetModuleNames 获取数据库中的模块名称列表 + GetModuleNames(context.Context, *GetModuleNamesReq) (*GetModuleNamesReply, error) mustEmbedUnimplementedAnalysisServer() } @@ -331,6 +288,9 @@ type UnimplementedAnalysisServer struct{} func (UnimplementedAnalysisServer) GetAnalysis(context.Context, *AnalysisRequest) (*AnalysisReply, error) { return nil, status.Errorf(codes.Unimplemented, "method GetAnalysis not implemented") } +func (UnimplementedAnalysisServer) InstrumentProject(context.Context, *InstrumentProjectReq) (*InstrumentProjectReply, error) { + return nil, status.Errorf(codes.Unimplemented, "method InstrumentProject not implemented") +} func (UnimplementedAnalysisServer) GetAnalysisByGID(context.Context, *AnalysisByGIDRequest) (*AnalysisByGIDReply, error) { return nil, status.Errorf(codes.Unimplemented, "method GetAnalysisByGID not implemented") } @@ -340,9 +300,6 @@ func (UnimplementedAnalysisServer) GetAllGIDs(context.Context, *GetAllGIDsReq) ( func (UnimplementedAnalysisServer) GetParamsByID(context.Context, *GetParamsByIDReq) (*GetParamsByIDReply, error) { return nil, status.Errorf(codes.Unimplemented, "method GetParamsByID not implemented") } -func (UnimplementedAnalysisServer) GetAllFunctionName(context.Context, *GetAllFunctionNameReq) (*GetAllFunctionNameReply, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetAllFunctionName not implemented") -} func (UnimplementedAnalysisServer) GetGidsByFunctionName(context.Context, *GetGidsByFunctionNameReq) (*GetGidsByFunctionNameReply, error) { return nil, status.Errorf(codes.Unimplemented, "method GetGidsByFunctionName not implemented") } @@ -364,27 +321,18 @@ func (UnimplementedAnalysisServer) GetHotFunctions(context.Context, *GetHotFunct func (UnimplementedAnalysisServer) GetGoroutineStats(context.Context, *GetGoroutineStatsReq) (*GetGoroutineStatsReply, error) { return nil, status.Errorf(codes.Unimplemented, "method GetGoroutineStats not implemented") } -func (UnimplementedAnalysisServer) GetFunctionAnalysis(context.Context, *GetFunctionAnalysisReq) (*GetFunctionAnalysisReply, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetFunctionAnalysis not implemented") -} -func (UnimplementedAnalysisServer) InstrumentProject(context.Context, *InstrumentProjectReq) (*InstrumentProjectReply, error) { - return nil, status.Errorf(codes.Unimplemented, "method InstrumentProject not implemented") -} -func (UnimplementedAnalysisServer) GetTreeGraph(context.Context, *GetTreeGraphReq) (*GetTreeGraphReply, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetTreeGraph not implemented") -} -func (UnimplementedAnalysisServer) GetTreeGraphByGID(context.Context, *GetTreeGraphByGIDReq) (*GetTreeGraphByGIDReply, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetTreeGraphByGID not implemented") -} func (UnimplementedAnalysisServer) GetFunctionCallStats(context.Context, *GetFunctionCallStatsReq) (*GetFunctionCallStatsReply, error) { return nil, status.Errorf(codes.Unimplemented, "method GetFunctionCallStats not implemented") } -func (UnimplementedAnalysisServer) GetPerformanceAnomalies(context.Context, *GetPerformanceAnomaliesReq) (*GetPerformanceAnomaliesReply, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetPerformanceAnomalies not implemented") -} func (UnimplementedAnalysisServer) SearchFunctions(context.Context, *SearchFunctionsReq) (*SearchFunctionsReply, error) { return nil, status.Errorf(codes.Unimplemented, "method SearchFunctions not implemented") } +func (UnimplementedAnalysisServer) GetFunctionInfoInGoroutine(context.Context, *GetFunctionInfoInGoroutineReq) (*GetFunctionInfoInGoroutineReply, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetFunctionInfoInGoroutine not implemented") +} +func (UnimplementedAnalysisServer) GetModuleNames(context.Context, *GetModuleNamesReq) (*GetModuleNamesReply, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetModuleNames not implemented") +} func (UnimplementedAnalysisServer) mustEmbedUnimplementedAnalysisServer() {} func (UnimplementedAnalysisServer) testEmbeddedByValue() {} @@ -424,6 +372,24 @@ func _Analysis_GetAnalysis_Handler(srv interface{}, ctx context.Context, dec fun return interceptor(ctx, in, info, handler) } +func _Analysis_InstrumentProject_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(InstrumentProjectReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AnalysisServer).InstrumentProject(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Analysis_InstrumentProject_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AnalysisServer).InstrumentProject(ctx, req.(*InstrumentProjectReq)) + } + return interceptor(ctx, in, info, handler) +} + func _Analysis_GetAnalysisByGID_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(AnalysisByGIDRequest) if err := dec(in); err != nil { @@ -478,24 +444,6 @@ func _Analysis_GetParamsByID_Handler(srv interface{}, ctx context.Context, dec f return interceptor(ctx, in, info, handler) } -func _Analysis_GetAllFunctionName_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GetAllFunctionNameReq) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(AnalysisServer).GetAllFunctionName(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: Analysis_GetAllFunctionName_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(AnalysisServer).GetAllFunctionName(ctx, req.(*GetAllFunctionNameReq)) - } - return interceptor(ctx, in, info, handler) -} - func _Analysis_GetGidsByFunctionName_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(GetGidsByFunctionNameReq) if err := dec(in); err != nil { @@ -622,128 +570,74 @@ func _Analysis_GetGoroutineStats_Handler(srv interface{}, ctx context.Context, d return interceptor(ctx, in, info, handler) } -func _Analysis_GetFunctionAnalysis_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GetFunctionAnalysisReq) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(AnalysisServer).GetFunctionAnalysis(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: Analysis_GetFunctionAnalysis_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(AnalysisServer).GetFunctionAnalysis(ctx, req.(*GetFunctionAnalysisReq)) - } - return interceptor(ctx, in, info, handler) -} - -func _Analysis_InstrumentProject_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(InstrumentProjectReq) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(AnalysisServer).InstrumentProject(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: Analysis_InstrumentProject_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(AnalysisServer).InstrumentProject(ctx, req.(*InstrumentProjectReq)) - } - return interceptor(ctx, in, info, handler) -} - -func _Analysis_GetTreeGraph_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GetTreeGraphReq) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(AnalysisServer).GetTreeGraph(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: Analysis_GetTreeGraph_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(AnalysisServer).GetTreeGraph(ctx, req.(*GetTreeGraphReq)) - } - return interceptor(ctx, in, info, handler) -} - -func _Analysis_GetTreeGraphByGID_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GetTreeGraphByGIDReq) +func _Analysis_GetFunctionCallStats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetFunctionCallStatsReq) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(AnalysisServer).GetTreeGraphByGID(ctx, in) + return srv.(AnalysisServer).GetFunctionCallStats(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Analysis_GetTreeGraphByGID_FullMethodName, + FullMethod: Analysis_GetFunctionCallStats_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(AnalysisServer).GetTreeGraphByGID(ctx, req.(*GetTreeGraphByGIDReq)) + return srv.(AnalysisServer).GetFunctionCallStats(ctx, req.(*GetFunctionCallStatsReq)) } return interceptor(ctx, in, info, handler) } -func _Analysis_GetFunctionCallStats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GetFunctionCallStatsReq) +func _Analysis_SearchFunctions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SearchFunctionsReq) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(AnalysisServer).GetFunctionCallStats(ctx, in) + return srv.(AnalysisServer).SearchFunctions(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Analysis_GetFunctionCallStats_FullMethodName, + FullMethod: Analysis_SearchFunctions_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(AnalysisServer).GetFunctionCallStats(ctx, req.(*GetFunctionCallStatsReq)) + return srv.(AnalysisServer).SearchFunctions(ctx, req.(*SearchFunctionsReq)) } return interceptor(ctx, in, info, handler) } -func _Analysis_GetPerformanceAnomalies_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GetPerformanceAnomaliesReq) +func _Analysis_GetFunctionInfoInGoroutine_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetFunctionInfoInGoroutineReq) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(AnalysisServer).GetPerformanceAnomalies(ctx, in) + return srv.(AnalysisServer).GetFunctionInfoInGoroutine(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Analysis_GetPerformanceAnomalies_FullMethodName, + FullMethod: Analysis_GetFunctionInfoInGoroutine_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(AnalysisServer).GetPerformanceAnomalies(ctx, req.(*GetPerformanceAnomaliesReq)) + return srv.(AnalysisServer).GetFunctionInfoInGoroutine(ctx, req.(*GetFunctionInfoInGoroutineReq)) } return interceptor(ctx, in, info, handler) } -func _Analysis_SearchFunctions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(SearchFunctionsReq) +func _Analysis_GetModuleNames_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetModuleNamesReq) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(AnalysisServer).SearchFunctions(ctx, in) + return srv.(AnalysisServer).GetModuleNames(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Analysis_SearchFunctions_FullMethodName, + FullMethod: Analysis_GetModuleNames_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(AnalysisServer).SearchFunctions(ctx, req.(*SearchFunctionsReq)) + return srv.(AnalysisServer).GetModuleNames(ctx, req.(*GetModuleNamesReq)) } return interceptor(ctx, in, info, handler) } @@ -759,6 +653,10 @@ var Analysis_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetAnalysis", Handler: _Analysis_GetAnalysis_Handler, }, + { + MethodName: "InstrumentProject", + Handler: _Analysis_InstrumentProject_Handler, + }, { MethodName: "GetAnalysisByGID", Handler: _Analysis_GetAnalysisByGID_Handler, @@ -771,10 +669,6 @@ var Analysis_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetParamsByID", Handler: _Analysis_GetParamsByID_Handler, }, - { - MethodName: "GetAllFunctionName", - Handler: _Analysis_GetAllFunctionName_Handler, - }, { MethodName: "GetGidsByFunctionName", Handler: _Analysis_GetGidsByFunctionName_Handler, @@ -803,34 +697,22 @@ var Analysis_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetGoroutineStats", Handler: _Analysis_GetGoroutineStats_Handler, }, - { - MethodName: "GetFunctionAnalysis", - Handler: _Analysis_GetFunctionAnalysis_Handler, - }, - { - MethodName: "InstrumentProject", - Handler: _Analysis_InstrumentProject_Handler, - }, - { - MethodName: "GetTreeGraph", - Handler: _Analysis_GetTreeGraph_Handler, - }, - { - MethodName: "GetTreeGraphByGID", - Handler: _Analysis_GetTreeGraphByGID_Handler, - }, { MethodName: "GetFunctionCallStats", Handler: _Analysis_GetFunctionCallStats_Handler, }, - { - MethodName: "GetPerformanceAnomalies", - Handler: _Analysis_GetPerformanceAnomalies_Handler, - }, { MethodName: "SearchFunctions", Handler: _Analysis_SearchFunctions_Handler, }, + { + MethodName: "GetFunctionInfoInGoroutine", + Handler: _Analysis_GetFunctionInfoInGoroutine_Handler, + }, + { + MethodName: "GetModuleNames", + Handler: _Analysis_GetModuleNames_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "analysis/v1/analysis.proto", diff --git a/api/analysis/v1/error_reason.pb.go b/api/analysis/v1/error_reason.pb.go index fe5cb71..2f0ba17 100644 --- a/api/analysis/v1/error_reason.pb.go +++ b/api/analysis/v1/error_reason.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.36.6 -// protoc v6.31.1 +// protoc v6.30.2 // source: analysis/v1/error_reason.proto package v1 diff --git a/api/filemanager/v1/filemanager.pb.go b/api/filemanager/v1/filemanager.pb.go index 4f43aad..be9179a 100644 --- a/api/filemanager/v1/filemanager.pb.go +++ b/api/filemanager/v1/filemanager.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.36.6 -// protoc v6.31.1 +// protoc v6.30.2 // source: filemanager/v1/filemanager.proto package v1 diff --git a/api/filemanager/v1/filemanager_grpc.pb.go b/api/filemanager/v1/filemanager_grpc.pb.go index 51d1e1d..debbb0c 100644 --- a/api/filemanager/v1/filemanager_grpc.pb.go +++ b/api/filemanager/v1/filemanager_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.5.1 -// - protoc v6.31.1 +// - protoc v6.30.2 // source: filemanager/v1/filemanager.proto package v1 diff --git a/api/staticanalysis/v1/staticanalysis.pb.go b/api/staticanalysis/v1/staticanalysis.pb.go index efbdfd8..2467a92 100644 --- a/api/staticanalysis/v1/staticanalysis.pb.go +++ b/api/staticanalysis/v1/staticanalysis.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.36.6 -// protoc v6.31.1 +// protoc v6.30.2 // source: staticanalysis/v1/staticanalysis.proto package v1 diff --git a/api/staticanalysis/v1/staticanalysis_grpc.pb.go b/api/staticanalysis/v1/staticanalysis_grpc.pb.go index 77e75ba..5148aee 100644 --- a/api/staticanalysis/v1/staticanalysis_grpc.pb.go +++ b/api/staticanalysis/v1/staticanalysis_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.5.1 -// - protoc v6.31.1 +// - protoc v6.30.2 // source: staticanalysis/v1/staticanalysis.proto package v1 diff --git a/cmd/commands/server.go b/cmd/commands/server.go index 10ea0d9..7c8d4a7 100644 --- a/cmd/commands/server.go +++ b/cmd/commands/server.go @@ -4,8 +4,6 @@ import ( "os" "github.com/go-kratos/kratos/v2" - "github.com/go-kratos/kratos/v2/config" - "github.com/go-kratos/kratos/v2/config/file" "github.com/go-kratos/kratos/v2/log" "github.com/go-kratos/kratos/v2/transport" "github.com/spf13/cobra" @@ -54,15 +52,62 @@ func NewServerCommand() *ServerCommand { } cmd.CobraCmd = &cobra.Command{ Use: "server", - Short: "start the server", - Run: cmd.Run, + Short: "启动 GoAnalysis 服务器", + Long: `启动 GoAnalysis 服务器,支持通过命令行参数、环境变量或配置文件进行配置。 + +配置优先级:命令行参数 > 环境变量 > 配置文件 > 默认值 + +示例: + # 使用默认配置启动 + goanalysis server + + # 自定义端口和日志级别 + goanalysis server --http-addr=0.0.0.0:8080 --log-level=info + + # 使用配置文件 + goanalysis server --conf=configs/config.yaml`, + Run: cmd.Run, } return cmd } // Init 初始化服务器命令 func (s *ServerCommand) Init() { - s.CobraCmd.Flags().StringVar(&s.flagconf, "conf", "./configs", "config path, eg: -conf config.yaml") + // 配置文件参数 + s.CobraCmd.Flags().StringVar(&s.flagconf, "conf", "", "配置文件路径,例如: -conf config.yaml") + + // 服务器配置参数 + s.CobraCmd.Flags().String("http-addr", "0.0.0.0:8001", "HTTP服务地址") + s.CobraCmd.Flags().String("grpc-addr", "0.0.0.0:9000", "gRPC服务地址") + s.CobraCmd.Flags().String("http-timeout", "1s", "HTTP超时时间") + s.CobraCmd.Flags().String("grpc-timeout", "1s", "gRPC超时时间") + + // 日志配置参数 + s.CobraCmd.Flags().String("log-level", "debug", "日志级别 (debug, info, warn, error)") + s.CobraCmd.Flags().String("log-file", "./logs/app.log", "日志文件路径") + s.CobraCmd.Flags().Bool("log-console", true, "是否输出到控制台") + s.CobraCmd.Flags().Int32("log-max-size", 100, "日志文件最大大小(MB)") + s.CobraCmd.Flags().Int32("log-max-age", 7, "日志保留天数") + s.CobraCmd.Flags().Int32("log-max-backups", 10, "保留的日志文件数量") + s.CobraCmd.Flags().Bool("log-compress", true, "是否压缩日志文件") + + // GitLab配置参数 + s.CobraCmd.Flags().String("gitlab-token", "", "GitLab访问令牌 (也可通过 GITLAB_TOKEN 环境变量设置)") + s.CobraCmd.Flags().String("gitlab-url", "", "GitLab API地址 (也可通过 GITLAB_API_URL 环境变量设置)") + s.CobraCmd.Flags().String("gitlab-clone-dir", "./data", "GitLab克隆目录") + + // OpenAI配置参数 + s.CobraCmd.Flags().String("openai-api-key", "", "OpenAI API密钥 (也可通过 OPENAI_API_KEY 环境变量设置)") + s.CobraCmd.Flags().String("openai-api-base", "", "OpenAI API地址 (也可通过 OPENAI_API_BASE 环境变量设置)") + s.CobraCmd.Flags().String("openai-model", "", "OpenAI模型名称 (也可通过 OPENAI_MODEL 环境变量设置)") + + // 存储路径配置参数 + s.CobraCmd.Flags().String("static-store-path", "./data/static", "静态分析存储路径") + s.CobraCmd.Flags().String("runtime-store-path", "./data/runtime", "运行时分析存储路径") + s.CobraCmd.Flags().String("file-storage-path", "./data/files", "文件存储路径") + + // 数据配置参数 + s.CobraCmd.Flags().String("db-path", "./goanalysis.db", "数据库文件路径") } // newApp 创建Kratos应用 @@ -79,19 +124,14 @@ func (s *ServerCommand) newApp(logger log.Logger, servers []transport.Server) *k // Run 执行服务器命令 func (s *ServerCommand) Run(cmd *cobra.Command, args []string) { - c := config.New( - config.WithSource( - file.NewSource(s.flagconf), - ), - ) - defer c.Close() - - if err := c.Load(); err != nil { + // 使用新的配置加载器 + bc, err := conf.LoadConfig(cmd) + if err != nil { panic(err) } - var bc conf.Bootstrap - if err := c.Scan(&bc); err != nil { + // 验证配置 + if err := conf.ValidateConfig(bc); err != nil { panic(err) } diff --git a/configs/config.yaml b/configs/config.yaml index 4fe9783..fd45959 100644 --- a/configs/config.yaml +++ b/configs/config.yaml @@ -1,6 +1,6 @@ server: http: - addr: 0.0.0.0:8000 + addr: 0.0.0.0:8001 timeout: 1s grpc: addr: 0.0.0.0:9000 diff --git a/go.sum b/go.sum index cfc8d7c..ae2474b 100644 --- a/go.sum +++ b/go.sum @@ -137,12 +137,16 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM= github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM= github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4= diff --git a/internal/biz/analysis/analysis.go b/internal/biz/analysis/analysis.go index dca399d..18fdbf6 100644 --- a/internal/biz/analysis/analysis.go +++ b/internal/biz/analysis/analysis.go @@ -13,10 +13,9 @@ import ( "github.com/go-kratos/kratos/v2/log" "github.com/pkg/errors" v1 "github.com/toheart/goanalysis/api/analysis/v1" - "github.com/toheart/goanalysis/internal/biz/entity" + "github.com/toheart/goanalysis/internal/biz/analysis/dos" "github.com/toheart/goanalysis/internal/conf" "github.com/toheart/goanalysis/internal/data" - sqlite "github.com/toheart/goanalysis/internal/data/sqlite" ) type AnalysisBiz struct { @@ -33,19 +32,11 @@ func (a *AnalysisBiz) GetTotalGIDs(dbpath string) (int, error) { return traceDB.GetTotalGIDs() } -func (a *AnalysisBiz) GetAllFunctionName(dbpath string) ([]string, error) { - traceDB, err := a.data.GetTraceDB(dbpath) - if err != nil { - return nil, err - } - return traceDB.GetAllFunctionName() -} - func NewAnalysisBiz(conf *conf.Biz, data *data.Data, logger log.Logger) *AnalysisBiz { return &AnalysisBiz{conf: conf, data: data, log: log.NewHelper(logger)} } -func (a *AnalysisBiz) GetTracesByGID(req *v1.AnalysisByGIDRequest) ([]entity.TraceData, error) { +func (a *AnalysisBiz) GetTracesByGID(req *v1.AnalysisByGIDRequest) ([]dos.TraceData, error) { a.log.Infof("get traces by gid: %s from db: %s", req.Gid, req.Dbpath) traceDB, err := a.data.GetTraceDB(req.Dbpath) if err != nil { @@ -55,7 +46,7 @@ func (a *AnalysisBiz) GetTracesByGID(req *v1.AnalysisByGIDRequest) ([]entity.Tra return traceDB.GetTracesByGID(req.Gid, int(req.Depth), req.CreateTime) } -func (a *AnalysisBiz) GetAllGIDs(dbpath string, page int, limit int) ([]entity.GoroutineTrace, error) { +func (a *AnalysisBiz) GetAllGIDs(dbpath string, page int, limit int) ([]dos.GoroutineTrace, error) { a.log.Infof("get all gids from db: %s", dbpath) traceDB, err := a.data.GetTraceDB(dbpath) if err != nil { @@ -72,7 +63,7 @@ func (a *AnalysisBiz) GetInitialFunc(dbpath string, gid uint64) (string, error) return traceDB.GetInitialFunc(gid) } -func (a *AnalysisBiz) GetParamsByID(dbpath string, id int32) ([]entity.TraceParams, error) { +func (a *AnalysisBiz) GetParamsByID(dbpath string, id int32) ([]dos.TraceParams, error) { traceDB, err := a.data.GetTraceDB(dbpath) if err != nil { return nil, err @@ -80,12 +71,48 @@ func (a *AnalysisBiz) GetParamsByID(dbpath string, id int32) ([]entity.TracePara return traceDB.GetParamsByID(id) } -func (a *AnalysisBiz) GetGidsByFunctionName(dbpath string, functionName string) ([]string, error) { +func (a *AnalysisBiz) GetGidsByFunctionName(dbpath string, functionName string) ([]*dos.TraceData, error) { + traceDB, err := a.data.GetTraceDB(dbpath) + if err != nil { + return nil, err + } + a.log.Infof("get gids by function name: %s from db: %s", functionName, dbpath) + traces, err := traceDB.GetTracesByFuncName(functionName) + if err != nil { + return nil, err + } + set := make(map[string]bool) + var result []*dos.TraceData + for _, trace := range traces { + if _, ok := set[fmt.Sprintf("%d:%d", trace.GID, trace.ParentId)]; !ok { + set[fmt.Sprintf("%d:%d", trace.GID, trace.ParentId)] = true + result = append(result, &dos.TraceData{ + ID: int64(trace.ID), + Name: trace.Name, + GID: trace.GID, + ParentId: trace.ParentId, + }) + } + } + + return result, nil +} + +// GetTracesByFunctionName 根据函数名获取所有跟踪数据 +func (a *AnalysisBiz) GetTracesByFunctionName(dbpath string, functionName string) ([]dos.TraceData, error) { traceDB, err := a.data.GetTraceDB(dbpath) if err != nil { return nil, err } - return traceDB.GetGidsByFunctionName(functionName) + return traceDB.GetTracesByFuncName(functionName) +} + +func (a *AnalysisBiz) GetGoroutineByGID(dbpath string, gid uint64) (*dos.GoroutineTrace, error) { + traceDB, err := a.data.GetTraceDB(dbpath) + if err != nil { + return nil, err + } + return traceDB.GetGoroutineByGID(int64(gid)) } func (a *AnalysisBiz) VerifyProjectPath(path string) bool { @@ -98,7 +125,7 @@ func (a *AnalysisBiz) VerifyProjectPath(path string) bool { } // GetTracesByParentFunc 根据父函数ID获取函数调用 -func (a *AnalysisBiz) GetTracesByParentFunc(dbpath string, parentId int64) ([]entity.TraceData, error) { +func (a *AnalysisBiz) GetTracesByParentFunc(dbpath string, parentId int64) ([]dos.TraceData, error) { a.log.Infof("get traces by parent id: %d from db: %s", parentId, dbpath) traceDB, err := a.data.GetTraceDB(dbpath) if err != nil { @@ -108,7 +135,7 @@ func (a *AnalysisBiz) GetTracesByParentFunc(dbpath string, parentId int64) ([]en } // GetAllParentIds 获取所有的父函数ID -func (a *AnalysisBiz) GetParentFunctions(dbpath string, functionName string) ([]*entity.Function, error) { +func (a *AnalysisBiz) GetParentFunctions(dbpath string, functionName string) ([]*dos.Function, error) { a.log.Infof("get all parent ids from db: %s", dbpath) traceDB, err := a.data.GetTraceDB(dbpath) if err != nil { @@ -118,7 +145,7 @@ func (a *AnalysisBiz) GetParentFunctions(dbpath string, functionName string) ([] } // GetChildFunctions 获取函数的子函数 -func (a *AnalysisBiz) GetChildFunctions(dbpath string, parentId int64) ([]*entity.Function, error) { +func (a *AnalysisBiz) GetChildFunctions(dbpath string, parentId int64) ([]*dos.Function, error) { a.log.Infof("get child functions of parent id: %d from db: %s", parentId, dbpath) traceDB, err := a.data.GetTraceDB(dbpath) if err != nil { @@ -128,7 +155,7 @@ func (a *AnalysisBiz) GetChildFunctions(dbpath string, parentId int64) ([]*entit } // GetHotFunctions 获取热点函数分析数据 -func (a *AnalysisBiz) GetHotFunctions(dbpath string, sortBy string) ([]entity.Function, error) { +func (a *AnalysisBiz) GetHotFunctions(dbpath string, sortBy string) ([]dos.Function, error) { a.log.Infof("get hot functions, sort by: %s from db: %s", sortBy, dbpath) traceDB, err := a.data.GetTraceDB(dbpath) if err != nil { @@ -138,23 +165,58 @@ func (a *AnalysisBiz) GetHotFunctions(dbpath string, sortBy string) ([]entity.Fu } // GetGoroutineStats 获取Goroutine统计信息 -func (a *AnalysisBiz) GetGoroutineStats(dbpath string) (*entity.GoroutineStats, error) { +func (a *AnalysisBiz) GetGoroutineStats(dbpath string) (*v1.GetGoroutineStatsReply, error) { a.log.Infof("get goroutine stats from db: %s", dbpath) traceDB, err := a.data.GetTraceDB(dbpath) if err != nil { return nil, err } - return traceDB.GetGoroutineStats() -} -// GetFunctionAnalysis 获取函数调用关系分析 -func (a *AnalysisBiz) GetFunctionAnalysis(dbpath string, functionName string, queryType string) ([]entity.FunctionNode, error) { - a.log.Infof("get function analysis, function: %s, type: %s from db: %s", functionName, queryType, dbpath) - traceDB, err := a.data.GetTraceDB(dbpath) + // 获取活跃Goroutine数量 + activeCount, err := traceDB.GetActiveGoroutineCount() if err != nil { return nil, err } - return traceDB.GetFunctionAnalysis(functionName, queryType) + + // 获取最大调用深度 + maxDepth, err := traceDB.GetMaxCallDepth() + if err != nil { + return nil, err + } + + // 获取所有时间消耗并计算平均值 + timeCosts, err := traceDB.GetAllTraceTimeCosts() + if err != nil { + return nil, err + } + + // 计算平均执行时间 + var totalTime float64 + var count int + for _, timeCost := range timeCosts { + if timeCost != "" { + timeCostMs := parseTimeCost(timeCost) + if timeCostMs > 0 { + totalTime += timeCostMs + count++ + } + } + } + + // 计算平均时间 + var avgTime float64 + if count > 0 { + avgTime = totalTime / float64(count) + } + + // 格式化平均时间 + avgTimeStr := formatTime(avgTime) + + return &v1.GetGoroutineStatsReply{ + Active: int32(activeCount), + AvgTime: avgTimeStr, + MaxDepth: int32(maxDepth), + }, nil } // GetGoroutineCallDepth 获取指定 Goroutine 的最大调用深度 @@ -168,7 +230,7 @@ func (a *AnalysisBiz) GetGoroutineCallDepth(dbpath string, gid uint64) (int, err } // GetGoroutineExecutionTime 获取指定 Goroutine 的总执行时间 -func (a *AnalysisBiz) GetGoroutineExecutionTime(dbpath string, groutine entity.GoroutineTrace) (string, error) { +func (a *AnalysisBiz) GetGoroutineExecutionTime(dbpath string, groutine dos.GoroutineTrace) (string, error) { a.log.Infof("get goroutine execution time for gid: %d from db: %s", groutine.ID, dbpath) traceDB, err := a.data.GetTraceDB(dbpath) if err != nil { @@ -196,7 +258,7 @@ func (a *AnalysisBiz) GetGoroutineExecutionTime(dbpath string, groutine entity.G return executionTime, nil } -func (a *AnalysisBiz) GetAllGoroutineTrace(dbpath string, includeMetrics bool) ([]entity.GoroutineTrace, error) { +func (a *AnalysisBiz) GetAllGoroutineTrace(dbpath string, includeMetrics bool) ([]dos.GoroutineTrace, error) { a.log.Infof("get all goroutine trace from db: %s", dbpath) traceDB, err := a.data.GetTraceDB(dbpath) if err != nil { @@ -236,388 +298,8 @@ func (a *AnalysisBiz) IsGoroutineFinished(dbpath string, gid uint64) (bool, erro return traceDB.IsGoroutineFinished(gid) } -func (a *AnalysisBiz) GetUpstreamTreeGraph(dbpath string, functionName string, depth int) ([]*entity.TreeNode, error) { - traceDB, err := a.data.GetTraceDB(dbpath) - if err != nil { - return nil, err - } - - // 获取指定函数的所有跟踪数据 - traces, err := traceDB.GetTracesByFuncName(functionName) - if err != nil { - return nil, err - } - - // 存储所有生成的树节点 - var trees []*entity.TreeNode - - // 为每个跟踪数据创建一个树 - for _, trace := range traces { - // 创建根节点 - rootNode := &entity.TreeNode{ - Name: functionName, - Value: trace.ID, - } - - // 递归构建上游调用树 - err = a.buildUpstreamTree(traceDB, rootNode, trace.ParentId, depth-1) - if err != nil { - return nil, err - } - - trees = append(trees, rootNode) - } - - return trees, nil -} - -// 递归构建上游调用树 -func (a *AnalysisBiz) buildUpstreamTree(traceDB *sqlite.TraceEntDB, currentNode *entity.TreeNode, parentId uint64, remainingDepth int) error { - // 如果父ID为0或者已达到最大深度,则停止递归 - if parentId == 0 || remainingDepth <= 0 { - return nil - } - - // 获取父函数的跟踪数据 - parentTrace, err := traceDB.GetTraceByID(int(parentId)) - if err != nil { - return err - } - - if parentTrace == nil { - return nil // 父跟踪不存在,可能是根调用 - } - - // 创建父节点 - parentNode := &entity.TreeNode{ - Name: parentTrace.Name, - Value: parentTrace.ID, - } - - // 将当前节点添加为父节点的子节点 - if parentNode.Children == nil { - parentNode.Children = []*entity.TreeNode{} - } - parentNode.Children = append(parentNode.Children, currentNode) - - // 继续向上递归构建树 - return a.buildUpstreamTree(traceDB, parentNode, parentTrace.ParentId, remainingDepth-1) -} - -func (a *AnalysisBiz) GetDownstreamTreeGraph(dbpath string, functionName string, depth int) (*entity.TreeNode, error) { - a.log.Infof("get downstream tree graph, function: %s, depth: %d, dbpath: %s", functionName, depth, dbpath) - - // 获取追踪数据库 - traceDB, err := a.data.GetTraceDB(dbpath) - if err != nil { - return nil, fmt.Errorf("get trace db failed: %w", err) - } - - // 获取函数的所有调用记录 - traces, err := traceDB.GetTracesByFuncName(functionName) - if err != nil { - return nil, fmt.Errorf("get traces by func name failed: %w", err) - } - - // 如果没有找到调用记录,返回空数组 - if len(traces) == 0 { - return nil, nil - } - - // 为每个trace创建一个根节点 - root := &entity.TreeNode{ - Name: functionName, - Value: traces[0].ID, - Children: []*entity.TreeNode{}, - } - parentIds := []int64{} - - for _, trace := range traces { - parentIds = append(parentIds, trace.ID) - } - - // 递归构建下游调用树 - err = a.buildDownstreamTree(traceDB, root, parentIds, depth) - if err != nil { - return nil, fmt.Errorf("build downstream tree failed: %w", err) - } - - return root, nil -} - -// 递归构建下游调用树 -func (a *AnalysisBiz) buildDownstreamTree(traceDB *sqlite.TraceEntDB, currentNode *entity.TreeNode, parentIds []int64, remainingDepth int) error { - // 如果已达到最大深度,则停止递归 - if remainingDepth <= 0 || currentNode == nil { - return nil - } - - for _, parentId := range parentIds { - // 获取当前函数调用的子函数 - childFunctions, err := traceDB.GetTracesByParentId(parentId) - if err != nil { - return err - } - - // 为每个子函数创建节点 - for _, childFunc := range childFunctions { - // 获取子函数的统计信息 - - // 创建子节点 - childNode := &entity.TreeNode{ - Name: childFunc.Name, - Children: []*entity.TreeNode{}, - } - - // 递归构建子节点的下游调用 - err = a.buildDownstreamTree(traceDB, childNode, []int64{childFunc.ID}, remainingDepth-1) - if err != nil { - return err - } - currentNode.Children = append(currentNode.Children, childNode) - } - } - - return nil -} - -// GetTreeGraph 获取运行时的树状图数据 -func (a *AnalysisBiz) GetTreeGraph(dbpath string, functionName string, chainType string, depth int) ([]*entity.TreeNode, error) { - a.log.Infof("get tree graph, function: %s, chain type: %s, dbpath: %s", functionName, chainType, dbpath) - - // 根据链路类型选择不同的查询方向 - var trees []*entity.TreeNode - var err error - switch chainType { - case "upstream": - trees, err = a.GetUpstreamTreeGraph(dbpath, functionName, depth) - if err != nil { - return nil, err - } - case "downstream": - tree, err := a.GetDownstreamTreeGraph(dbpath, functionName, depth) - if err != nil { - return nil, err - } - trees = append(trees, tree) - case "full": - // 全链路需要分别获取上游和下游调用,然后合并 - upstreamGraph, err := a.GetUpstreamTreeGraph(dbpath, functionName, depth) - if err != nil { - a.log.Warnf("get upstream call graph failed: %v", err) - } - - downstreamGraph, err := a.GetDownstreamTreeGraph(dbpath, functionName, depth) - if err != nil { - a.log.Warnf("get downstream call graph failed: %v", err) - } - - // 合并处理上游和下游调用图 - trees, err := a.buildFullChainTreeNodes(functionName, upstreamGraph, downstreamGraph) - if err != nil { - return nil, err - } - return trees, nil - default: - return nil, fmt.Errorf("invalid chain type: %s", chainType) - } - - return trees, nil -} - -func (a *AnalysisBiz) buildFullChainTreeNodes(functionName string, upstreamGraph []*entity.TreeNode, downstreamGraph *entity.TreeNode) ([]*entity.TreeNode, error) { - // 如果上游图为空,直接返回下游图 - if len(upstreamGraph) == 0 { - return []*entity.TreeNode{downstreamGraph}, nil - } - - for _, node := range upstreamGraph { - // 递归查找叶子节点 - var findLeafNodes func(node *entity.TreeNode) *entity.TreeNode - findLeafNodes = func(node *entity.TreeNode) *entity.TreeNode { - // 如果节点没有子节点,则为叶子节点 - if len(node.Children) == 0 { - return node - } - - // 递归处理所有子节点 - for _, child := range node.Children { - leafNode := findLeafNodes(child) - if leafNode != nil { - return leafNode - } - } - return nil - } - - // 对当前节点执行递归查找 - leafNode := findLeafNodes(node) - if leafNode != nil { - leafNode.Children = append(leafNode.Children, downstreamGraph) - } - } - - return upstreamGraph, nil -} - -// GetTreeGraphByGID 根据GID获取多棵树状图数据 -func (a *AnalysisBiz) GetTreeGraphByGID(dbpath string, gid uint64) ([]*entity.TreeNode, error) { - a.log.Infof("get tree graph by gid: %d, dbpath: %s", gid, dbpath) - - // 获取追踪数据库 - traceDB, err := a.data.GetTraceDB(dbpath) - if err != nil { - return nil, err - } - - // 获取指定GID的所有调用跟踪数据 - traces, err := traceDB.GetTracesByGID(gid, 3, "") - if err != nil { - return nil, err - } - - // 如果没有找到相关调用数据 - if len(traces) == 0 { - return []*entity.TreeNode{}, nil - } - - // 按照调用层级构建多棵树 - // 首先找到所有根调用,即没有父函数的调用 - var rootTrees []*entity.TreeNode - - // 根据ParentId对调用进行分组 - tracesByParentId := make(map[uint64][]entity.TraceData) - traceById := make(map[int64]entity.TraceData) - - for _, trace := range traces { - tracesByParentId[trace.ParentId] = append(tracesByParentId[trace.ParentId], trace) - traceById[trace.ID] = trace - } - - // 找出所有根调用(ParentId为0或不存在父调用的) - rootTraces := tracesByParentId[0] - - // 如果没有明确的根调用,则使用缩进级别为0的调用作为根 - if len(rootTraces) == 0 { - for _, trace := range traces { - if trace.Indent == 0 { - rootTraces = append(rootTraces, trace) - } - } - } - - // 如果仍然没有根调用,则使用所有调用中缩进级别最小的作为根 - if len(rootTraces) == 0 && len(traces) > 0 { - minIndent := traces[0].Indent - for _, trace := range traces { - if trace.Indent < minIndent { - minIndent = trace.Indent - } - } - - for _, trace := range traces { - if trace.Indent == minIndent { - rootTraces = append(rootTraces, trace) - } - } - } - - // 为每个根调用构建树 - for _, rootTrace := range rootTraces { - rootNode := &entity.TreeNode{ - Name: rootTrace.Name, - Value: int64(rootTrace.ID), - } - - // 递归构建子树 - buildTreeFromTrace(rootNode, rootTrace.ID, tracesByParentId, 0, 3) // 限制最大深度为5层 - - rootTrees = append(rootTrees, rootNode) - } - - return rootTrees, nil -} - -// buildTreeFromTrace 递归构建调用树 -func buildTreeFromTrace(node *entity.TreeNode, traceId int64, tracesByParentId map[uint64][]entity.TraceData, currentDepth, maxDepth int) { - // 防止过深递归 - if currentDepth >= maxDepth { - return - } - - // 获取当前调用的所有子调用 - childTraces := tracesByParentId[uint64(traceId)] - - // 为每个子调用创建节点 - for _, childTrace := range childTraces { - childNode := &entity.TreeNode{ - Name: childTrace.Name, - Value: childTrace.ID, - } - // 添加子节点 - node.Children = append(node.Children, childNode) - - // 递归处理子调用 - buildTreeFromTrace(childNode, childTrace.ID, tracesByParentId, currentDepth+1, maxDepth) - } -} - -// GetFunctionHotPaths 获取函数热点路径分析 -func (a *AnalysisBiz) GetFunctionHotPaths(dbpath string, functionName string, limit int) ([]entity.HotPathInfo, error) { - // TODO 没想法怎么做 - return nil, nil -} - -// calculatePathStats 计算路径的调用统计信息 -func (a *AnalysisBiz) calculatePathStats(traceDB *sqlite.TraceEntDB, functionNames []string) (int, string, string) { - // 这里应该根据实际情况从数据库中查询这条路径的统计信息 - // 简单实现:假设调用次数是叶子节点函数的调用次数 - if len(functionNames) == 0 { - return 0, "0ms", "0ms" - } - - leafFunction := functionNames[len(functionNames)-1] - - // 获取叶子函数的所有调用数据 - traces, err := traceDB.GetTracesByFuncName(leafFunction) - if err != nil { - a.log.Warnf("获取函数%s的调用数据失败: %v", leafFunction, err) - return 0, "0ms", "0ms" - } - - // 统计调用次数和总时间 - callCount := len(traces) - - // 解析时间 - var totalTimeMs float64 - for _, trace := range traces { - timeCostMs := parseTimeCost(trace.TimeCost) - totalTimeMs += timeCostMs - } - - // 计算平均时间 - var avgTimeMs float64 - if callCount > 0 { - avgTimeMs = totalTimeMs / float64(callCount) - } - - // 格式化时间 - totalTime := formatTime(totalTimeMs) - avgTime := formatTime(avgTimeMs) - - return callCount, totalTime, avgTime -} - -// sortHotPathsByCallCount 按调用次数对热点路径进行排序 -func (a *AnalysisBiz) sortHotPathsByCallCount(paths []entity.HotPathInfo) { - // 按调用次数降序排序 - sort.Slice(paths, func(i, j int) bool { - return paths[i].CallCount > paths[j].CallCount - }) -} - // GetFunctionCallStats 获取函数调用统计分析 -func (a *AnalysisBiz) GetFunctionCallStats(dbpath string, functionName string) ([]entity.FunctionCallStats, error) { +func (a *AnalysisBiz) GetFunctionCallStats(dbpath string, functionName string) ([]dos.FunctionCallStats, error) { a.log.Infof("获取函数调用统计,函数:%s,数据库:%s", functionName, dbpath) // 获取追踪数据库 @@ -626,7 +308,7 @@ func (a *AnalysisBiz) GetFunctionCallStats(dbpath string, functionName string) ( return nil, err } - var stats []entity.FunctionCallStats + var stats []dos.FunctionCallStats // 如果指定了函数名,则只获取该函数的统计信息 if functionName != "" { @@ -697,7 +379,7 @@ func (a *AnalysisBiz) GetFunctionCallStats(dbpath string, functionName string) ( } // 创建函数调用统计信息 - stat := entity.FunctionCallStats{ + stat := dos.FunctionCallStats{ Name: functionName, Package: extractPackage(functionName), CallCount: len(traces), @@ -736,276 +418,18 @@ func (a *AnalysisBiz) GetFunctionCallStats(dbpath string, functionName string) ( return stats, nil } -// GetPerformanceAnomalies 获取性能异常检测结果 -func (a *AnalysisBiz) GetPerformanceAnomalies(dbpath string, functionName string, threshold float64) ([]entity.PerformanceAnomaly, error) { - a.log.Infof("获取性能异常检测,函数:%s,数据库:%s,阈值:%f", functionName, dbpath, threshold) +// GetFunctionInfoInGoroutine 获取函数在指定Goroutine中的信息 +func (a *AnalysisBiz) GetFunctionInfoInGoroutine(dbpath string, gid uint64, targetFunctionId int64) (*dos.FunctionInfo, error) { + a.log.Infof("get function info in goroutine, gid: %d, functionId: %d from db: %s", gid, targetFunctionId, dbpath) - // 获取追踪数据库 traceDB, err := a.data.GetTraceDB(dbpath) if err != nil { return nil, err } - // 如果阈值未设置,使用默认值 - if threshold <= 0 { - threshold = 2.0 // 默认为2个标准差 - } - - var anomalies []entity.PerformanceAnomaly - - // 如果指定了函数名,则只检测该函数 - if functionName != "" { - // 获取函数的统计信息 - stats, err := a.GetFunctionCallStats(dbpath, functionName) - if err != nil { - a.log.Errorf("获取函数%s的统计信息失败: %v", functionName, err) - return nil, err - } - - if len(stats) > 0 { - // 检测时间波动异常 - if a.detectTimeVarianceAnomaly(&stats[0], threshold) { - anomalies = append(anomalies, createTimeVarianceAnomaly(&stats[0], threshold)) - } - - // 检测调用深度异常 - if a.detectDepthAnomaly(traceDB, functionName, threshold) { - anomalies = append(anomalies, createDepthAnomaly(functionName, extractPackage(functionName), threshold)) - } - - // 检测调用频率异常 - if a.detectFrequencyAnomaly(traceDB, functionName, threshold) { - anomalies = append(anomalies, createFrequencyAnomaly(functionName, extractPackage(functionName), threshold)) - } - } - } else { - // 获取所有函数的统计信息 - allStats, err := a.GetFunctionCallStats(dbpath, "") - if err != nil { - a.log.Errorf("获取所有函数统计信息失败: %v", err) - return nil, err - } - - // 计算所有函数的标准差的均值,用于比较 - var totalStdDev float64 - for _, stat := range allStats { - totalStdDev += stat.TimeStdDev - } - avgStdDev := 0.0 - if len(allStats) > 0 { - avgStdDev = totalStdDev / float64(len(allStats)) - } - - // 对每个函数检测异常 - for _, stat := range allStats { - // 检测时间波动异常,使用相对于平均标准差的比例 - if stat.TimeStdDev > avgStdDev*threshold { - anomalies = append(anomalies, createTimeVarianceAnomaly(&stat, threshold)) - } - - // 检测调用深度异常 - if a.detectDepthAnomaly(traceDB, stat.Name, threshold) { - anomalies = append(anomalies, createDepthAnomaly(stat.Name, stat.Package, threshold)) - } - - // 检测调用频率异常 - if a.detectFrequencyAnomaly(traceDB, stat.Name, threshold) { - anomalies = append(anomalies, createFrequencyAnomaly(stat.Name, stat.Package, threshold)) - } - } - } - - // 按严重程度排序 - sort.Slice(anomalies, func(i, j int) bool { - return anomalies[i].Severity > anomalies[j].Severity - }) - - return anomalies, nil + return traceDB.GetFunctionInfoInGoroutine(gid, targetFunctionId) } -// 辅助函数 - -// 检测时间波动异常 -func (a *AnalysisBiz) detectTimeVarianceAnomaly(stat *entity.FunctionCallStats, threshold float64) bool { - // 如果函数只被调用一次,无法判断波动 - if stat.CallCount <= 1 { - return false - } - - // 计算变异系数(CV):标准差/平均值,用于衡量相对波动程度 - avgTimeMs := parseTimeCost(stat.AvgTime) - if avgTimeMs <= 0 { - return false - } - - cv := stat.TimeStdDev / avgTimeMs - - // 如果变异系数大于阈值,则认为存在时间波动异常 - return cv > threshold/10 // 调整阈值,使其更符合CV的比例 -} - -// 检测调用深度异常 -func (a *AnalysisBiz) detectDepthAnomaly(traceDB *sqlite.TraceEntDB, functionName string, threshold float64) bool { - // 获取该函数在所有Goroutine中的调用深度 - depths, err := traceDB.GetFunctionCallDepths(functionName) - if err != nil { - a.log.Warnf("获取函数%s的调用深度失败: %v", functionName, err) - return false - } - - // 如果样本太少,无法判断 - if len(depths) <= 1 { - return false - } - - // 计算深度的平均值和标准差 - var totalDepth int - for _, d := range depths { - totalDepth += d - } - avgDepth := float64(totalDepth) / float64(len(depths)) - - var sumSquares float64 - for _, d := range depths { - diff := float64(d) - avgDepth - sumSquares += diff * diff - } - stdDev := math.Sqrt(sumSquares / float64(len(depths)-1)) - - // 检查是否有深度异常的调用 - for _, d := range depths { - if math.Abs(float64(d)-avgDepth) > stdDev*threshold { - return true - } - } - - return false -} - -// 检测调用频率异常 -func (a *AnalysisBiz) detectFrequencyAnomaly(traceDB *sqlite.TraceEntDB, functionName string, threshold float64) bool { - // 获取该函数的所有调用记录 - traces, err := traceDB.GetTracesByFuncName(functionName) - if err != nil { - a.log.Warnf("获取函数%s的调用记录失败: %v", functionName, err) - return false - } - - // 如果样本太少,无法判断 - if len(traces) <= 2 { - return false - } - - // 按时间戳排序,计算调用间隔 - sort.Slice(traces, func(i, j int) bool { - return traces[i].CreatedAt < traces[j].CreatedAt - }) - - // 计算调用间隔 - intervals := make([]float64, len(traces)-1) - for i := 1; i < len(traces); i++ { - // 解析时间戳,计算间隔(毫秒) - t1, err1 := time.Parse(time.RFC3339, traces[i-1].CreatedAt) - t2, err2 := time.Parse(time.RFC3339, traces[i].CreatedAt) - - if err1 != nil || err2 != nil { - continue - } - - interval := t2.Sub(t1).Milliseconds() - intervals[i-1] = float64(interval) - } - - // 计算间隔的平均值和标准差 - var totalInterval float64 - for _, interval := range intervals { - totalInterval += interval - } - avgInterval := totalInterval / float64(len(intervals)) - - var sumSquares float64 - for _, interval := range intervals { - diff := interval - avgInterval - sumSquares += diff * diff - } - stdDev := math.Sqrt(sumSquares / float64(len(intervals)-1)) - - // 计算变异系数 - cv := stdDev / avgInterval - - // 如果变异系数大于阈值,则认为存在频率异常 - return cv > threshold/5 // 调整阈值,使其更符合调用频率CV的比例 -} - -// 创建时间波动异常 -func createTimeVarianceAnomaly(stat *entity.FunctionCallStats, threshold float64) entity.PerformanceAnomaly { - // 计算变异系数 - avgTimeMs := parseTimeCost(stat.AvgTime) - cv := stat.TimeStdDev / avgTimeMs - - // 计算严重程度 (0.0-1.0) - severity := math.Min(cv/(threshold/5), 1.0) - - // 创建详细信息 - details := map[string]string{ - "avg_time": stat.AvgTime, - "max_time": stat.MaxTime, - "min_time": stat.MinTime, - "std_dev": fmt.Sprintf("%.2f ms", stat.TimeStdDev), - "call_count": fmt.Sprintf("%d", stat.CallCount), - "cv": fmt.Sprintf("%.2f", cv), - "threshold_cv": fmt.Sprintf("%.2f", threshold/10), - } - - return entity.PerformanceAnomaly{ - Name: stat.Name, - Package: stat.Package, - AnomalyType: "time_variance", - Description: fmt.Sprintf("函数 %s 的执行时间波动较大,变异系数为 %.2f (阈值: %.2f)", stat.Name, cv, threshold/10), - Severity: severity, - Details: details, - } -} - -// 创建深度异常 -func createDepthAnomaly(funcName string, pkg string, threshold float64) entity.PerformanceAnomaly { - // 固定严重程度为0.7,因为深度异常通常表示潜在的调用栈问题 - severity := 0.7 - - details := map[string]string{ - "threshold": fmt.Sprintf("%.1f 个标准差", threshold), - } - - return entity.PerformanceAnomaly{ - Name: funcName, - Package: pkg, - AnomalyType: "depth_anomaly", - Description: fmt.Sprintf("函数 %s 在不同调用中的调用深度存在异常波动", funcName), - Severity: severity, - Details: details, - } -} - -// 创建频率异常 -func createFrequencyAnomaly(funcName string, pkg string, threshold float64) entity.PerformanceAnomaly { - // 固定严重程度为0.5,因为频率异常可能是正常的业务逻辑导致的 - severity := 0.5 - - details := map[string]string{ - "threshold": fmt.Sprintf("%.1f 个标准差", threshold/5), - } - - return entity.PerformanceAnomaly{ - Name: funcName, - Package: pkg, - AnomalyType: "frequency_anomaly", - Description: fmt.Sprintf("函数 %s 的调用频率存在异常波动", funcName), - Severity: severity, - Details: details, - } -} - -// 提取包名 func extractPackage(functionName string) string { lastDot := strings.LastIndex(functionName, ".") if lastDot <= 0 { @@ -1064,7 +488,7 @@ func formatTime(timeMs float64) string { } // SearchFunctions 搜索函数 -func (a *AnalysisBiz) SearchFunctions(ctx context.Context, dbPath string, query string, limit int32) ([]*entity.Function, int32, error) { +func (a *AnalysisBiz) SearchFunctions(ctx context.Context, dbPath string, query string, limit int32) ([]*dos.Function, int32, error) { // 验证参数 if dbPath == "" { return nil, 0, errors.New("database path is required") @@ -1086,6 +510,70 @@ func (a *AnalysisBiz) SearchFunctions(ctx context.Context, dbPath string, query if err != nil { return nil, 0, fmt.Errorf("failed to search functions: %v", err) } + // 名字去重 + set := make(map[string]bool) + var result []*dos.Function + for _, function := range functions { + if _, ok := set[function.Name]; !ok { + set[function.Name] = true + result = append(result, function) + } + } + + return result, total, nil +} + +// GetModuleNames 获取数据库中的模块名称列表 +func (a *AnalysisBiz) GetModuleNames(dbpath string, maxSamples int32) ([]string, error) { + a.log.Infof("get module names from db: %s with max samples: %d", dbpath, maxSamples) + + traceDB, err := a.data.GetTraceDB(dbpath) + if err != nil { + return nil, err + } + + // 获取采样后的函数名称列表 + functionNames, err := traceDB.GetSampledFunctionNames(maxSamples) + if err != nil { + return nil, err + } + + // 提取模块名称并统计频率 + moduleCount := make(map[string]int) + + for _, functionName := range functionNames { + // 提取包路径前缀(最后一个.之前的部分) + lastDotIndex := strings.LastIndex(functionName, ".") + if lastDotIndex > 0 { + packagePath := functionName[:lastDotIndex] + + // 按/分割,生成所有层级的前缀 + parts := strings.Split(packagePath, "/") + for i := 1; i <= len(parts); i++ { + prefix := strings.Join(parts[:i], "/") + moduleCount[prefix]++ + } + } else { + // 如果没有.,说明是标准库函数,直接使用函数名 + moduleCount[functionName]++ + } + } + + var stats []dos.ModuleStat + for name, count := range moduleCount { + stats = append(stats, dos.ModuleStat{Name: name, Count: count}) + } + + // 按频率降序排序 + sort.Slice(stats, func(i, j int) bool { + return stats[i].Count > stats[j].Count + }) + + // 取前5个 + result := make([]string, 0, 5) + for i := 0; i < len(stats) && i < 5; i++ { + result = append(result, stats[i].Name) + } - return functions, total, nil + return result, nil } diff --git a/internal/biz/analysis/dos/goroutine.go b/internal/biz/analysis/dos/goroutine.go new file mode 100644 index 0000000..ede00f9 --- /dev/null +++ b/internal/biz/analysis/dos/goroutine.go @@ -0,0 +1,19 @@ +package dos + +// GoroutineTrace 存储goroutine信息的结构体 +type GoroutineTrace struct { + ID int64 `json:"id"` // 自增ID + GID uint64 `json:"gid"` // Goroutine ID + TimeCost string `json:"timeCost"` // 执行时间 + CreateTime string `json:"createTime"` // 创建时间 + IsFinished int `json:"isFinished"` // 是否完成 + InitFuncName string `json:"initFuncName"` // 初始函数名 + Depth int `json:"depth"` // 调用深度 +} + +// GoroutineStats Goroutine统计信息 +type GoroutineStats struct { + Active int // 活跃Goroutine数量 + AvgTime string // 平均执行时间 + MaxDepth int // 最大调用深度 +} diff --git a/internal/biz/analysis/dos/runtime.go b/internal/biz/analysis/dos/runtime.go new file mode 100644 index 0000000..f284903 --- /dev/null +++ b/internal/biz/analysis/dos/runtime.go @@ -0,0 +1,106 @@ +package dos + +import "strings" + +// TraceData 存储跟踪数据的结构体 +type TraceData struct { + ID int64 `json:"id"` // 唯一标识符 + Name string `json:"name"` // 函数名称 + GID uint64 `json:"gid"` // Goroutine ID + Indent int `json:"indent"` // 缩进级别 + ParamCount int `json:"paramCount"` // 参数数量 + TimeCost string `json:"timeCost"` // 执行时间 + ParentId uint64 `json:"parentId"` // 父函数ID + CreatedAt string `json:"createdAt"` // 创建时间 + Seq string `json:"seq"` // 序列号 +} + +// FunctionNode 函数调用节点 +type FunctionNode struct { + ID string // 节点ID + Name string // 函数名称 + Package string // 包名 + CallCount int // 调用次数 + AvgTime string // 平均耗时 + Children []FunctionNode // 子节点 +} + +// FunctionInfo 函数在Goroutine中的信息 +type FunctionInfo struct { + ID int64 `json:"id"` // 函数ID + Name string `json:"name"` // 函数名称 + Indent int `json:"indent"` // 函数在调用链中的实际深度 + Found bool `json:"found"` // 是否在当前深度范围内找到 + ParentIds []ParentInfo `json:"parentIds"` // 父函数ID+深度列表(去重) +} + +// ParentInfo 父函数信息 +type ParentInfo struct { + ParentId int64 `json:"parentId"` // 父函数ID + Depth int `json:"depth"` // 深度 + Name string `json:"name"` // 父函数名称 +} + +// 按频率排序,取前5个 +type ModuleStat struct { + Name string + Count int +} + +type TraceParams struct { + ID int64 `json:"id"` // 唯一标识符 + TraceID int64 `json:"traceId"` // 关联的TraceData ID + Position int `json:"position"` // 参数位置 + Data string `json:"data"` // 参数JSON数据 + IsReceiver bool `json:"isReceiver"` // 是否为接收者参数 + BaseID int64 `json:"baseId"` // 基础参数ID(自关联,当参数为增量存储时使用) +} + +type Function struct { + Id int64 // 函数ID + Name string // 函数名称 + Package string // 包名 + ParentId int64 // 父函数ID + CallCount int // 调用次数 + TotalTime string // 总耗时 + AvgTime string // 平均耗时 + ParamCount int // 参数数量 + Depth int // 深度 + Seq string // 序列号 +} + +func NewFunction(id int64, name string, callCount int, totalTime string, avgTime string) *Function { + f := &Function{ + Id: id, + Name: name, + CallCount: callCount, + TotalTime: totalTime, + AvgTime: avgTime, + } + f.SetPackage() + return f +} + +func (f *Function) SetPackage() { + parts := strings.Split(f.Name, "/") + packageName := "main" + if len(parts) > 1 { + lastPart := parts[len(parts)-1] // 取最后一个部分作为函数名 + packageNames := strings.Split(lastPart, ".") + packageName = packageNames[0] + } + f.Package = packageName +} + +// FunctionCallStats 函数调用统计信息 +type FunctionCallStats struct { + Name string // 函数名称 + Package string // 包名 + CallCount int // 调用次数 + CallerCount int // 调用方数量 + CalleeCount int // 被调用方数量 + AvgTime string // 平均执行时间 + MaxTime string // 最大执行时间 + MinTime string // 最小执行时间 + TimeStdDev float64 // 执行时间标准差 +} diff --git a/internal/biz/callgraph/filter.go b/internal/biz/callgraph/filter.go index e69ac11..9cc4916 100644 --- a/internal/biz/callgraph/filter.go +++ b/internal/biz/callgraph/filter.go @@ -34,7 +34,13 @@ func (f *Filter) IsStandardLibrary(node *callgraph.Node) bool { // IsInternal 检查节点是否为内部模块 func (f *Filter) IsInternal(node *callgraph.Node) bool { - return strings.Contains(node.Func.String(), f.config.ModuleName) + // 增加nil检查以提高健壮性 + if node.Func == nil || node.Func.Pkg == nil || node.Func.Pkg.Pkg == nil { + return false + } + // node.Func.Pkg.Pkg.Path() 返回纯包路径,如 "github.com/toheart/goanalysis/internal/biz" + // 使用 HasPrefix 匹配模块名,更精确 + return strings.HasPrefix(node.Func.Pkg.Pkg.Path(), f.config.ModuleName) } // ShouldProcessEdge 检查边是否应该被处理 @@ -47,25 +53,25 @@ func (f *Filter) ShouldProcessEdge(edge *callgraph.Edge) bool { caller := edge.Caller callee := edge.Callee - // 排除标准库节点:如果调用者或被调用者是标准库,则排除 - if f.IsStandardLibrary(caller) || f.IsStandardLibrary(callee) { + // 规则1:调用者必须是项目内部函数。这是最核心的过滤条件。 + if !f.IsInternal(caller) { return false } - // 排除忽略的包 - if f.ShouldIgnore(caller) || f.ShouldIgnore(callee) { + // 规则2:被调用者不能是标准库函数 (排除对 builtin 和 std lib 的调用) + if f.IsStandardLibrary(callee) { return false } - // 排除调用者、被调用者两者都不属于当前项目的方法 - callerIsInternal := f.IsInternal(caller) - calleeIsInternal := f.IsInternal(callee) - - // 至少有一个必须是内部模块,否则排除 - if !callerIsInternal && !calleeIsInternal { + // 规则3:调用者和被调用者都不能在用户指定的忽略路径中 + if f.ShouldIgnore(caller) || f.ShouldIgnore(callee) { return false } + // 如果通过以上所有检查,则处理该边。 + // 这个逻辑精确地保留了以下两种调用关系: + // 1. internal -> internal + // 2. internal -> third-party return true } diff --git a/internal/biz/entity/runtime.go b/internal/biz/entity/runtime.go index 134ea87..9ed5fec 100644 --- a/internal/biz/entity/runtime.go +++ b/internal/biz/entity/runtime.go @@ -1,5 +1,13 @@ package entity +// GoroutineFunctionInfo 存储Goroutine和函数信息的结构体 +type GoroutineFunctionInfo struct { + GID uint64 `json:"gid"` // Goroutine ID + ParentId uint64 `json:"parentId"` // 父函数ID + InitialFunc string `json:"initialFunc"` // 初始函数名 + IsFinished bool `json:"isFinished"` // 是否完成 +} + // TraceData 存储跟踪数据的结构体 type TraceData struct { ID int64 `json:"id"` // 唯一标识符 @@ -55,6 +63,23 @@ type FunctionGraphNode struct { type FunctionGraphEdge struct { Source string // 源节点ID Target string // 目标节点ID + Value int // 调用次数 Label string // 边标签 EdgeType string // 边类型: "caller_to_root", "root_to_callee" } + +// FunctionInfo 函数在Goroutine中的信息 +type FunctionInfo struct { + ID int64 `json:"id"` // 函数ID + Name string `json:"name"` // 函数名称 + Indent int `json:"indent"` // 函数在调用链中的实际深度 + Found bool `json:"found"` // 是否在当前深度范围内找到 + ParentIds []ParentInfo `json:"parentIds"` // 父函数ID+深度列表(去重) +} + +// ParentInfo 父函数信息 +type ParentInfo struct { + ParentId int64 `json:"parentId"` // 父函数ID + Depth int `json:"depth"` // 深度 + Name string `json:"name"` // 父函数名称 +} diff --git a/internal/biz/rewrite/rewrite.go b/internal/biz/rewrite/rewrite.go index a88b0fe..c925c52 100644 --- a/internal/biz/rewrite/rewrite.go +++ b/internal/biz/rewrite/rewrite.go @@ -37,6 +37,10 @@ func RewriteDir(dir string) { return nil } if info.IsDir() { + // 跳过vendor目录 + if info.Name() == "vendor" { + return filepath.SkipDir + } return nil } // 排除 @@ -173,6 +177,11 @@ func (r *Rewrite) ImportFunctrace() { } func (r *Rewrite) HasSameDefer(decl *ast.FuncDecl) bool { + // 检查函数是否有函数体 + if decl.Body == nil { + return false + } + for _, stmt := range decl.Body.List { // 判断是否为defer 函数 ds, ok := stmt.(*ast.DeferStmt) @@ -201,6 +210,185 @@ func (r *Rewrite) HasSameDefer(decl *ast.FuncDecl) bool { return false } +// hasSameDeferInBody 通用的defer检查函数,用于检查任何函数体中是否已有相同的defer语句 +func (r *Rewrite) hasSameDeferInBody(body *ast.BlockStmt) bool { + if body == nil { + return false + } + + for _, stmt := range body.List { + ds, ok := stmt.(*ast.DeferStmt) + if !ok { + continue + } + + ce, ok := ds.Call.Fun.(*ast.CallExpr) + if !ok { + continue + } + se, ok := ce.Fun.(*ast.SelectorExpr) + if !ok { + continue + } + + x, ok := se.X.(*ast.Ident) + if !ok { + continue + } + if (x.Name == "functrace") && (se.Sel.Name == "Trace") { + return true + } + } + return false +} + +// addDeferToBody 通用的添加defer语句函数 +func (r *Rewrite) addDeferToBody(body *ast.BlockStmt, funcType *ast.FuncType, recv *ast.FieldList) bool { + if body == nil { + return false + } + + // 检查是否已经有相同的defer语句 + if r.hasSameDeferInBody(body) { + return false + } + + // 生成defer语句 + elts := r.genTraceParams(funcType, recv) + deferStmt := r.genDefer(elts) + + // 将defer语句添加到函数体的开头 + body.List = append([]ast.Stmt{deferStmt}, body.List...) + return true +} + +// processFuncLit 处理函数字面量,添加defer语句 +func (r *Rewrite) processFuncLit(funcLit *ast.FuncLit) bool { + return r.addDeferToBody(funcLit.Body, funcLit.Type, nil) +} + +// processGoStmt 处理go语句 +func (r *Rewrite) processGoStmt(goStmt *ast.GoStmt) bool { + // 检查go语句中的函数是否为函数字面量 + if funcLit, ok := goStmt.Call.Fun.(*ast.FuncLit); ok { + return r.processFuncLit(funcLit) + } + + // 处理go语句中的函数调用参数,查找其中的函数字面量 + return r.processCallExpr(goStmt.Call) +} + +// processCallExpr 处理函数调用表达式,查找其中的函数字面量参数 +func (r *Rewrite) processCallExpr(callExpr *ast.CallExpr) bool { + modified := false + + // 检查函数调用的参数中是否有函数字面量 + for _, arg := range callExpr.Args { + if funcLit, ok := arg.(*ast.FuncLit); ok { + if r.processFuncLit(funcLit) { + modified = true + } + } else if nestedCall, ok := arg.(*ast.CallExpr); ok { + // 递归处理嵌套的函数调用 + if r.processCallExpr(nestedCall) { + modified = true + } + } + } + + // 递归处理函数调用本身(如果它也是一个函数字面量) + if funcLit, ok := callExpr.Fun.(*ast.FuncLit); ok { + if r.processFuncLit(funcLit) { + modified = true + } + } + + return modified +} + +// processStmtList 递归处理语句列表 +func (r *Rewrite) processStmtList(stmts []ast.Stmt) bool { + modified := false + for _, stmt := range stmts { + if r.processStmt(stmt) { + modified = true + } + } + return modified +} + +// processStmt 递归处理语句,查找go语句和函数字面量 +func (r *Rewrite) processStmt(stmt ast.Stmt) bool { + modified := false + + switch s := stmt.(type) { + case *ast.GoStmt: + if r.processGoStmt(s) { + modified = true + } + case *ast.ExprStmt: + // 处理表达式语句中的函数调用 + if callExpr, ok := s.X.(*ast.CallExpr); ok { + modified = r.processCallExpr(callExpr) + } + case *ast.BlockStmt: + modified = r.processStmtList(s.List) + case *ast.IfStmt: + if s.Init != nil { + modified = r.processStmt(s.Init) || modified + } + if s.Body != nil { + modified = r.processStmtList(s.Body.List) || modified + } + if s.Else != nil { + modified = r.processStmt(s.Else) || modified + } + case *ast.ForStmt: + if s.Init != nil { + modified = r.processStmt(s.Init) || modified + } + if s.Body != nil { + modified = r.processStmtList(s.Body.List) || modified + } + case *ast.RangeStmt: + if s.Body != nil { + modified = r.processStmtList(s.Body.List) || modified + } + case *ast.SwitchStmt: + if s.Init != nil { + modified = r.processStmt(s.Init) || modified + } + if s.Body != nil { + for _, caseClause := range s.Body.List { + if cc, ok := caseClause.(*ast.CaseClause); ok { + modified = r.processStmtList(cc.Body) || modified + } + } + } + case *ast.TypeSwitchStmt: + if s.Init != nil { + modified = r.processStmt(s.Init) || modified + } + if s.Body != nil { + for _, caseClause := range s.Body.List { + if cc, ok := caseClause.(*ast.CaseClause); ok { + modified = r.processStmtList(cc.Body) || modified + } + } + } + case *ast.SelectStmt: + if s.Body != nil { + for _, commClause := range s.Body.List { + if cc, ok := commClause.(*ast.CommClause); ok { + modified = r.processStmtList(cc.Body) || modified + } + } + } + } + + return modified +} + func (r *Rewrite) RewriteFile() { flag := false // 插入defer函数 @@ -213,15 +401,20 @@ func (r *Rewrite) RewriteFile() { continue } - // 判断是否需要插入defer函数 - if r.HasSameDefer(funcDel) { + // 检查函数是否有函数体,没有函数体的函数(如接口方法声明)跳过 + if funcDel.Body == nil { continue } - elts := r.genTraceParams(funcDel.Type, funcDel.Recv) - deferStmt := r.genDefer(elts) - // 将defer语句添加到函数体的开头 - funcDel.Body.List = append([]ast.Stmt{deferStmt}, funcDel.Body.List...) - flag = true + + // 为函数声明添加defer语句 + if r.addDeferToBody(funcDel.Body, funcDel.Type, funcDel.Recv) { + flag = true + } + + // 递归处理函数体中的所有语句,查找go语句 + if r.processStmtList(funcDel.Body.List) { + flag = true + } } if flag { // 插入import diff --git a/internal/biz/rewrite/rewrite_test.go b/internal/biz/rewrite/rewrite_test.go new file mode 100644 index 0000000..cd54abe --- /dev/null +++ b/internal/biz/rewrite/rewrite_test.go @@ -0,0 +1,766 @@ +package rewrite + +import ( + "go/ast" + "go/token" + "os" + "path/filepath" + "strings" + "testing" +) + +func TestNewRewrite(t *testing.T) { + // 创建临时测试文件 + tmpDir := t.TempDir() + testFile := filepath.Join(tmpDir, "test.go") + + content := `package main + +func testFunc() { + fmt.Println("test") +} +` + err := os.WriteFile(testFile, []byte(content), 0644) + if err != nil { + t.Fatalf("Failed to create test file: %v", err) + } + + rewrite, err := NewRewrite(testFile) + if err != nil { + t.Fatalf("NewRewrite failed: %v", err) + } + + if rewrite == nil { + t.Fatal("NewRewrite returned nil") + } + + if rewrite.fullPath != testFile { + t.Errorf("Expected fullPath %s, got %s", testFile, rewrite.fullPath) + } + + if rewrite.fset == nil { + t.Error("fset should not be nil") + } + + if rewrite.f == nil { + t.Error("f should not be nil") + } +} + +func TestGenTraceParams(t *testing.T) { + rewrite := &Rewrite{} + + tests := []struct { + name string + funcType *ast.FuncType + recv *ast.FieldList + expected int // 期望的参数数量 + }{ + { + name: "no parameters", + funcType: &ast.FuncType{ + Params: &ast.FieldList{}, + }, + expected: 0, + }, + { + name: "with parameters", + funcType: &ast.FuncType{ + Params: &ast.FieldList{ + List: []*ast.Field{ + { + Names: []*ast.Ident{{Name: "a"}}, + }, + { + Names: []*ast.Ident{{Name: "b"}}, + }, + }, + }, + }, + expected: 2, + }, + { + name: "with receiver", + funcType: &ast.FuncType{ + Params: &ast.FieldList{}, + }, + recv: &ast.FieldList{ + List: []*ast.Field{ + { + Names: []*ast.Ident{{Name: "r"}}, + }, + }, + }, + expected: 1, + }, + { + name: "with underscore parameters", + funcType: &ast.FuncType{ + Params: &ast.FieldList{ + List: []*ast.Field{ + { + Names: []*ast.Ident{{Name: "_"}}, + }, + { + Names: []*ast.Ident{{Name: "valid"}}, + }, + }, + }, + }, + expected: 1, // 只有valid参数会被包含 + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := rewrite.genTraceParams(tt.funcType, tt.recv) + if len(result) != tt.expected { + t.Errorf("Expected %d parameters, got %d", tt.expected, len(result)) + } + }) + } +} + +func TestGenDefer(t *testing.T) { + rewrite := &Rewrite{} + + elts := []ast.Expr{ + &ast.BasicLit{Kind: token.STRING, Value: `"param1"`}, + &ast.BasicLit{Kind: token.STRING, Value: `"param2"`}, + } + + deferStmt := rewrite.genDefer(elts) + if deferStmt == nil { + t.Fatal("genDefer returned nil") + } + + // 检查是否为defer语句 + if deferStmt.Call == nil { + t.Error("defer statement should have a call") + } + + // 检查函数调用结构 + callExpr, ok := deferStmt.Call.Fun.(*ast.CallExpr) + if !ok { + t.Error("defer call should be a CallExpr") + } + + // 检查是否为functrace.Trace调用 + selector, ok := callExpr.Fun.(*ast.SelectorExpr) + if !ok { + t.Error("defer call should have a SelectorExpr") + } + + if ident, ok := selector.X.(*ast.Ident); !ok || ident.Name != "functrace" { + t.Error("defer call should call functrace.Trace") + } + + if selector.Sel.Name != "Trace" { + t.Error("defer call should call functrace.Trace") + } +} + +func TestHasSameDefer(t *testing.T) { + rewrite := &Rewrite{} + + tests := []struct { + name string + funcDecl *ast.FuncDecl + expected bool + }{ + { + name: "no body", + funcDecl: &ast.FuncDecl{ + Body: nil, + }, + expected: false, + }, + { + name: "no defer statements", + funcDecl: &ast.FuncDecl{ + Body: &ast.BlockStmt{ + List: []ast.Stmt{ + &ast.ExprStmt{}, + }, + }, + }, + expected: false, + }, + { + name: "has functrace defer", + funcDecl: &ast.FuncDecl{ + Body: &ast.BlockStmt{ + List: []ast.Stmt{ + &ast.DeferStmt{ + Call: &ast.CallExpr{ + Fun: &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.Ident{Name: "functrace"}, + Sel: &ast.Ident{Name: "Trace"}, + }, + }, + }, + }, + }, + }, + }, + expected: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := rewrite.HasSameDefer(tt.funcDecl) + if result != tt.expected { + t.Errorf("Expected %v, got %v", tt.expected, result) + } + }) + } +} + +func TestHasSameDeferInBody(t *testing.T) { + rewrite := &Rewrite{} + + tests := []struct { + name string + body *ast.BlockStmt + expected bool + }{ + { + name: "nil body", + body: nil, + expected: false, + }, + { + name: "no functrace defer", + body: &ast.BlockStmt{ + List: []ast.Stmt{ + &ast.DeferStmt{ + Call: &ast.CallExpr{ + Fun: &ast.Ident{Name: "otherFunc"}, + }, + }, + }, + }, + expected: false, + }, + { + name: "has functrace defer", + body: &ast.BlockStmt{ + List: []ast.Stmt{ + &ast.DeferStmt{ + Call: &ast.CallExpr{ + Fun: &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.Ident{Name: "functrace"}, + Sel: &ast.Ident{Name: "Trace"}, + }, + }, + }, + }, + }, + }, + expected: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := rewrite.hasSameDeferInBody(tt.body) + if result != tt.expected { + t.Errorf("Expected %v, got %v", tt.expected, result) + } + }) + } +} + +func TestAddDeferToBody(t *testing.T) { + rewrite := &Rewrite{} + + tests := []struct { + name string + body *ast.BlockStmt + funcType *ast.FuncType + recv *ast.FieldList + expected bool + }{ + { + name: "nil body", + body: nil, + funcType: &ast.FuncType{}, + expected: false, + }, + { + name: "empty body", + body: &ast.BlockStmt{ + List: []ast.Stmt{}, + }, + funcType: &ast.FuncType{}, + expected: true, + }, + { + name: "body with existing functrace defer", + body: &ast.BlockStmt{ + List: []ast.Stmt{ + &ast.DeferStmt{ + Call: &ast.CallExpr{ + Fun: &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.Ident{Name: "functrace"}, + Sel: &ast.Ident{Name: "Trace"}, + }, + }, + }, + }, + }, + }, + funcType: &ast.FuncType{}, + expected: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + initialLen := 0 + if tt.body != nil { + initialLen = len(tt.body.List) + } + + result := rewrite.addDeferToBody(tt.body, tt.funcType, tt.recv) + if result != tt.expected { + t.Errorf("Expected %v, got %v", tt.expected, result) + } + + // 如果应该添加defer语句,检查是否真的添加了 + if tt.expected && tt.body != nil { + if len(tt.body.List) != initialLen+1 { + t.Errorf("Expected body to have %d statements, got %d", initialLen+1, len(tt.body.List)) + } + + // 检查第一个语句是否为defer语句 + if _, ok := tt.body.List[0].(*ast.DeferStmt); !ok { + t.Error("First statement should be a defer statement") + } + } + }) + } +} + +func TestProcessFuncLit(t *testing.T) { + rewrite := &Rewrite{} + + tests := []struct { + name string + funcLit *ast.FuncLit + expected bool + }{ + { + name: "nil body", + funcLit: &ast.FuncLit{ + Body: nil, + }, + expected: false, + }, + { + name: "empty body", + funcLit: &ast.FuncLit{ + Type: &ast.FuncType{}, + Body: &ast.BlockStmt{ + List: []ast.Stmt{}, + }, + }, + expected: true, + }, + { + name: "body with existing functrace defer", + funcLit: &ast.FuncLit{ + Type: &ast.FuncType{}, + Body: &ast.BlockStmt{ + List: []ast.Stmt{ + &ast.DeferStmt{ + Call: &ast.CallExpr{ + Fun: &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.Ident{Name: "functrace"}, + Sel: &ast.Ident{Name: "Trace"}, + }, + }, + }, + }, + }, + }, + }, + expected: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := rewrite.processFuncLit(tt.funcLit) + if result != tt.expected { + t.Errorf("Expected %v, got %v", tt.expected, result) + } + }) + } +} + +func TestProcessGoStmt(t *testing.T) { + rewrite := &Rewrite{} + + tests := []struct { + name string + goStmt *ast.GoStmt + expected bool + }{ + { + name: "direct func literal", + goStmt: &ast.GoStmt{ + Call: &ast.CallExpr{ + Fun: &ast.FuncLit{ + Type: &ast.FuncType{}, + Body: &ast.BlockStmt{ + List: []ast.Stmt{}, + }, + }, + }, + }, + expected: true, + }, + { + name: "function call with func literal parameter", + goStmt: &ast.GoStmt{ + Call: &ast.CallExpr{ + Fun: &ast.Ident{Name: "someFunc"}, + Args: []ast.Expr{ + &ast.FuncLit{ + Type: &ast.FuncType{}, + Body: &ast.BlockStmt{ + List: []ast.Stmt{}, + }, + }, + }, + }, + }, + expected: true, + }, + { + name: "function call without func literal", + goStmt: &ast.GoStmt{ + Call: &ast.CallExpr{ + Fun: &ast.Ident{Name: "someFunc"}, + Args: []ast.Expr{ + &ast.BasicLit{Kind: token.STRING, Value: `"test"`}, + }, + }, + }, + expected: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := rewrite.processGoStmt(tt.goStmt) + if result != tt.expected { + t.Errorf("Expected %v, got %v", tt.expected, result) + } + }) + } +} + +func TestProcessCallExpr(t *testing.T) { + rewrite := &Rewrite{} + + tests := []struct { + name string + callExpr *ast.CallExpr + expected bool + }{ + { + name: "no func literal parameters", + callExpr: &ast.CallExpr{ + Fun: &ast.Ident{Name: "someFunc"}, + Args: []ast.Expr{ + &ast.BasicLit{Kind: token.STRING, Value: `"test"`}, + }, + }, + expected: false, + }, + { + name: "with func literal parameter", + callExpr: &ast.CallExpr{ + Fun: &ast.Ident{Name: "someFunc"}, + Args: []ast.Expr{ + &ast.FuncLit{ + Type: &ast.FuncType{}, + Body: &ast.BlockStmt{ + List: []ast.Stmt{}, + }, + }, + }, + }, + expected: true, + }, + { + name: "nested function call", + callExpr: &ast.CallExpr{ + Fun: &ast.Ident{Name: "outerFunc"}, + Args: []ast.Expr{ + &ast.CallExpr{ + Fun: &ast.Ident{Name: "innerFunc"}, + Args: []ast.Expr{ + &ast.FuncLit{ + Type: &ast.FuncType{}, + Body: &ast.BlockStmt{ + List: []ast.Stmt{}, + }, + }, + }, + }, + }, + }, + expected: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := rewrite.processCallExpr(tt.callExpr) + if result != tt.expected { + t.Errorf("Expected %v, got %v", tt.expected, result) + } + }) + } +} + +func TestRewriteFile_Integration(t *testing.T) { + // 创建临时测试文件 + tmpDir := t.TempDir() + testFile := filepath.Join(tmpDir, "test.go") + + content := `package main + +import "fmt" + +func main() { + fmt.Println("Hello") +} + +func testFunc(a, b int) string { + return "test" +} + +func (r *Receiver) method() { + go func() { + fmt.Println("goroutine") + }() + + go someFunction(func() { + fmt.Println("nested") + }) +} +` + err := os.WriteFile(testFile, []byte(content), 0644) + if err != nil { + t.Fatalf("Failed to create test file: %v", err) + } + + rewrite, err := NewRewrite(testFile) + if err != nil { + t.Fatalf("NewRewrite failed: %v", err) + } + + // 执行重写 + rewrite.RewriteFile() + + // 读取重写后的文件 + rewrittenContent, err := os.ReadFile(testFile) + if err != nil { + t.Fatalf("Failed to read rewritten file: %v", err) + } + + contentStr := string(rewrittenContent) + + // 检查是否添加了import + if !strings.Contains(contentStr, "github.com/toheart/functrace") { + t.Error("Expected functrace import to be added") + } + + // 检查是否在函数中添加了defer语句 + if !strings.Contains(contentStr, "defer functrace.Trace") { + t.Error("Expected defer functrace.Trace to be added") + } + + // 检查是否在goroutine中添加了defer语句 + if !strings.Contains(contentStr, "go func()") { + t.Error("Expected goroutine to be preserved") + } +} + +func TestRewriteFile_StringMethod(t *testing.T) { + // 创建临时测试文件 + tmpDir := t.TempDir() + testFile := filepath.Join(tmpDir, "test.go") + + content := `package main + +func (r *Receiver) String() string { + return "receiver" +} +` + err := os.WriteFile(testFile, []byte(content), 0644) + if err != nil { + t.Fatalf("Failed to create test file: %v", err) + } + + rewrite, err := NewRewrite(testFile) + if err != nil { + t.Fatalf("NewRewrite failed: %v", err) + } + + // 执行重写 + rewrite.RewriteFile() + + // 读取重写后的文件 + rewrittenContent, err := os.ReadFile(testFile) + if err != nil { + t.Fatalf("Failed to read rewritten file: %v", err) + } + + contentStr := string(rewrittenContent) + + // String方法不应该被修改 + if strings.Contains(contentStr, "defer functrace.Trace") { + t.Error("String method should not be modified") + } +} + +func TestRewriteFile_InterfaceMethod(t *testing.T) { + // 创建临时测试文件 + tmpDir := t.TempDir() + testFile := filepath.Join(tmpDir, "test.go") + + content := `package main + +type Interface interface { + Method() +} +` + err := os.WriteFile(testFile, []byte(content), 0644) + if err != nil { + t.Fatalf("Failed to create test file: %v", err) + } + + rewrite, err := NewRewrite(testFile) + if err != nil { + t.Fatalf("NewRewrite failed: %v", err) + } + + // 执行重写 + rewrite.RewriteFile() + + // 读取重写后的文件 + rewrittenContent, err := os.ReadFile(testFile) + if err != nil { + t.Fatalf("Failed to read rewritten file: %v", err) + } + + contentStr := string(rewrittenContent) + + // 接口方法不应该被修改 + if strings.Contains(contentStr, "defer functrace.Trace") { + t.Error("Interface method should not be modified") + } +} + +func TestRewriteDir(t *testing.T) { + // 创建临时目录结构 + tmpDir := t.TempDir() + + // 创建子目录 + subDir := filepath.Join(tmpDir, "subdir") + err := os.Mkdir(subDir, 0755) + if err != nil { + t.Fatalf("Failed to create subdir: %v", err) + } + + // 创建vendor目录 + vendorDir := filepath.Join(tmpDir, "vendor") + err = os.Mkdir(vendorDir, 0755) + if err != nil { + t.Fatalf("Failed to create vendor dir: %v", err) + } + + // 创建测试文件 + files := map[string]string{ + filepath.Join(tmpDir, "main.go"): `package main + +func main() { + fmt.Println("main") +}`, + filepath.Join(subDir, "helper.go"): `package helper + +func helper() { + fmt.Println("helper") +}`, + filepath.Join(vendorDir, "vendor.go"): `package vendor + +func vendor() { + fmt.Println("vendor") +}`, + filepath.Join(tmpDir, "test_test.go"): `package main + +func TestMain(t *testing.T) { + t.Log("test") +}`, + filepath.Join(tmpDir, "non_go.txt"): `This is not a Go file`, + } + + for path, content := range files { + err := os.WriteFile(path, []byte(content), 0644) + if err != nil { + t.Fatalf("Failed to create file %s: %v", path, err) + } + } + + // 执行目录重写 + RewriteDir(tmpDir) + + // 检查文件是否被修改 + mainContent, err := os.ReadFile(filepath.Join(tmpDir, "main.go")) + if err != nil { + t.Fatalf("Failed to read main.go: %v", err) + } + + if !strings.Contains(string(mainContent), "defer functrace.Trace") { + t.Error("main.go should be modified") + } + + helperContent, err := os.ReadFile(filepath.Join(subDir, "helper.go")) + if err != nil { + t.Fatalf("Failed to read helper.go: %v", err) + } + + if !strings.Contains(string(helperContent), "defer functrace.Trace") { + t.Error("helper.go should be modified") + } + + // vendor目录应该被跳过 + vendorContent, err := os.ReadFile(filepath.Join(vendorDir, "vendor.go")) + if err != nil { + t.Fatalf("Failed to read vendor.go: %v", err) + } + + if strings.Contains(string(vendorContent), "defer functrace.Trace") { + t.Error("vendor.go should not be modified") + } + + // 测试文件应该被跳过 + testContent, err := os.ReadFile(filepath.Join(tmpDir, "test_test.go")) + if err != nil { + t.Fatalf("Failed to read test_test.go: %v", err) + } + + if strings.Contains(string(testContent), "defer functrace.Trace") { + t.Error("test_test.go should not be modified") + } +} diff --git a/internal/conf/defaults.go b/internal/conf/defaults.go new file mode 100644 index 0000000..bde2bb7 --- /dev/null +++ b/internal/conf/defaults.go @@ -0,0 +1,93 @@ +package conf + +import ( + "time" + + "google.golang.org/protobuf/types/known/durationpb" +) + +// GetDefaultConfig 返回默认配置 +func GetDefaultConfig() *Bootstrap { + return &Bootstrap{ + Server: &Server{ + Http: &Server_HTTP{ + Network: "tcp", + Addr: "0.0.0.0:8001", + Timeout: durationpb.New(1 * time.Second), + }, + Grpc: &Server_GRPC{ + Network: "tcp", + Addr: "0.0.0.0:9000", + Timeout: durationpb.New(1 * time.Second), + }, + }, + Logger: &Logger{ + Level: "debug", + FilePath: "./logs/app.log", + Console: true, + MaxSize: 100, + MaxAge: 7, + MaxBackups: 10, + Compress: true, + }, + Biz: &Biz{ + Gitlab: &GitLab{ + Token: "", // 从环境变量读取 + Url: "", // 从环境变量读取 + CloneDir: "./data", + }, + Openai: &OpenAI{ + ApiKey: "", // 从环境变量读取 + ApiBase: "", // 从环境变量读取 + Model: "", // 从环境变量读取 + }, + StaticStorePath: "./data/static", + RuntimeStorePath: "./data/runtime", + FileStoragePath: "./data/files", + }, + Data: &Data{ + Dbpath: "./goanalysis.db", + }, + } +} + +// LoadFromEnv 从环境变量加载敏感配置 +func LoadFromEnv(config *Bootstrap) { + // GitLab配置 + if config.Biz != nil && config.Biz.Gitlab != nil { + if token := getEnvOrDefault("GITLAB_TOKEN", ""); token != "" { + config.Biz.Gitlab.Token = token + } + if url := getEnvOrDefault("GITLAB_API_URL", ""); url != "" { + config.Biz.Gitlab.Url = url + } + } + + // OpenAI配置 + if config.Biz != nil && config.Biz.Openai != nil { + if apiKey := getEnvOrDefault("OPENAI_API_KEY", ""); apiKey != "" { + config.Biz.Openai.ApiKey = apiKey + } + if apiBase := getEnvOrDefault("OPENAI_API_BASE", ""); apiBase != "" { + config.Biz.Openai.ApiBase = apiBase + } + if model := getEnvOrDefault("OPENAI_MODEL", ""); model != "" { + config.Biz.Openai.Model = model + } + } +} + +// getEnvOrDefault 获取环境变量,如果不存在则返回默认值 +func getEnvOrDefault(key, defaultValue string) string { + if value := getEnv(key); value != "" { + return value + } + return defaultValue +} + +// getEnv 获取环境变量(这里需要导入os包,但为了避免循环依赖,我们在这里声明) +// 实际实现会在调用处处理 +func getEnv(key string) string { + // 这个函数会在实际使用时通过os.Getenv实现 + return "" +} diff --git a/internal/conf/loader.go b/internal/conf/loader.go new file mode 100644 index 0000000..caab23f --- /dev/null +++ b/internal/conf/loader.go @@ -0,0 +1,207 @@ +package conf + +import ( + "os" + "strconv" + "strings" + "time" + + "github.com/go-kratos/kratos/v2/config" + "github.com/go-kratos/kratos/v2/config/file" + "github.com/spf13/cobra" + "google.golang.org/protobuf/types/known/durationpb" +) + +// LoadConfig 加载配置,优先级:命令行参数 > 环境变量 > 配置文件 > 默认值 +func LoadConfig(cmd *cobra.Command) (*Bootstrap, error) { + // 1. 加载默认配置 + config := GetDefaultConfig() + + // 2. 如果指定了配置文件,加载配置文件 + if configFile := cmd.Flag("conf").Value.String(); configFile != "" { + if err := loadFromFile(configFile, config); err != nil { + return nil, err + } + } + + // 3. 从环境变量加载敏感信息 + loadFromEnv(config) + + // 4. 命令行参数覆盖(最高优先级) + loadFromFlags(cmd, config) + + return config, nil +} + +// loadFromFile 从配置文件加载配置 +func loadFromFile(configFile string, bootstrap *Bootstrap) error { + c := config.New( + config.WithSource( + file.NewSource(configFile), + ), + ) + defer c.Close() + + if err := c.Load(); err != nil { + return err + } + + return c.Scan(bootstrap) +} + +// loadFromEnv 从环境变量加载配置 +func loadFromEnv(config *Bootstrap) { + // GitLab配置 + if config.Biz != nil && config.Biz.Gitlab != nil { + if token := os.Getenv("GITLAB_TOKEN"); token != "" { + config.Biz.Gitlab.Token = token + } + if url := os.Getenv("GITLAB_API_URL"); url != "" { + config.Biz.Gitlab.Url = url + } + } + + // OpenAI配置 + if config.Biz != nil && config.Biz.Openai != nil { + if apiKey := os.Getenv("OPENAI_API_KEY"); apiKey != "" { + config.Biz.Openai.ApiKey = apiKey + } + if apiBase := os.Getenv("OPENAI_API_BASE"); apiBase != "" { + config.Biz.Openai.ApiBase = apiBase + } + if model := os.Getenv("OPENAI_MODEL"); model != "" { + config.Biz.Openai.Model = model + } + } +} + +// loadFromFlags 从命令行参数加载配置 +func loadFromFlags(cmd *cobra.Command, config *Bootstrap) { + // 服务器配置 + if flag := cmd.Flag("http-addr"); flag != nil && flag.Changed { + config.Server.Http.Addr = flag.Value.String() + } + if flag := cmd.Flag("grpc-addr"); flag != nil && flag.Changed { + config.Server.Grpc.Addr = flag.Value.String() + } + if flag := cmd.Flag("http-timeout"); flag != nil && flag.Changed { + if timeout, err := time.ParseDuration(flag.Value.String()); err == nil { + config.Server.Http.Timeout = durationpb.New(timeout) + } + } + if flag := cmd.Flag("grpc-timeout"); flag != nil && flag.Changed { + if timeout, err := time.ParseDuration(flag.Value.String()); err == nil { + config.Server.Grpc.Timeout = durationpb.New(timeout) + } + } + + // 日志配置 + if flag := cmd.Flag("log-level"); flag != nil && flag.Changed { + config.Logger.Level = flag.Value.String() + } + if flag := cmd.Flag("log-file"); flag != nil && flag.Changed { + config.Logger.FilePath = flag.Value.String() + } + if flag := cmd.Flag("log-console"); flag != nil && flag.Changed { + if console, err := strconv.ParseBool(flag.Value.String()); err == nil { + config.Logger.Console = console + } + } + if flag := cmd.Flag("log-max-size"); flag != nil && flag.Changed { + if maxSize, err := strconv.ParseInt(flag.Value.String(), 10, 32); err == nil { + config.Logger.MaxSize = int32(maxSize) + } + } + if flag := cmd.Flag("log-max-age"); flag != nil && flag.Changed { + if maxAge, err := strconv.ParseInt(flag.Value.String(), 10, 32); err == nil { + config.Logger.MaxAge = int32(maxAge) + } + } + if flag := cmd.Flag("log-max-backups"); flag != nil && flag.Changed { + if maxBackups, err := strconv.ParseInt(flag.Value.String(), 10, 32); err == nil { + config.Logger.MaxBackups = int32(maxBackups) + } + } + if flag := cmd.Flag("log-compress"); flag != nil && flag.Changed { + if compress, err := strconv.ParseBool(flag.Value.String()); err == nil { + config.Logger.Compress = compress + } + } + + // 业务配置 + if flag := cmd.Flag("gitlab-token"); flag != nil && flag.Changed { + config.Biz.Gitlab.Token = flag.Value.String() + } + if flag := cmd.Flag("gitlab-url"); flag != nil && flag.Changed { + config.Biz.Gitlab.Url = flag.Value.String() + } + if flag := cmd.Flag("gitlab-clone-dir"); flag != nil && flag.Changed { + config.Biz.Gitlab.CloneDir = flag.Value.String() + } + if flag := cmd.Flag("openai-api-key"); flag != nil && flag.Changed { + config.Biz.Openai.ApiKey = flag.Value.String() + } + if flag := cmd.Flag("openai-api-base"); flag != nil && flag.Changed { + config.Biz.Openai.ApiBase = flag.Value.String() + } + if flag := cmd.Flag("openai-model"); flag != nil && flag.Changed { + config.Biz.Openai.Model = flag.Value.String() + } + if flag := cmd.Flag("static-store-path"); flag != nil && flag.Changed { + config.Biz.StaticStorePath = flag.Value.String() + } + if flag := cmd.Flag("runtime-store-path"); flag != nil && flag.Changed { + config.Biz.RuntimeStorePath = flag.Value.String() + } + if flag := cmd.Flag("file-storage-path"); flag != nil && flag.Changed { + config.Biz.FileStoragePath = flag.Value.String() + } + + // 数据配置 + if flag := cmd.Flag("db-path"); flag != nil && flag.Changed { + config.Data.Dbpath = flag.Value.String() + } +} + +// ValidateConfig 验证配置 +func ValidateConfig(config *Bootstrap) error { + // 验证服务器配置 + if config.Server == nil { + config.Server = &Server{} + } + if config.Server.Http == nil { + config.Server.Http = &Server_HTTP{} + } + if config.Server.Grpc == nil { + config.Server.Grpc = &Server_GRPC{} + } + + // 验证日志配置 + if config.Logger == nil { + config.Logger = &Logger{} + } + + // 验证业务配置 + if config.Biz == nil { + config.Biz = &Biz{} + } + if config.Biz.Gitlab == nil { + config.Biz.Gitlab = &GitLab{} + } + if config.Biz.Openai == nil { + config.Biz.Openai = &OpenAI{} + } + + // 验证数据配置 + if config.Data == nil { + config.Data = &Data{} + } + + return nil +} + +// ParseDuration 解析时间字符串 +func ParseDuration(s string) (time.Duration, error) { + s = strings.TrimSpace(s) + return time.ParseDuration(s) +} diff --git a/internal/data/ent/runtime/gen/migrate/schema.go b/internal/data/ent/runtime/gen/migrate/schema.go index d365063..e276704 100644 --- a/internal/data/ent/runtime/gen/migrate/schema.go +++ b/internal/data/ent/runtime/gen/migrate/schema.go @@ -29,7 +29,7 @@ var ( {Name: "id", Type: field.TypeInt64, Increment: true}, {Name: "traceId", Type: field.TypeInt64}, {Name: "position", Type: field.TypeInt}, - {Name: "data", Type: field.TypeString, Default: ""}, + {Name: "data", Type: field.TypeBytes}, {Name: "isReceiver", Type: field.TypeBool, Default: false}, {Name: "baseId", Type: field.TypeInt64, Nullable: true}, } diff --git a/internal/data/ent/runtime/gen/mutation.go b/internal/data/ent/runtime/gen/mutation.go index 79c882d..079e35a 100644 --- a/internal/data/ent/runtime/gen/mutation.go +++ b/internal/data/ent/runtime/gen/mutation.go @@ -737,7 +737,7 @@ type ParamStoreDataMutation struct { addtraceId *int64 position *int addposition *int - data *string + data *[]byte isReceiver *bool baseId *int64 addbaseId *int64 @@ -964,12 +964,12 @@ func (m *ParamStoreDataMutation) ResetPosition() { } // SetData sets the "data" field. -func (m *ParamStoreDataMutation) SetData(s string) { - m.data = &s +func (m *ParamStoreDataMutation) SetData(b []byte) { + m.data = &b } // Data returns the value of the "data" field in the mutation. -func (m *ParamStoreDataMutation) Data() (r string, exists bool) { +func (m *ParamStoreDataMutation) Data() (r []byte, exists bool) { v := m.data if v == nil { return @@ -980,7 +980,7 @@ func (m *ParamStoreDataMutation) Data() (r string, exists bool) { // OldData returns the old "data" field's value of the ParamStoreData entity. // If the ParamStoreData object wasn't provided to the builder, the object is fetched from the database. // An error is returned if the mutation operation is not UpdateOne, or the database query fails. -func (m *ParamStoreDataMutation) OldData(ctx context.Context) (v string, err error) { +func (m *ParamStoreDataMutation) OldData(ctx context.Context) (v []byte, err error) { if !m.op.Is(OpUpdateOne) { return v, errors.New("OldData is only allowed on UpdateOne operations") } @@ -1216,7 +1216,7 @@ func (m *ParamStoreDataMutation) SetField(name string, value ent.Value) error { m.SetPosition(v) return nil case paramstoredata.FieldData: - v, ok := value.(string) + v, ok := value.([]byte) if !ok { return fmt.Errorf("unexpected type %T for field %s", value, name) } diff --git a/internal/data/ent/runtime/gen/paramstoredata.go b/internal/data/ent/runtime/gen/paramstoredata.go index 2ee3cd5..6b1847f 100644 --- a/internal/data/ent/runtime/gen/paramstoredata.go +++ b/internal/data/ent/runtime/gen/paramstoredata.go @@ -22,7 +22,7 @@ type ParamStoreData struct { // 参数位置 Position int `json:"position,omitempty"` // 参数JSON数据 - Data string `json:"data,omitempty"` + Data []byte `json:"data,omitempty"` // 是否为接收者参数 IsReceiver bool `json:"isReceiver,omitempty"` // 基础参数ID(自关联,当参数为增量存储时使用) @@ -35,12 +35,12 @@ func (*ParamStoreData) scanValues(columns []string) ([]any, error) { values := make([]any, len(columns)) for i := range columns { switch columns[i] { + case paramstoredata.FieldData: + values[i] = new([]byte) case paramstoredata.FieldIsReceiver: values[i] = new(sql.NullBool) case paramstoredata.FieldID, paramstoredata.FieldTraceId, paramstoredata.FieldPosition, paramstoredata.FieldBaseId: values[i] = new(sql.NullInt64) - case paramstoredata.FieldData: - values[i] = new(sql.NullString) default: values[i] = new(sql.UnknownType) } @@ -75,10 +75,10 @@ func (psd *ParamStoreData) assignValues(columns []string, values []any) error { psd.Position = int(value.Int64) } case paramstoredata.FieldData: - if value, ok := values[i].(*sql.NullString); !ok { + if value, ok := values[i].(*[]byte); !ok { return fmt.Errorf("unexpected type %T for field data", values[i]) - } else if value.Valid { - psd.Data = value.String + } else if value != nil { + psd.Data = *value } case paramstoredata.FieldIsReceiver: if value, ok := values[i].(*sql.NullBool); !ok { @@ -136,7 +136,7 @@ func (psd *ParamStoreData) String() string { builder.WriteString(fmt.Sprintf("%v", psd.Position)) builder.WriteString(", ") builder.WriteString("data=") - builder.WriteString(psd.Data) + builder.WriteString(fmt.Sprintf("%v", psd.Data)) builder.WriteString(", ") builder.WriteString("isReceiver=") builder.WriteString(fmt.Sprintf("%v", psd.IsReceiver)) diff --git a/internal/data/ent/runtime/gen/paramstoredata/paramstoredata.go b/internal/data/ent/runtime/gen/paramstoredata/paramstoredata.go index 4794901..91805a0 100644 --- a/internal/data/ent/runtime/gen/paramstoredata/paramstoredata.go +++ b/internal/data/ent/runtime/gen/paramstoredata/paramstoredata.go @@ -47,7 +47,7 @@ func ValidColumn(column string) bool { var ( // DefaultData holds the default value on creation for the "data" field. - DefaultData string + DefaultData []byte // DefaultIsReceiver holds the default value on creation for the "isReceiver" field. DefaultIsReceiver bool ) @@ -70,11 +70,6 @@ func ByPosition(opts ...sql.OrderTermOption) OrderOption { return sql.OrderByField(FieldPosition, opts...).ToFunc() } -// ByData orders the results by the data field. -func ByData(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldData, opts...).ToFunc() -} - // ByIsReceiver orders the results by the isReceiver field. func ByIsReceiver(opts ...sql.OrderTermOption) OrderOption { return sql.OrderByField(FieldIsReceiver, opts...).ToFunc() diff --git a/internal/data/ent/runtime/gen/paramstoredata/where.go b/internal/data/ent/runtime/gen/paramstoredata/where.go index 55f880f..e93b767 100644 --- a/internal/data/ent/runtime/gen/paramstoredata/where.go +++ b/internal/data/ent/runtime/gen/paramstoredata/where.go @@ -63,7 +63,7 @@ func Position(v int) predicate.ParamStoreData { } // Data applies equality check predicate on the "data" field. It's identical to DataEQ. -func Data(v string) predicate.ParamStoreData { +func Data(v []byte) predicate.ParamStoreData { return predicate.ParamStoreData(sql.FieldEQ(FieldData, v)) } @@ -158,70 +158,45 @@ func PositionLTE(v int) predicate.ParamStoreData { } // DataEQ applies the EQ predicate on the "data" field. -func DataEQ(v string) predicate.ParamStoreData { +func DataEQ(v []byte) predicate.ParamStoreData { return predicate.ParamStoreData(sql.FieldEQ(FieldData, v)) } // DataNEQ applies the NEQ predicate on the "data" field. -func DataNEQ(v string) predicate.ParamStoreData { +func DataNEQ(v []byte) predicate.ParamStoreData { return predicate.ParamStoreData(sql.FieldNEQ(FieldData, v)) } // DataIn applies the In predicate on the "data" field. -func DataIn(vs ...string) predicate.ParamStoreData { +func DataIn(vs ...[]byte) predicate.ParamStoreData { return predicate.ParamStoreData(sql.FieldIn(FieldData, vs...)) } // DataNotIn applies the NotIn predicate on the "data" field. -func DataNotIn(vs ...string) predicate.ParamStoreData { +func DataNotIn(vs ...[]byte) predicate.ParamStoreData { return predicate.ParamStoreData(sql.FieldNotIn(FieldData, vs...)) } // DataGT applies the GT predicate on the "data" field. -func DataGT(v string) predicate.ParamStoreData { +func DataGT(v []byte) predicate.ParamStoreData { return predicate.ParamStoreData(sql.FieldGT(FieldData, v)) } // DataGTE applies the GTE predicate on the "data" field. -func DataGTE(v string) predicate.ParamStoreData { +func DataGTE(v []byte) predicate.ParamStoreData { return predicate.ParamStoreData(sql.FieldGTE(FieldData, v)) } // DataLT applies the LT predicate on the "data" field. -func DataLT(v string) predicate.ParamStoreData { +func DataLT(v []byte) predicate.ParamStoreData { return predicate.ParamStoreData(sql.FieldLT(FieldData, v)) } // DataLTE applies the LTE predicate on the "data" field. -func DataLTE(v string) predicate.ParamStoreData { +func DataLTE(v []byte) predicate.ParamStoreData { return predicate.ParamStoreData(sql.FieldLTE(FieldData, v)) } -// DataContains applies the Contains predicate on the "data" field. -func DataContains(v string) predicate.ParamStoreData { - return predicate.ParamStoreData(sql.FieldContains(FieldData, v)) -} - -// DataHasPrefix applies the HasPrefix predicate on the "data" field. -func DataHasPrefix(v string) predicate.ParamStoreData { - return predicate.ParamStoreData(sql.FieldHasPrefix(FieldData, v)) -} - -// DataHasSuffix applies the HasSuffix predicate on the "data" field. -func DataHasSuffix(v string) predicate.ParamStoreData { - return predicate.ParamStoreData(sql.FieldHasSuffix(FieldData, v)) -} - -// DataEqualFold applies the EqualFold predicate on the "data" field. -func DataEqualFold(v string) predicate.ParamStoreData { - return predicate.ParamStoreData(sql.FieldEqualFold(FieldData, v)) -} - -// DataContainsFold applies the ContainsFold predicate on the "data" field. -func DataContainsFold(v string) predicate.ParamStoreData { - return predicate.ParamStoreData(sql.FieldContainsFold(FieldData, v)) -} - // IsReceiverEQ applies the EQ predicate on the "isReceiver" field. func IsReceiverEQ(v bool) predicate.ParamStoreData { return predicate.ParamStoreData(sql.FieldEQ(FieldIsReceiver, v)) diff --git a/internal/data/ent/runtime/gen/paramstoredata_create.go b/internal/data/ent/runtime/gen/paramstoredata_create.go index 6873dfd..9eef226 100644 --- a/internal/data/ent/runtime/gen/paramstoredata_create.go +++ b/internal/data/ent/runtime/gen/paramstoredata_create.go @@ -32,16 +32,8 @@ func (psdc *ParamStoreDataCreate) SetPosition(i int) *ParamStoreDataCreate { } // SetData sets the "data" field. -func (psdc *ParamStoreDataCreate) SetData(s string) *ParamStoreDataCreate { - psdc.mutation.SetData(s) - return psdc -} - -// SetNillableData sets the "data" field if the given value is not nil. -func (psdc *ParamStoreDataCreate) SetNillableData(s *string) *ParamStoreDataCreate { - if s != nil { - psdc.SetData(*s) - } +func (psdc *ParamStoreDataCreate) SetData(b []byte) *ParamStoreDataCreate { + psdc.mutation.SetData(b) return psdc } @@ -179,7 +171,7 @@ func (psdc *ParamStoreDataCreate) createSpec() (*ParamStoreData, *sqlgraph.Creat _node.Position = value } if value, ok := psdc.mutation.Data(); ok { - _spec.SetField(paramstoredata.FieldData, field.TypeString, value) + _spec.SetField(paramstoredata.FieldData, field.TypeBytes, value) _node.Data = value } if value, ok := psdc.mutation.IsReceiver(); ok { diff --git a/internal/data/ent/runtime/gen/paramstoredata_update.go b/internal/data/ent/runtime/gen/paramstoredata_update.go index 86ad74f..11cd8f1 100644 --- a/internal/data/ent/runtime/gen/paramstoredata_update.go +++ b/internal/data/ent/runtime/gen/paramstoredata_update.go @@ -70,16 +70,8 @@ func (psdu *ParamStoreDataUpdate) AddPosition(i int) *ParamStoreDataUpdate { } // SetData sets the "data" field. -func (psdu *ParamStoreDataUpdate) SetData(s string) *ParamStoreDataUpdate { - psdu.mutation.SetData(s) - return psdu -} - -// SetNillableData sets the "data" field if the given value is not nil. -func (psdu *ParamStoreDataUpdate) SetNillableData(s *string) *ParamStoreDataUpdate { - if s != nil { - psdu.SetData(*s) - } +func (psdu *ParamStoreDataUpdate) SetData(b []byte) *ParamStoreDataUpdate { + psdu.mutation.SetData(b) return psdu } @@ -178,7 +170,7 @@ func (psdu *ParamStoreDataUpdate) sqlSave(ctx context.Context) (n int, err error _spec.AddField(paramstoredata.FieldPosition, field.TypeInt, value) } if value, ok := psdu.mutation.Data(); ok { - _spec.SetField(paramstoredata.FieldData, field.TypeString, value) + _spec.SetField(paramstoredata.FieldData, field.TypeBytes, value) } if value, ok := psdu.mutation.IsReceiver(); ok { _spec.SetField(paramstoredata.FieldIsReceiver, field.TypeBool, value) @@ -255,16 +247,8 @@ func (psduo *ParamStoreDataUpdateOne) AddPosition(i int) *ParamStoreDataUpdateOn } // SetData sets the "data" field. -func (psduo *ParamStoreDataUpdateOne) SetData(s string) *ParamStoreDataUpdateOne { - psduo.mutation.SetData(s) - return psduo -} - -// SetNillableData sets the "data" field if the given value is not nil. -func (psduo *ParamStoreDataUpdateOne) SetNillableData(s *string) *ParamStoreDataUpdateOne { - if s != nil { - psduo.SetData(*s) - } +func (psduo *ParamStoreDataUpdateOne) SetData(b []byte) *ParamStoreDataUpdateOne { + psduo.mutation.SetData(b) return psduo } @@ -393,7 +377,7 @@ func (psduo *ParamStoreDataUpdateOne) sqlSave(ctx context.Context) (_node *Param _spec.AddField(paramstoredata.FieldPosition, field.TypeInt, value) } if value, ok := psduo.mutation.Data(); ok { - _spec.SetField(paramstoredata.FieldData, field.TypeString, value) + _spec.SetField(paramstoredata.FieldData, field.TypeBytes, value) } if value, ok := psduo.mutation.IsReceiver(); ok { _spec.SetField(paramstoredata.FieldIsReceiver, field.TypeBool, value) diff --git a/internal/data/ent/runtime/gen/runtime.go b/internal/data/ent/runtime/gen/runtime.go index fce12fe..0850db3 100644 --- a/internal/data/ent/runtime/gen/runtime.go +++ b/internal/data/ent/runtime/gen/runtime.go @@ -28,7 +28,7 @@ func init() { // paramstoredataDescData is the schema descriptor for data field. paramstoredataDescData := paramstoredataFields[3].Descriptor() // paramstoredata.DefaultData holds the default value on creation for the data field. - paramstoredata.DefaultData = paramstoredataDescData.Default.(string) + paramstoredata.DefaultData = paramstoredataDescData.Default.([]byte) // paramstoredataDescIsReceiver is the schema descriptor for isReceiver field. paramstoredataDescIsReceiver := paramstoredataFields[4].Descriptor() // paramstoredata.DefaultIsReceiver holds the default value on creation for the isReceiver field. diff --git a/internal/data/ent/runtime/schema/params.go b/internal/data/ent/runtime/schema/params.go index a7b006a..4907044 100644 --- a/internal/data/ent/runtime/schema/params.go +++ b/internal/data/ent/runtime/schema/params.go @@ -27,9 +27,9 @@ func (ParamStoreData) Fields() []ent.Field { StorageKey("position"). Comment("参数位置"), - field.String("data"). + field.Bytes("data"). Comment("参数JSON数据"). - Default(""), + Default([]byte{}), field.Bool("isReceiver"). StorageKey("isReceiver"). diff --git a/internal/data/sqlite/trace_ent.go b/internal/data/sqlite/trace_ent.go index 3f72008..45d5cc3 100644 --- a/internal/data/sqlite/trace_ent.go +++ b/internal/data/sqlite/trace_ent.go @@ -1,6 +1,7 @@ package sqlite import ( + "bytes" "context" "fmt" "os" @@ -12,7 +13,8 @@ import ( "entgo.io/ent/dialect" "entgo.io/ent/dialect/sql" jsonpatch "github.com/evanphx/json-patch/v5" - "github.com/toheart/goanalysis/internal/biz/entity" + "github.com/klauspost/compress/zstd" + "github.com/toheart/goanalysis/internal/biz/analysis/dos" "github.com/toheart/goanalysis/internal/data/ent/runtime/gen" "github.com/toheart/goanalysis/internal/data/ent/runtime/gen/goroutinetrace" "github.com/toheart/goanalysis/internal/data/ent/runtime/gen/paramstoredata" @@ -40,7 +42,7 @@ func NewTraceEntDB(dbPath string) (*TraceEntDB, error) { } // GetTracesByGID 根据 GID 获取跟踪数据 -func (d *TraceEntDB) GetTracesByGID(gid uint64, depth int, createTime string) ([]entity.TraceData, error) { +func (d *TraceEntDB) GetTracesByGID(gid uint64, depth int, createTime string) ([]dos.TraceData, error) { ctx := context.Background() // 查询跟踪数据 @@ -55,14 +57,15 @@ func (d *TraceEntDB) GetTracesByGID(gid uint64, depth int, createTime string) ([ } // 转换为业务实体 - var result []entity.TraceData + var result []dos.TraceData for _, trace := range traces { createdAt, err := time.Parse(time.RFC3339Nano, trace.CreatedAt) if err != nil { return nil, fmt.Errorf("parse createdAt failed: %w", err) } + // 创建业务实体 - traceData := entity.TraceData{ + traceData := dos.TraceData{ ID: int64(trace.ID), Name: trace.Name, GID: uint64(trace.Gid), @@ -81,7 +84,7 @@ func (d *TraceEntDB) GetTracesByGID(gid uint64, depth int, createTime string) ([ } // GetTraceByID 根据 ID 获取跟踪数据 -func (d *TraceEntDB) GetTraceByID(id int) (*entity.TraceData, error) { +func (d *TraceEntDB) GetTraceByID(id int) (*dos.TraceData, error) { ctx := context.Background() // 查询跟踪数据 @@ -99,7 +102,7 @@ func (d *TraceEntDB) GetTraceByID(id int) (*entity.TraceData, error) { } // 创建业务实体 - traceData := &entity.TraceData{ + traceData := &dos.TraceData{ ID: int64(trace.ID), Name: trace.Name, GID: trace.Gid, @@ -115,7 +118,7 @@ func (d *TraceEntDB) GetTraceByID(id int) (*entity.TraceData, error) { } // GetTraceChildren 获取跟踪数据的子节点 -func (d *TraceEntDB) GetTraceChildren(parentID int64) ([]entity.TraceData, error) { +func (d *TraceEntDB) GetTraceChildren(parentID int64) ([]dos.TraceData, error) { ctx := context.Background() // 查询子节点 @@ -128,14 +131,14 @@ func (d *TraceEntDB) GetTraceChildren(parentID int64) ([]entity.TraceData, error } // 转换为业务实体 - var result []entity.TraceData + var result []dos.TraceData for _, trace := range traces { createdAt, err := time.Parse(time.RFC3339Nano, trace.CreatedAt) if err != nil { return nil, fmt.Errorf("parse createdAt failed: %w", err) } // 创建业务实体 - traceData := entity.TraceData{ + traceData := dos.TraceData{ ID: int64(trace.ID), Name: trace.Name, GID: trace.Gid, @@ -159,12 +162,12 @@ func (d *TraceEntDB) Close() error { } // GetAllGIDs 获取所有的 GID,支持分页 -func (d *TraceEntDB) GetAllGIDs(page int, limit int) ([]entity.GoroutineTrace, error) { +func (d *TraceEntDB) GetAllGIDs(page int, limit int) ([]dos.GoroutineTrace, error) { ctx := context.Background() offset := (page - 1) * limit // 计算偏移量 // 查询所有不同的 GID - var gids []entity.GoroutineTrace + var gids []dos.GoroutineTrace result, err := d.client.GoroutineTrace.Query().Order(gen.Asc(goroutinetrace.FieldIsFinished)).Offset(offset).Limit(limit).All(ctx) if err != nil { return nil, fmt.Errorf("get all gids failed: %w", err) @@ -172,7 +175,7 @@ func (d *TraceEntDB) GetAllGIDs(page int, limit int) ([]entity.GoroutineTrace, e // 转换为 uint64 类型 for _, gid := range result { - gids = append(gids, entity.GoroutineTrace{ + gids = append(gids, dos.GoroutineTrace{ ID: int64(gid.ID), GID: gid.OriginGid, TimeCost: gid.TimeCost, @@ -202,7 +205,7 @@ func (d *TraceEntDB) GetAllFunctionName() ([]string, error) { } // GetParamsByID 根据 ID 获取参数 -func (d *TraceEntDB) GetParamsByID(id int32) ([]entity.TraceParams, error) { +func (d *TraceEntDB) GetParamsByID(id int32) ([]dos.TraceParams, error) { ctx := context.Background() // 查询跟踪数据 @@ -213,30 +216,33 @@ func (d *TraceEntDB) GetParamsByID(id int32) ([]entity.TraceParams, error) { } return nil, fmt.Errorf("found params failed: %w", err) } - var result []entity.TraceParams + var result []dos.TraceParams // 获取receiver参数 - for key, param := range params { + for _, param := range params { + item := dos.TraceParams{ + ID: param.ID, + TraceID: param.TraceId, + Position: param.Position, + IsReceiver: param.IsReceiver, + BaseID: *param.BaseId, + } + data := decompress(param.Data) if param.IsReceiver && param.BaseId != nil && *param.BaseId != 0 { // 通过BaseId 获取数据 parentParam, err := d.client.ParamStoreData.Query().Where(paramstoredata.ID(int64(*param.BaseId))).First(ctx) if err != nil { return nil, fmt.Errorf("found parent param failed: %w", err) } + parentParamData := decompress(parentParam.Data) // 使用jsonPath 恢复数据 - data, err := jsonpatch.MergePatch([]byte(parentParam.Data), []byte(param.Data)) + deData, err := jsonpatch.MergePatch([]byte(parentParamData), []byte(data)) if err != nil { return nil, fmt.Errorf("create merge patch failed: %w", err) } - params[key].Data = string(data) + data = string(deData) } - result = append(result, entity.TraceParams{ - ID: param.ID, - TraceID: param.TraceId, - Position: param.Position, - Data: param.Data, - IsReceiver: param.IsReceiver, - BaseID: *param.BaseId, - }) + item.Data = data + result = append(result, item) } return result, nil @@ -246,17 +252,65 @@ func (d *TraceEntDB) GetParamsByID(id int32) ([]entity.TraceParams, error) { func (d *TraceEntDB) GetGidsByFunctionName(functionName string) ([]string, error) { ctx := context.Background() - // 查询具有指定函数名的所有 GID - gids, err := d.client.TraceData. + // 查询具有指定函数名的所有跟踪数据,不按GID分组 + traces, err := d.client.TraceData. Query(). Where(tracedata.Name(functionName)). - GroupBy(tracedata.FieldGid). - Strings(ctx) + All(ctx) if err != nil { - return nil, fmt.Errorf("查询函数名对应的 GID 失败: %w", err) + return nil, fmt.Errorf("查询函数名对应的跟踪数据失败: %w", err) } - return gids, nil + // 用于去重的map,key为"gid:parentId" + processedGIDParentID := make(map[string]bool) + var result []string + + for _, trace := range traces { + // 创建唯一键:gid:parentId + uniqueKey := fmt.Sprintf("%d:%d", trace.Gid, trace.ParentId) + + // 如果已经处理过相同的gid:parentId组合,跳过 + if processedGIDParentID[uniqueKey] { + continue + } + + // 标记为已处理 + processedGIDParentID[uniqueKey] = true + + // 将GID添加到结果中 + result = append(result, fmt.Sprintf("%d", trace.Gid)) + } + + return result, nil +} + +// GetGoroutineByGID 根据 GID 获取单个 Goroutine 信息 +func (d *TraceEntDB) GetGoroutineByGID(gid int64) (*dos.GoroutineTrace, error) { + ctx := context.Background() + + // 查询指定 GID 的 Goroutine 信息 + goroutine, err := d.client.GoroutineTrace. + Query(). + Where(goroutinetrace.ID(gid)). + First(ctx) + if err != nil { + if gen.IsNotFound(err) { + return nil, fmt.Errorf("Goroutine with GID %d not found", gid) + } + return nil, fmt.Errorf("查询 Goroutine 信息失败: %w", err) + } + + // 转换为业务实体 + result := &dos.GoroutineTrace{ + ID: int64(goroutine.ID), + GID: goroutine.OriginGid, + TimeCost: goroutine.TimeCost, + CreateTime: goroutine.CreateTime, + IsFinished: goroutine.IsFinished, + InitFuncName: goroutine.InitFuncName, + } + + return result, nil } // GetTotalGIDs 获取 GID 总数 @@ -296,7 +350,7 @@ func (d *TraceEntDB) GetInitialFunc(gid uint64) (string, error) { } // GetTracesByParentId 根据父函数 ID 查询函数调用 -func (d *TraceEntDB) GetTracesByParentId(parentId int64) ([]entity.TraceData, error) { +func (d *TraceEntDB) GetTracesByParentId(parentId int64) ([]dos.TraceData, error) { ctx := context.Background() // 查询具有指定父 ID 的所有跟踪数据 @@ -314,14 +368,14 @@ func (d *TraceEntDB) GetTracesByParentId(parentId int64) ([]entity.TraceData, er } // 转换为业务实体 - var result []entity.TraceData + var result []dos.TraceData for _, trace := range traces { createdAt, err := time.Parse(time.RFC3339Nano, trace.CreatedAt) if err != nil { return nil, fmt.Errorf("parse createdAt failed: %w", err) } // 创建业务实体 - traceData := entity.TraceData{ + traceData := dos.TraceData{ ID: int64(trace.ID), Name: trace.Name, GID: uint64(trace.Gid), @@ -340,7 +394,7 @@ func (d *TraceEntDB) GetTracesByParentId(parentId int64) ([]entity.TraceData, er } // GetAllParentIds 获取所有的父函数 ID -func (d *TraceEntDB) GetAllParentFunctions(functionName string) ([]*entity.Function, error) { +func (d *TraceEntDB) GetAllParentFunctions(functionName string) ([]*dos.Function, error) { ctx := context.Background() // 查询所有不为空的父 ID @@ -372,9 +426,9 @@ func (d *TraceEntDB) GetAllParentFunctions(functionName string) ([]*entity.Funct } // 转换为 int64 类型 - var result []*entity.Function + var result []*dos.Function for _, item := range parentFunctions { - f := entity.NewFunction(int64(item.ID), item.Name, 0, "0ms", "0ms") + f := dos.NewFunction(int64(item.ID), item.Name, 0, "0ms", "0ms") f.SetPackage() result = append(result, f) } @@ -383,7 +437,7 @@ func (d *TraceEntDB) GetAllParentFunctions(functionName string) ([]*entity.Funct } // GetChildFunctions 获取函数的子函数 -func (d *TraceEntDB) GetChildFunctions(parentId int64) ([]*entity.Function, error) { +func (d *TraceEntDB) GetChildFunctions(parentId int64) ([]*dos.Function, error) { ctx := context.Background() // 查询具有指定父 ID 的所有不同函数名 @@ -399,9 +453,9 @@ func (d *TraceEntDB) GetChildFunctions(parentId int64) ([]*entity.Function, erro if err != nil { return nil, fmt.Errorf("查询子函数失败: %w", err) } - result := make([]*entity.Function, 0) + result := make([]*dos.Function, 0) for _, item := range childFunctions { - f := entity.NewFunction(int64(item.ID), item.Name, 0, item.TimeCost, "0ms") + f := dos.NewFunction(int64(item.ID), item.Name, 0, item.TimeCost, "0ms") f.ParamCount = item.ParamsCount f.Depth = item.Indent + 1 f.Seq = item.Seq // 添加seq字段 @@ -412,7 +466,7 @@ func (d *TraceEntDB) GetChildFunctions(parentId int64) ([]*entity.Function, erro } // GetHotFunctions 获取热点函数分析数据 -func (d *TraceEntDB) GetHotFunctions(sortBy string) ([]entity.Function, error) { +func (d *TraceEntDB) GetHotFunctions(sortBy string) ([]dos.Function, error) { ctx := context.Background() // 查询所有跟踪数据 @@ -444,7 +498,7 @@ func (d *TraceEntDB) GetHotFunctions(sortBy string) ([]entity.Function, error) { } // 转换为热点函数列表 - var hotFunctions []entity.Function + var hotFunctions []dos.Function for name, stats := range funcStats { // 提取包名 parts := strings.Split(name, ".") @@ -475,7 +529,7 @@ func (d *TraceEntDB) GetHotFunctions(sortBy string) ([]entity.Function, error) { avgTimeStr = fmt.Sprintf("%.2fms", avgTime) } - hotFunctions = append(hotFunctions, entity.Function{ + hotFunctions = append(hotFunctions, dos.Function{ Name: name, Package: pkg, CallCount: stats.CallCount, @@ -519,10 +573,9 @@ func parseTimeString(timeStr string) float64 { return value } -// GetGoroutineStats 获取 Goroutine 统计信息 -func (d *TraceEntDB) GetGoroutineStats() (*entity.GoroutineStats, error) { +// GetActiveGoroutineCount 获取活跃Goroutine数量 +func (d *TraceEntDB) GetActiveGoroutineCount() (int, error) { ctx := context.Background() - stats := &entity.GoroutineStats{} // 使用GoroutineTrace表获取活跃Goroutine数量 gids, err := d.client.GoroutineTrace. @@ -530,9 +583,15 @@ func (d *TraceEntDB) GetGoroutineStats() (*entity.GoroutineStats, error) { Where(goroutinetrace.IsFinished(0)). All(ctx) if err != nil { - return nil, fmt.Errorf("found active goroutines failed: %w", err) + return 0, fmt.Errorf("found active goroutines failed: %w", err) } - stats.Active = len(gids) + + return len(gids), nil +} + +// GetMaxCallDepth 获取最大调用深度 +func (d *TraceEntDB) GetMaxCallDepth() (int, error) { + ctx := context.Background() // 通过TraceData表获取最大调用深度 maxDepth, err := d.client.TraceData. @@ -540,50 +599,40 @@ func (d *TraceEntDB) GetGoroutineStats() (*entity.GoroutineStats, error) { Aggregate(gen.Max(tracedata.FieldIndent)). Int(ctx) if err != nil { - return nil, fmt.Errorf("found max call depth failed: %w", err) + return 0, fmt.Errorf("found max call depth failed: %w", err) } - stats.MaxDepth = maxDepth + 1 // 调用深度为最大缩进级别 + 1 - // 计算平均执行时间 + return maxDepth + 1, nil // 调用深度为最大缩进级别 + 1 +} + +// GetAllTraceTimeCosts 获取所有跟踪数据的时间消耗 +func (d *TraceEntDB) GetAllTraceTimeCosts() ([]string, error) { + ctx := context.Background() + + // 查询所有跟踪数据的时间消耗 traces, err := d.client.TraceData. Query(). + Select(tracedata.FieldTimeCost). All(ctx) if err != nil { return nil, fmt.Errorf("found traces failed: %w", err) } - var totalTime float64 - var count int + // 提取时间消耗字符串 + var timeCosts []string for _, trace := range traces { if trace.TimeCost != "" { - timeCost := parseTimeString(trace.TimeCost) - if timeCost > 0 { - totalTime += timeCost - count++ - } + timeCosts = append(timeCosts, trace.TimeCost) } } - // 计算平均时间 - var avgTime float64 - if count > 0 { - avgTime = totalTime / float64(count) - } - - // 格式化平均时间 - if avgTime > 1000 { - stats.AvgTime = fmt.Sprintf("%.2fs", avgTime/1000) - } else { - stats.AvgTime = fmt.Sprintf("%.2fms", avgTime) - } - - return stats, nil + return timeCosts, nil } // GetFunctionAnalysis 获取函数调用关系分析 -func (d *TraceEntDB) GetFunctionAnalysis(functionName string, queryType string) ([]entity.FunctionNode, error) { +func (d *TraceEntDB) GetFunctionAnalysis(functionName string, queryType string) ([]dos.FunctionNode, error) { // 不需要ctx变量 - var result []entity.FunctionNode + var result []dos.FunctionNode // 生成唯一ID nextID := 1 @@ -594,7 +643,7 @@ func (d *TraceEntDB) GetFunctionAnalysis(functionName string, queryType string) } // 创建根节点 - rootNode := entity.FunctionNode{ + rootNode := dos.FunctionNode{ ID: generateID(), Name: functionName, CallCount: 0, @@ -626,7 +675,7 @@ func (d *TraceEntDB) GetFunctionAnalysis(functionName string, queryType string) // 添加调用者作为子节点 for _, caller := range callers { - callerNode := entity.FunctionNode{ + callerNode := dos.FunctionNode{ ID: generateID(), Name: caller, } @@ -657,7 +706,7 @@ func (d *TraceEntDB) GetFunctionAnalysis(functionName string, queryType string) // 添加被调用者作为子节点 for _, callee := range callees { - calleeNode := entity.FunctionNode{ + calleeNode := dos.FunctionNode{ ID: generateID(), Name: callee, } @@ -758,7 +807,7 @@ func (d *TraceEntDB) GetCalleeFunctions(functionName string) ([]string, error) { } // GetTracesByFuncName 获取指定函数名的所有跟踪数据 -func (d *TraceEntDB) GetTracesByFuncName(functionName string) ([]entity.TraceData, error) { +func (d *TraceEntDB) GetTracesByFuncName(functionName string) ([]dos.TraceData, error) { ctx := context.Background() // 查询跟踪数据 @@ -771,14 +820,14 @@ func (d *TraceEntDB) GetTracesByFuncName(functionName string) ([]entity.TraceDat } // 转换为业务实体 - var result []entity.TraceData + var result []dos.TraceData for _, trace := range traces { createdAt, err := time.Parse(time.RFC3339Nano, trace.CreatedAt) if err != nil { return nil, fmt.Errorf("parse createdAt failed: %w", err) } // 创建业务实体 - traceData := entity.TraceData{ + traceData := dos.TraceData{ ID: int64(trace.ID), Name: trace.Name, GID: trace.Gid, @@ -884,7 +933,7 @@ func (d *TraceEntDB) GetGoroutineCallDepth(gid uint64) (int, error) { return maxIndent + 1, nil } -func (d *TraceEntDB) GetLastFunction() (*entity.TraceData, error) { +func (d *TraceEntDB) GetLastFunction() (*dos.TraceData, error) { ctx := context.Background() trace, err := d.client.TraceData. Query(). @@ -894,7 +943,7 @@ func (d *TraceEntDB) GetLastFunction() (*entity.TraceData, error) { return nil, fmt.Errorf("get last function failed: %w", err) } - return &entity.TraceData{ + return &dos.TraceData{ ID: int64(trace.ID), Name: trace.Name, ParamCount: trace.ParamsCount, @@ -952,7 +1001,7 @@ func (d *TraceEntDB) IsGoroutineFinished(gid uint64) (bool, error) { return goroutine.IsFinished == 1, nil } -func (d *TraceEntDB) SearchFunctions(ctx context.Context, dbPath string, query string, limit int32) ([]*entity.Function, int32, error) { +func (d *TraceEntDB) SearchFunctions(ctx context.Context, dbPath string, query string, limit int32) ([]*dos.Function, int32, error) { traces, err := d.client.TraceData.Query(). Where(tracedata.NameContains(query)). Limit(int(limit)). @@ -960,19 +1009,169 @@ func (d *TraceEntDB) SearchFunctions(ctx context.Context, dbPath string, query s if err != nil { return nil, 0, fmt.Errorf("search functions failed: %w", err) } - var functions []*entity.Function + var functions []*dos.Function for _, trace := range traces { stats, err := d.getFunctionStats(trace.Name) if err != nil { return nil, 0, fmt.Errorf("get function stats failed: %w", err) } - f := entity.NewFunction(int64(trace.ID), trace.Name, stats.CallCount, stats.AvgTime, stats.AvgTime) + f := dos.NewFunction(int64(trace.ID), trace.Name, stats.CallCount, stats.AvgTime, stats.AvgTime) f.SetPackage() functions = append(functions, f) } return functions, int32(len(functions)), nil } -func formatTime(totalTime int64) string { - return fmt.Sprintf("%d ms", totalTime) // 返回总时间的字符串格式 +// GetFunctionInfoInGoroutine 获取函数在指定Goroutine中的信息 +func (d *TraceEntDB) GetFunctionInfoInGoroutine(gid uint64, targetFunctionId int64) (*dos.FunctionInfo, error) { + ctx := context.Background() + + // 1. 查询目标函数信息 + targetTrace, err := d.client.TraceData.Query().Where( + tracedata.ID(int(targetFunctionId)), + tracedata.Gid(uint64(gid)), + ).First(ctx) + if err != nil { + if gen.IsNotFound(err) { + return nil, fmt.Errorf("function not found") + } + return nil, fmt.Errorf("query target function failed: %w", err) + } + + functionInfo := &dos.FunctionInfo{ + ID: targetFunctionId, + Name: targetTrace.Name, + Indent: targetTrace.Indent, + } + + // 2. 递归获取所有父函数信息 + parentInfos, err := d.getParentFunctionInfosRecursive(ctx, gid, targetTrace.ParentId) + if err != nil { + return nil, fmt.Errorf("get parent function infos failed: %w", err) + } + functionInfo.ParentIds = parentInfos + + return functionInfo, nil +} + +// getParentFunctionInfosRecursive 递归获取从当前parentId到深度为0的所有父函数信息列表(按调用链顺序) +func (d *TraceEntDB) getParentFunctionInfosRecursive(ctx context.Context, gid uint64, parentId int64) ([]dos.ParentInfo, error) { + var result []dos.ParentInfo + + // 递归终止条件:parentId为0或小于等于0 + if parentId <= 0 { + return result, nil + } + + // 查询当前parentId对应的TraceData + parentTrace, err := d.client.TraceData.Query().Where( + tracedata.ID(int(parentId)), + tracedata.Gid(uint64(gid)), + ).First(ctx) + if err != nil { + if gen.IsNotFound(err) { + // 如果找不到父节点,直接返回当前已获取的结果 + return result, nil + } + return nil, fmt.Errorf("query parent function failed: %w", err) + } + + // 先递归获取更高层的父节点 + upperParents, err := d.getParentFunctionInfosRecursive(ctx, gid, parentTrace.ParentId) + if err != nil { + return nil, err + } + result = append(result, upperParents...) + + // 再添加当前父节点信息 + parentInfo := dos.ParentInfo{ + ParentId: int64(parentTrace.ID), + Name: parentTrace.Name, + Depth: parentTrace.Indent, + } + result = append(result, parentInfo) + + return result, nil +} + +// GetSampledFunctionNames 获取采样后的函数名称列表 +func (d *TraceEntDB) GetSampledFunctionNames(maxSamples int32) ([]string, error) { + ctx := context.Background() + + // 首先获取总记录数 + totalCount, err := d.client.TraceData.Query().Count(ctx) + if err != nil { + return nil, fmt.Errorf("get total count failed: %w", err) + } + + var functionNames []string + + // 如果总记录数小于等于maxSamples,全量查询 + if int32(totalCount) <= maxSamples { + traces, err := d.client.TraceData.Query(). + Select(tracedata.FieldName). + All(ctx) + if err != nil { + return nil, fmt.Errorf("query all function names failed: %w", err) + } + + for _, trace := range traces { + functionNames = append(functionNames, trace.Name) + } + } else { + // 如果总记录数大于maxSamples,使用分页采样 + // 计算采样间隔 + sampleInterval := totalCount / int(maxSamples) + if sampleInterval < 1 { + sampleInterval = 1 + } + + // 分页查询进行采样 + for offset := 0; offset < totalCount && len(functionNames) < int(maxSamples); offset += sampleInterval { + traces, err := d.client.TraceData.Query(). + Select(tracedata.FieldName). + Limit(1). + Offset(offset). + All(ctx) + if err != nil { + return nil, fmt.Errorf("query sampled function names failed: %w", err) + } + + if len(traces) > 0 { + functionNames = append(functionNames, traces[0].Name) + } + } + } + + return functionNames, nil +} + +var ( + zstdEncoder, _ = zstd.NewWriter(nil) + zstdDecoder, _ = zstd.NewReader(nil) + magicNumber = []byte{'F', 'T', 'Z', '$'} // Fun-Trace-Zstd Magic Number +) + +// compress uses zstd to compress a string and returns the compressed data prefixed with a magic number. +func compress(s string) []byte { + compressed := zstdEncoder.EncodeAll([]byte(s), nil) + return append(magicNumber, compressed...) +} + +// decompress uses zstd to decompress data. It checks for a magic number to identify +// compressed data and includes a fallback for uncompressed or corrupted data. +func decompress(data []byte) string { + if len(data) < len(magicNumber) || !bytes.Equal(data[:len(magicNumber)], magicNumber) { + // Data doesn't have the magic number, so it's legacy uncompressed data. + return string(data) + } + + // Data has the magic number, so it should be decompressed. + decompressed, err := zstdDecoder.DecodeAll(data[len(magicNumber):], nil) + if err != nil { + // Data is corrupted. The calling function will fail to unmarshal it, + // which will be logged as a high-level error. + return string(data) + } + return string(decompressed) } diff --git a/internal/service/analysis.go b/internal/service/analysis.go index 62791ca..8ef4328 100644 --- a/internal/service/analysis.go +++ b/internal/service/analysis.go @@ -8,7 +8,6 @@ import ( "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" v1 "github.com/toheart/goanalysis/api/analysis/v1" "github.com/toheart/goanalysis/internal/biz/analysis" - "github.com/toheart/goanalysis/internal/biz/entity" "github.com/toheart/goanalysis/internal/biz/rewrite" "google.golang.org/grpc" ) @@ -130,66 +129,44 @@ func (a *AnalysisService) GetParamsByID(ctx context.Context, in *v1.GetParamsByI return reply, nil } -func (a *AnalysisService) GetAllFunctionName(ctx context.Context, in *v1.GetAllFunctionNameReq) (*v1.GetAllFunctionNameReply, error) { - a.log.Infof("get all function name from db: %s", in.Dbpath) - functionNames, err := a.uc.GetAllFunctionName(in.Dbpath) - if err != nil { - return nil, err - } - return &v1.GetAllFunctionNameReply{FunctionNames: functionNames}, nil -} - func (a *AnalysisService) GetGidsByFunctionName(ctx context.Context, in *v1.GetGidsByFunctionNameReq) (*v1.GetGidsByFunctionNameReply, error) { // 获取函数名称 functionName := in.FunctionName includeMetrics := in.IncludeMetrics dbpath := in.Path // 使用 Path 字段作为 dbpath - // 获取所有GID - groutines, err := a.uc.GetAllGIDs(dbpath, 0, 1000) // 假设最多1000个GID + a.log.Infof("find %s in which goroutines, dbpath: %s", functionName, dbpath) + + // 调用业务逻辑层获取GID列表(已经处理了去重逻辑) + functions, err := a.uc.GetGidsByFunctionName(dbpath, functionName) if err != nil { + a.log.Errorf("found %s gids failed: %v", functionName, err) return nil, err } - // 过滤包含指定函数的GID - var matchingG []entity.GoroutineTrace - for _, g := range groutines { - traces, err := a.uc.GetTracesByGID(&v1.AnalysisByGIDRequest{ - Dbpath: dbpath, - Gid: uint64(g.ID), - Depth: 3, - CreateTime: "", - }) + // 构建响应 + reply := &v1.GetGidsByFunctionNameReply{} + + for _, function := range functions { + // 获取Goroutine的基本信息 + goroutine, err := a.uc.GetGoroutineByGID(dbpath, function.GID) if err != nil { + a.log.Warnf("get goroutine %d info failed: %v", function.GID, err) continue } - // 检查是否包含指定函数 - for _, trace := range traces { - // 简化函数名称进行比较 - simplifiedName := getLastSegment(removeParentheses(trace.Name)) - if simplifiedName == functionName { - matchingG = append(matchingG, g) - break - } - } - } - - // 构建响应 - reply := &v1.GetGidsByFunctionNameReply{} - for _, g := range matchingG { - - isfinished := (g.IsFinished == 1) + isfinished := (goroutine.IsFinished == 1) body := &v1.GetGidsByFunctionNameReply_Body{ - Gid: uint64(g.ID), - InitialFunc: g.InitFuncName, + Gid: function.GID, + InitialFunc: goroutine.InitFuncName, IsFinished: isfinished, + FunctionId: function.ID, } // 如果需要包含调用深度和执行时间 if includeMetrics { // 获取调用深度 - depth, err := a.uc.GetGoroutineCallDepth(dbpath, uint64(g.ID)) + depth, err := a.uc.GetGoroutineCallDepth(dbpath, function.GID) if err != nil { // 如果获取失败,使用默认值 body.Depth = 0 @@ -198,7 +175,7 @@ func (a *AnalysisService) GetGidsByFunctionName(ctx context.Context, in *v1.GetG } // 获取执行时间 - execTime, err := a.uc.GetGoroutineExecutionTime(dbpath, g) + execTime, err := a.uc.GetGoroutineExecutionTime(dbpath, *goroutine) if err != nil { // 如果获取失败,使用默认值 body.ExecutionTime = "N/A" @@ -211,7 +188,9 @@ func (a *AnalysisService) GetGidsByFunctionName(ctx context.Context, in *v1.GetG } // 获取总数 - reply.Total = int32(len(matchingG)) + reply.Total = int32(len(reply.Body)) + + a.log.Infof("found %s in %d goroutines", functionName, len(reply.Body)) return reply, nil } @@ -336,39 +315,6 @@ func (a *AnalysisService) GetGoroutineStats(ctx context.Context, in *v1.GetGorou }, nil } -// GetFunctionAnalysis 获取函数调用关系分析 -func (a *AnalysisService) GetFunctionAnalysis(ctx context.Context, in *v1.GetFunctionAnalysisReq) (*v1.GetFunctionAnalysisReply, error) { - functionNodes, err := a.uc.GetFunctionAnalysis(in.Dbpath, in.FunctionName, in.Type) - if err != nil { - return nil, err - } - - reply := &v1.GetFunctionAnalysisReply{} - reply.CallData = convertToProtoFunctionNodes(functionNodes) - return reply, nil -} - -// 转换为protobuf类型的辅助函数 -func convertToProtoFunctionNodes(nodes []entity.FunctionNode) []*v1.GetFunctionAnalysisReply_FunctionNode { - protoNodes := make([]*v1.GetFunctionAnalysisReply_FunctionNode, len(nodes)) - for i, node := range nodes { - protoNode := &v1.GetFunctionAnalysisReply_FunctionNode{ - Id: node.ID, - Name: node.Name, - Package: node.Package, - CallCount: int32(node.CallCount), - AvgTime: node.AvgTime, - } - - if len(node.Children) > 0 { - protoNode.Children = convertToProtoFunctionNodes(node.Children) - } - - protoNodes[i] = protoNode - } - return protoNodes -} - // InstrumentProject 对项目进行插桩 func (a *AnalysisService) InstrumentProject(ctx context.Context, in *v1.InstrumentProjectReq) (*v1.InstrumentProjectReply, error) { a.log.Infof("Instrumenting project at path: %s", in.Path) @@ -396,79 +342,6 @@ func (a *AnalysisService) InstrumentProject(ctx context.Context, in *v1.Instrume }, nil } -// GetTreeGraph 获取树状图 -func (a *AnalysisService) GetTreeGraph(ctx context.Context, req *v1.GetTreeGraphReq) (*v1.GetTreeGraphReply, error) { - a.log.Infof("get tree graph, function: %s, dbpath: %s, chain_type: %s, depth: %d", req.FunctionName, req.DbPath, req.ChainType, req.Depth) - - // 调用业务逻辑获取树状图数据 - trees, err := a.uc.GetTreeGraph(req.DbPath, req.FunctionName, req.ChainType, int(req.Depth)) - if err != nil { - a.log.Errorf("get tree graph failed: %v", err) - return nil, err - } - - // 转换为API响应格式 - reply := &v1.GetTreeGraphReply{ - Trees: make([]*v1.TreeNode, 0, len(trees)), - } - - // 转换每棵树节点 - for _, tree := range trees { - protoTree := a.convertTreeNodeToProto(tree) - reply.Trees = append(reply.Trees, protoTree) - } - - return reply, nil -} - -// 将实体TreeNode转换为proto TreeNode -func (a *AnalysisService) convertTreeNodeToProto(node *entity.TreeNode) *v1.TreeNode { - if node == nil { - return nil - } - - protoNode := &v1.TreeNode{ - Name: node.Name, - Value: node.Value, - Collapsed: true, - } - - // 递归转换子节点 - if len(node.Children) > 0 { - protoNode.Children = make([]*v1.TreeNode, 0, len(node.Children)) - for _, child := range node.Children { - protoNode.Children = append(protoNode.Children, a.convertTreeNodeToProto(child)) - } - } - - return protoNode -} - -// GetTreeGraphByGID 根据GID获取多棵树状图数据 -func (a *AnalysisService) GetTreeGraphByGID(ctx context.Context, req *v1.GetTreeGraphByGIDReq) (*v1.GetTreeGraphByGIDReply, error) { - a.log.Infof("get tree graph by gid: %d, dbpath: %s", req.Gid, req.DbPath) - - // 调用业务逻辑获取树状图数据 - treeTrees, err := a.uc.GetTreeGraphByGID(req.DbPath, req.Gid) - if err != nil { - a.log.Errorf("get tree graph by gid failed: %v", err) - return nil, err - } - - // 转换为API响应格式 - reply := &v1.GetTreeGraphByGIDReply{ - Trees: make([]*v1.TreeNode, 0, len(treeTrees)), - } - - // 转换每棵树 - for _, tree := range treeTrees { - protoTree := a.convertTreeNodeToProto(tree) - reply.Trees = append(reply.Trees, protoTree) - } - - return reply, nil -} - // GetFunctionCallStats 获取函数调用统计分析 func (a *AnalysisService) GetFunctionCallStats(ctx context.Context, req *v1.GetFunctionCallStatsReq) (*v1.GetFunctionCallStatsReply, error) { a.log.Infof("get function call stats, function: %s, dbpath: %s", req.FunctionName, req.DbPath) @@ -503,57 +376,71 @@ func (a *AnalysisService) GetFunctionCallStats(ctx context.Context, req *v1.GetF return reply, nil } -// GetPerformanceAnomalies 获取性能异常检测结果 -func (a *AnalysisService) GetPerformanceAnomalies(ctx context.Context, req *v1.GetPerformanceAnomaliesReq) (*v1.GetPerformanceAnomaliesReply, error) { - a.log.Infof("获取性能异常检测, 函数: %s, dbpath: %s, 阈值: %f", req.FunctionName, req.DbPath, req.Threshold) - - // 调用业务逻辑获取性能异常数据 - anomalies, err := a.uc.GetPerformanceAnomalies(req.DbPath, req.FunctionName, req.Threshold) +// SearchFunctions 实现函数搜索服务 +func (s *AnalysisService) SearchFunctions(ctx context.Context, req *v1.SearchFunctionsReq) (*v1.SearchFunctionsReply, error) { + functions, total, err := s.uc.SearchFunctions(ctx, req.Dbpath, req.Query, req.Limit) if err != nil { - a.log.Errorf("获取性能异常检测失败: %v", err) return nil, err } - // 转换为API响应格式 - reply := &v1.GetPerformanceAnomaliesReply{ - Anomalies: make([]*v1.PerformanceAnomaly, 0, len(anomalies)), + reply := &v1.SearchFunctionsReply{ + Functions: make([]*v1.SearchFunctionsReply_FunctionInfo, 0, len(functions)), + Total: total, } - for _, anomaly := range anomalies { - performanceAnomaly := &v1.PerformanceAnomaly{ - Name: anomaly.Name, - Package: anomaly.Package, - AnomalyType: anomaly.AnomalyType, - Description: anomaly.Description, - Severity: anomaly.Severity, - Details: anomaly.Details, - } - reply.Anomalies = append(reply.Anomalies, performanceAnomaly) + for _, f := range functions { + reply.Functions = append(reply.Functions, &v1.SearchFunctionsReply_FunctionInfo{ + Name: f.Name, + Package: f.Package, + }) } return reply, nil } -// SearchFunctions 实现函数搜索服务 -func (s *AnalysisService) SearchFunctions(ctx context.Context, req *v1.SearchFunctionsReq) (*v1.SearchFunctionsReply, error) { - functions, total, err := s.uc.SearchFunctions(ctx, req.Dbpath, req.Query, req.Limit) +// GetFunctionInfoInGoroutine 获取函数在指定Goroutine中的信息 +func (a *AnalysisService) GetFunctionInfoInGoroutine(ctx context.Context, in *v1.GetFunctionInfoInGoroutineReq) (*v1.GetFunctionInfoInGoroutineReply, error) { + a.log.Infof("get function info in goroutine, gid: %d, functionId: %d from db: %s", in.Gid, in.FunctionId, in.Dbpath) + + functionInfo, err := a.uc.GetFunctionInfoInGoroutine(in.Dbpath, in.Gid, in.FunctionId) if err != nil { return nil, err } - - reply := &v1.SearchFunctionsReply{ - Functions: make([]*v1.SearchFunctionsReply_FunctionInfo, 0, len(functions)), - Total: total, + // 转换ParentInfo为proto格式 + var parentInfos []*v1.ParentInfo + for _, parentInfo := range functionInfo.ParentIds { + parentInfos = append(parentInfos, &v1.ParentInfo{ + ParentId: parentInfo.ParentId, + Depth: int32(parentInfo.Depth), + Name: parentInfo.Name, + }) } - for _, f := range functions { - reply.Functions = append(reply.Functions, &v1.SearchFunctionsReply_FunctionInfo{ - Name: f.Name, - Package: f.Package, - CallCount: int32(f.CallCount), - AvgTime: f.AvgTime, - }) + reply := &v1.GetFunctionInfoInGoroutineReply{ + FunctionInfo: &v1.GetFunctionInfoInGoroutineReply_FunctionInfo{ + Id: functionInfo.ID, + Name: functionInfo.Name, + Depth: int32(functionInfo.Indent), + ParentIds: parentInfos, + }, } return reply, nil } + +func (a *AnalysisService) GetModuleNames(ctx context.Context, in *v1.GetModuleNamesReq) (*v1.GetModuleNamesReply, error) { + // 设置默认采样数量 + maxSamples := in.MaxSamples + if maxSamples <= 0 { + maxSamples = 5000 // 默认采样5000条记录 + } + + moduleNames, err := a.uc.GetModuleNames(in.Dbpath, maxSamples) + if err != nil { + return nil, err + } + + return &v1.GetModuleNamesReply{ + ModuleNames: moduleNames, + }, nil +} diff --git a/openapi.yaml b/openapi.yaml index 4207b81..a9644c7 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -122,17 +122,17 @@ paths: application/json: schema: $ref: '#/components/schemas/filemanager.v1.DownloadFileReply' - /api/runtime/function/analysis: + /api/runtime/function/info: post: tags: - Analysis - description: GetFunctionAnalysis 获取函数调用关系分析 - operationId: Analysis_GetFunctionAnalysis + description: GetFunctionInfoInGoroutine 获取函数在指定Goroutine中的信息 + operationId: Analysis_GetFunctionInfoInGoroutine requestBody: content: application/json: schema: - $ref: '#/components/schemas/analysis.v1.GetFunctionAnalysisReq' + $ref: '#/components/schemas/analysis.v1.GetFunctionInfoInGoroutineReq' required: true responses: "200": @@ -140,26 +140,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/analysis.v1.GetFunctionAnalysisReply' - /api/runtime/function/anomalies: - post: - tags: - - Analysis - description: GetPerformanceAnomalies 获取性能异常检测结果 - operationId: Analysis_GetPerformanceAnomalies - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/analysis.v1.GetPerformanceAnomaliesReq' - required: true - responses: - "200": - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/analysis.v1.GetPerformanceAnomaliesReply' + $ref: '#/components/schemas/analysis.v1.GetFunctionInfoInGoroutineReply' /api/runtime/function/stats: post: tags: @@ -179,24 +160,6 @@ paths: application/json: schema: $ref: '#/components/schemas/analysis.v1.GetFunctionCallStatsReply' - /api/runtime/functions: - post: - tags: - - Analysis - operationId: Analysis_GetAllFunctionName - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/analysis.v1.GetAllFunctionNameReq' - required: true - responses: - "200": - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/analysis.v1.GetAllFunctionNameReply' /api/runtime/functions/children: post: tags: @@ -347,6 +310,25 @@ paths: application/json: schema: $ref: '#/components/schemas/analysis.v1.InstrumentProjectReply' + /api/runtime/modules: + post: + tags: + - Analysis + description: GetModuleNames 获取数据库中的模块名称列表 + operationId: Analysis_GetModuleNames + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/analysis.v1.GetModuleNamesReq' + required: true + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/analysis.v1.GetModuleNamesReply' /api/runtime/params/{id}: post: tags: @@ -421,44 +403,6 @@ paths: application/json: schema: $ref: '#/components/schemas/analysis.v1.AnalysisByGIDReply' - /api/runtime/tree-graph: - post: - tags: - - Analysis - description: 获取运行时树状图数据 - operationId: Analysis_GetTreeGraph - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/analysis.v1.GetTreeGraphReq' - required: true - responses: - "200": - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/analysis.v1.GetTreeGraphReply' - /api/runtime/tree-graph/gid: - post: - tags: - - Analysis - description: 根据GID获取多棵树状图数据 - operationId: Analysis_GetTreeGraphByGID - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/analysis.v1.GetTreeGraphByGIDReq' - required: true - responses: - "200": - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/analysis.v1.GetTreeGraphByGIDReply' /api/runtime/verify/path: post: tags: @@ -898,18 +842,6 @@ components: format: int32 seq: type: string - analysis.v1.GetAllFunctionNameReply: - type: object - properties: - functionNames: - type: array - items: - type: string - analysis.v1.GetAllFunctionNameReq: - type: object - properties: - dbpath: - type: string analysis.v1.GetAllGIDsReply: type: object properties: @@ -963,58 +895,55 @@ components: dbpath: type: string description: GetChildFunctionsReq 获取函数的子函数的请求 - analysis.v1.GetFunctionAnalysisReply: + analysis.v1.GetFunctionCallStatsReply: type: object properties: - callData: + stats: type: array items: - $ref: '#/components/schemas/analysis.v1.GetFunctionAnalysisReply_FunctionNode' - description: GetFunctionAnalysisReply 获取函数调用关系分析的响应 - analysis.v1.GetFunctionAnalysisReply_FunctionNode: + $ref: '#/components/schemas/analysis.v1.FunctionCallStats' + description: 获取函数调用统计响应 + analysis.v1.GetFunctionCallStatsReq: + type: object + properties: + dbPath: + type: string + functionName: + type: string + description: 获取函数调用统计请求 + analysis.v1.GetFunctionInfoInGoroutineReply: + type: object + properties: + functionInfo: + $ref: '#/components/schemas/analysis.v1.GetFunctionInfoInGoroutineReply_FunctionInfo' + description: GetFunctionInfoInGoroutineReply 获取函数在指定Goroutine中的信息响应 + analysis.v1.GetFunctionInfoInGoroutineReply_FunctionInfo: type: object properties: id: type: string name: type: string - package: - type: string - callCount: + depth: type: integer format: int32 - avgTime: - type: string - children: + parentIds: type: array items: - $ref: '#/components/schemas/analysis.v1.GetFunctionAnalysisReply_FunctionNode' - analysis.v1.GetFunctionAnalysisReq: + $ref: '#/components/schemas/analysis.v1.ParentInfo' + analysis.v1.GetFunctionInfoInGoroutineReq: type: object properties: - functionName: - type: string - type: - type: string dbpath: type: string - description: GetFunctionAnalysisReq 获取函数调用关系分析的请求 - analysis.v1.GetFunctionCallStatsReply: - type: object - properties: - stats: - type: array - items: - $ref: '#/components/schemas/analysis.v1.FunctionCallStats' - description: 获取函数调用统计响应 - analysis.v1.GetFunctionCallStatsReq: - type: object - properties: - dbPath: + gid: type: string - functionName: + functionId: type: string - description: 获取函数调用统计请求 + currentDepth: + type: integer + format: int32 + description: GetFunctionInfoInGoroutineReq 获取函数在指定Goroutine中的信息请求 analysis.v1.GetGidsByFunctionNameReply: type: object properties: @@ -1039,6 +968,8 @@ components: type: string isFinished: type: boolean + functionId: + type: string analysis.v1.GetGidsByFunctionNameReq: type: object properties: @@ -1096,6 +1027,23 @@ components: dbpath: type: string description: GetHotFunctionsReq 获取热点函数的请求 + analysis.v1.GetModuleNamesReply: + type: object + properties: + moduleNames: + type: array + items: + type: string + description: GetModuleNamesReply 获取模块名称响应 + analysis.v1.GetModuleNamesReq: + type: object + properties: + dbpath: + type: string + maxSamples: + type: integer + format: int32 + description: GetModuleNamesReq 获取模块名称请求 analysis.v1.GetParamsByIDReply: type: object properties: @@ -1125,25 +1073,6 @@ components: type: string functionName: type: string - analysis.v1.GetPerformanceAnomaliesReply: - type: object - properties: - anomalies: - type: array - items: - $ref: '#/components/schemas/analysis.v1.PerformanceAnomaly' - description: 获取性能异常检测响应 - analysis.v1.GetPerformanceAnomaliesReq: - type: object - properties: - dbPath: - type: string - functionName: - type: string - threshold: - type: number - format: double - description: 获取性能异常检测请求 analysis.v1.GetTracesByParentFuncReply: type: object properties: @@ -1187,43 +1116,6 @@ components: dbpath: type: string description: GetTracesByParentFuncReq 根据父函数ID获取函数调用的请求 - analysis.v1.GetTreeGraphByGIDReply: - type: object - properties: - trees: - type: array - items: - $ref: '#/components/schemas/analysis.v1.TreeNode' - description: 根据GID获取树状图响应 - 返回多棵树 - analysis.v1.GetTreeGraphByGIDReq: - type: object - properties: - dbPath: - type: string - gid: - type: string - description: 根据GID获取树状图请求 - analysis.v1.GetTreeGraphReply: - type: object - properties: - trees: - type: array - items: - $ref: '#/components/schemas/analysis.v1.TreeNode' - description: 获取树状图响应 - analysis.v1.GetTreeGraphReq: - type: object - properties: - dbPath: - type: string - functionName: - type: string - chainType: - type: string - depth: - type: integer - format: int32 - description: 获取树状图请求 analysis.v1.InstrumentProjectReply: type: object properties: @@ -1238,25 +1130,17 @@ components: path: type: string description: 插桩请求 - analysis.v1.PerformanceAnomaly: + analysis.v1.ParentInfo: type: object properties: - name: - type: string - package: - type: string - anomalyType: + parentId: type: string - description: + name: type: string - severity: - type: number - format: double - details: - type: object - additionalProperties: - type: string - description: 性能异常信息 + depth: + type: integer + format: int32 + description: ParentInfo 父函数信息 analysis.v1.SearchFunctionsReply: type: object properties: @@ -1275,11 +1159,6 @@ components: type: string package: type: string - callCount: - type: integer - format: int32 - avgTime: - type: string analysis.v1.SearchFunctionsReq: type: object properties: @@ -1299,20 +1178,6 @@ components: format: int32 param: type: string - analysis.v1.TreeNode: - type: object - properties: - name: - type: string - value: - type: string - collapsed: - type: boolean - children: - type: array - items: - $ref: '#/components/schemas/analysis.v1.TreeNode' - description: 树状图节点 analysis.v1.VerifyProjectPathReply: type: object properties: