This is an automated email from the ASF dual-hosted git repository.

wangtao29 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozhera.git


The following commit(s) were added to refs/heads/master by this push:
     new cab5b4e2 refactor: refactor ozhera intelligence (#612)
cab5b4e2 is described below

commit cab5b4e2f71b56a4ee8d744a39ea220321cf952d
Author: EricDing <[email protected]>
AuthorDate: Mon Nov 17 09:31:54 2025 +0800

    refactor: refactor ozhera intelligence (#612)
    
    * refactor: refactor ozhera intelligence
    
    * feat: add coder tool and git mcp
---
 ozhera-intelligence/README_cn.md                   |   2 +-
 .../{MarkDownParam.java => CodeFixInfo.java}       |  39 +--
 .../domain/rootanalysis/MarkDownParam.java         |   4 +
 .../domain/rootanalysis/TracePromptResult.java     |   3 +
 .../domain/rootanalysis/constant/Prompts.java      |  32 +++
 .../bootstrap/IntelligenceBootStrap.java           |   2 +-
 .../intelligence/config/DubboConfiguration.java    |   4 +-
 .../intelligence/filter/TokenValidationFilter.java |   4 +-
 .../src/main/resources/application.properties      |  24 +-
 .../resources/config/opensource-outer.properties   |  23 +-
 .../ozhera-intelligence-service/pom.xml            |  22 ++
 .../intelligence/agents/config/AgentConfig.java    |  70 +++--
 .../intelligence/agents/tool/CodeFixTool.java      | 319 +++++++++++++++++++++
 .../agents/tool/TraceAnalysisTool.java             | 217 ++++++++++++++
 .../ozhera/intelligence/service/LogService.java    |   2 +-
 .../intelligence/service/MetricsService.java       |   4 +-
 .../ozhera/intelligence/service/PromptService.java |  27 ++
 .../intelligence/service/TraceAnalysisService.java |   8 +-
 .../ozhera/intelligence/service/TraceService.java  | 129 ++++++++-
 19 files changed, 877 insertions(+), 58 deletions(-)

diff --git a/ozhera-intelligence/README_cn.md b/ozhera-intelligence/README_cn.md
index 8e167bab..e22b3486 100644
--- a/ozhera-intelligence/README_cn.md
+++ b/ozhera-intelligence/README_cn.md
@@ -38,7 +38,7 @@
 + TraceService,取链路数据
 
 # 重要依赖
-会依赖小米开源的一款[Agent构建平台——m78](https://github.com/XiaoMi/mone/tree/master/m78-all)
+会依赖小米开源的一款[Agent平台——hive](https://github.com/XiaoMi/mone/tree/master/m78-all)
 
 
 # 智能化工作流程(时序图)
diff --git 
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/MarkDownParam.java
 
b/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/CodeFixInfo.java
similarity index 65%
copy from 
ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/MarkDownParam.java
copy to 
ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/CodeFixInfo.java
index 64f36f3b..5ba95e3e 100644
--- 
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/MarkDownParam.java
+++ 
b/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/CodeFixInfo.java
@@ -18,26 +18,31 @@
  */
 package org.apache.ozhera.intelligence.domain.rootanalysis;
 
+import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;
+import lombok.NoArgsConstructor;
 
+/**
+ * Code fix information containing projectId, envId and stacktrace
+ */
 @Data
 @Builder
-public class MarkDownParam {
-
-    private String traceReason;
-
-    private String application;
-
-    private String logReason;
-
-    private String metricsReason;
-
-    private String simpleReason;
-
-    private String traceId;
-
-    private String timestamp;
-
-    private String env;
+@NoArgsConstructor
+@AllArgsConstructor
+public class CodeFixInfo {
+    /**
+     * Project ID extracted from service name
+     */
+    private String projectId;
+
+    /**
+     * Environment ID extracted from process tags
+     */
+    private String envId;
+
+    /**
+     * Exception stack trace extracted from span logs
+     */
+    private String stacktrace;
 }
diff --git 
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/MarkDownParam.java
 
b/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/MarkDownParam.java
index 64f36f3b..927d7299 100644
--- 
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/MarkDownParam.java
+++ 
b/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/MarkDownParam.java
@@ -29,6 +29,10 @@ public class MarkDownParam {
 
     private String application;
 
+    private String projectId;
+
+    private String envId;
+
     private String logReason;
 
     private String metricsReason;
diff --git 
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TracePromptResult.java
 
b/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TracePromptResult.java
index 1c3f3b58..fa913fcf 100644
--- 
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TracePromptResult.java
+++ 
b/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TracePromptResult.java
@@ -35,6 +35,9 @@ public class TracePromptResult {
     // Whether it is the root cause, determined based on analysis
     private boolean root;
 
+    // project ID of the application.
+    private String projectId;
+
     // Environment ID of the application,
     // obtained from the value of service.env.id in process.tags of the 
problem node
     private String envId;
diff --git 
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/constant/Prompts.java
 
b/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/constant/Prompts.java
index 30860208..44560de8 100644
--- 
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/constant/Prompts.java
+++ 
b/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/constant/Prompts.java
@@ -172,4 +172,36 @@ public class Prompts {
               <simpleReason>在TestService的252行发生空指针异常,导致返回了500错误码</simpleReason>
             </result>
             """;
+
+    public static final String CODE_FIX_ANALYSIS_PROMPT = """
+            
作为一位经验丰富的Java开发工程师,你负责分析请求链路中各个节点的Span信息,找出导致异常的根本原因节点的spanId。我们会提供一个包含请求链路全部节点的数据集。你的任务是:
+
+            1. 确认服务之间的调用关系和依赖,从而确定每个节点在链路中的依赖层级。可以通过节点中的 references.spanID 
来确认当前节点的父节点。
+            2. 识别存在的异常节点,并找到最底层的异常节点。
+            3. 如果 span.kind 是 client 节点,并且报服务调用超时异常,请判断其调用的 server 节点的耗时,若 
server 节点耗时过高,则根本原因是 server 节点而非 client 节点。
+            4. 返回异常根因节点的 spanId。
+
+            请使用以下 XML 格式返回分析结果:
+            ```xml
+            <result>
+              <spanId>异常根因节点的spanId</spanId>
+            </result>
+            ```
+
+            请确保结果为有效的 XML 数据。如果传入的 data 数据为空,则返回以下固定的内容:
+            ```xml
+            <result>
+              <spanId></spanId>
+            </result>
+            ```
+
+            ## 返回结果示例:
+            ```xml
+            <result>
+              <spanId>a291ab32156dca70</spanId>
+            </result>
+            ```
+
+            以下是提供的数据集:
+            """;
 }
diff --git 
a/ozhera-intelligence/ozhera-intelligence-server/src/main/java/org/apache/ozhera/intelligence/bootstrap/IntelligenceBootStrap.java
 
b/ozhera-intelligence/ozhera-intelligence-server/src/main/java/org/apache/ozhera/intelligence/bootstrap/IntelligenceBootStrap.java
index fc258db6..a9e4dfcd 100644
--- 
a/ozhera-intelligence/ozhera-intelligence-server/src/main/java/org/apache/ozhera/intelligence/bootstrap/IntelligenceBootStrap.java
+++ 
b/ozhera-intelligence/ozhera-intelligence-server/src/main/java/org/apache/ozhera/intelligence/bootstrap/IntelligenceBootStrap.java
@@ -24,7 +24,7 @@ import 
org.springframework.boot.autoconfigure.EnableAutoConfiguration;
 import org.springframework.context.annotation.ComponentScan;
 
 @EnableAutoConfiguration
-@ComponentScan(basePackages = {"org.apache.ozhera.intelligence"})
+@ComponentScan(basePackages = {"org.apache.ozhera.intelligence", 
"run.mone.mcp.git"})
 @Slf4j
 public class IntelligenceBootStrap {
     public static void main(String... args) {
diff --git 
a/ozhera-intelligence/ozhera-intelligence-server/src/main/java/org/apache/ozhera/intelligence/config/DubboConfiguration.java
 
b/ozhera-intelligence/ozhera-intelligence-server/src/main/java/org/apache/ozhera/intelligence/config/DubboConfiguration.java
index f672299f..5886d7db 100644
--- 
a/ozhera-intelligence/ozhera-intelligence-server/src/main/java/org/apache/ozhera/intelligence/config/DubboConfiguration.java
+++ 
b/ozhera-intelligence/ozhera-intelligence-server/src/main/java/org/apache/ozhera/intelligence/config/DubboConfiguration.java
@@ -37,13 +37,13 @@ public class DubboConfiguration {
     @Value("${server.port}")
     private String httpGateWayPort;
 
-    @NacosValue("${dubbo.registry.address}")
+    @Value("${dubbo.registry.address}")
     private String regAddress;
 
     @Bean
     public ApplicationConfig applicationConfig() {
         ApplicationConfig applicationConfig = new ApplicationConfig();
-        applicationConfig.setName("Trace-etl-manager");
+        applicationConfig.setName("ozhera-intelligence");
         applicationConfig.setParameters(Maps.newHashMap());
         applicationConfig.getParameters().put("http_gateway_port", 
httpGateWayPort);
         applicationConfig.getParameters().put("dubbo_version", "1.0");
diff --git 
a/ozhera-intelligence/ozhera-intelligence-server/src/main/java/org/apache/ozhera/intelligence/filter/TokenValidationFilter.java
 
b/ozhera-intelligence/ozhera-intelligence-server/src/main/java/org/apache/ozhera/intelligence/filter/TokenValidationFilter.java
index 572da052..f0eb8c08 100644
--- 
a/ozhera-intelligence/ozhera-intelligence-server/src/main/java/org/apache/ozhera/intelligence/filter/TokenValidationFilter.java
+++ 
b/ozhera-intelligence/ozhera-intelligence-server/src/main/java/org/apache/ozhera/intelligence/filter/TokenValidationFilter.java
@@ -18,9 +18,9 @@
  */
 package org.apache.ozhera.intelligence.filter;
 
-import com.alibaba.nacos.api.config.annotation.NacosValue;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 import org.springframework.web.filter.OncePerRequestFilter;
 
@@ -35,7 +35,7 @@ public class TokenValidationFilter extends 
OncePerRequestFilter {
 
     private static final Logger logger = 
LoggerFactory.getLogger(TokenValidationFilter.class);
 
-    @NacosValue("${analyze.token}")
+    @Value("${analyze.token}")
     private String validToken;
 
     @Override
diff --git 
a/ozhera-intelligence/ozhera-intelligence-server/src/main/resources/application.properties
 
b/ozhera-intelligence/ozhera-intelligence-server/src/main/resources/application.properties
index 8bebaee4..56b6c1eb 100644
--- 
a/ozhera-intelligence/ozhera-intelligence-server/src/main/resources/application.properties
+++ 
b/ozhera-intelligence/ozhera-intelligence-server/src/main/resources/application.properties
@@ -32,4 +32,26 @@ log.query.version=${log.query.version}
 nacos.address=${nacos.address}
 
 # agents name
-trace.agent.name=${trace.agent.name}
\ No newline at end of file
+mcp.agent.name=${mcp.agent.name}
+
+# Trace span sectional API
+trace.span.sectional.url=${trace.span.sectional.url}
+# Trace query mode: http or dubbo
+trace.query.mode=${trace.query.mode}
+
+hive.manager.base-url=${hive.manager.base-url}
+hive.manager.reg.switch=${hive.manager.reg.switch}
+hive.manager.token=${hive.manager.token}
+# mcp llm config from LLMProvider
+mcp.llm=${mcp.llm}
+mcp.transport.type=${mcp.transport.type}
+mcp.grpc.port=${mcp.grpc.port}
+
+hera.trace.url=${hera.trace.url}
+dubbo.registry.address=${dubbo.registry.address}
+analyze.token=${analyze.token}
+prometheus.api.url=${prometheus.api.url}
+
+# Git Default Configuration
+git.default.username=${git.default.username}
+git.default.token=${git.default.token}
\ No newline at end of file
diff --git 
a/ozhera-intelligence/ozhera-intelligence-server/src/main/resources/config/opensource-outer.properties
 
b/ozhera-intelligence/ozhera-intelligence-server/src/main/resources/config/opensource-outer.properties
index 88360392..f279dcd9 100644
--- 
a/ozhera-intelligence/ozhera-intelligence-server/src/main/resources/config/opensource-outer.properties
+++ 
b/ozhera-intelligence/ozhera-intelligence-server/src/main/resources/config/opensource-outer.properties
@@ -31,4 +31,25 @@ log.query.version=1.0
 
 nacos.address=nacos:80
 
-trace.agent.name=trace-analysis
\ No newline at end of file
+mcp.agent.name=trace-analysis
+
+# Trace span sectional API
+trace.span.sectional.url=http://xx
+# Trace query mode: http or dubbo,
+trace.query.mode=dubbo
+
+hive.manager.base-url=http://xxxx
+hive.manager.reg.switch=true
+hive.manager.token=xxxxx
+mcp.llm=
+mcp.transport.type=grpc
+mcp.grpc.port=9288
+
+hera.trace.url=
+dubbo.registry.address=nacos://nacos:80
+analyze.token=
+prometheus.api.url=
+
+# Git Default Configuration
+git.default.username=xxx
+git.default.token=xxx
\ No newline at end of file
diff --git a/ozhera-intelligence/ozhera-intelligence-service/pom.xml 
b/ozhera-intelligence/ozhera-intelligence-service/pom.xml
index 73b222c7..35469a45 100644
--- a/ozhera-intelligence/ozhera-intelligence-service/pom.xml
+++ b/ozhera-intelligence/ozhera-intelligence-service/pom.xml
@@ -36,6 +36,28 @@
     </properties>
 
     <dependencies>
+        <dependency>
+            <groupId>run.mone</groupId>
+            <artifactId>mcp-miline</artifactId>
+            <version>1.6.1-jdk21-SNAPSHOT</version>
+            <exclusions>
+                <exclusion>
+                    <artifactId>spring-webmvc</artifactId>
+                    <groupId>org.springframework</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>run.mone</groupId>
+            <artifactId>mcp-git</artifactId>
+            <version>1.6.1-jdk21-SNAPSHOT</version>
+            <exclusions>
+                <exclusion>
+                    <artifactId>spring-webmvc</artifactId>
+                    <groupId>org.springframework</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
         <dependency>
             <groupId>org.apache.ozhera</groupId>
             <artifactId>ozhera-intelligence-domain</artifactId>
diff --git 
a/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/agents/config/AgentConfig.java
 
b/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/agents/config/AgentConfig.java
index a5b0cae2..eedac345 100644
--- 
a/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/agents/config/AgentConfig.java
+++ 
b/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/agents/config/AgentConfig.java
@@ -19,48 +19,82 @@
 package org.apache.ozhera.intelligence.agents.config;
 
 import com.google.common.collect.Lists;
-import org.apache.ozhera.intelligence.agents.function.TraceAnalysisFunction;
+import org.apache.ozhera.intelligence.agents.tool.CodeFixTool;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import run.mone.hive.mcp.function.ChatFunction;
-import run.mone.hive.mcp.service.Rag;
 import run.mone.hive.mcp.service.RoleMeta;
-import run.mone.hive.mcp.service.WebQuery;
-import run.mone.hive.roles.tool.AskTool;
-import run.mone.hive.roles.tool.AttemptCompletionTool;
-import run.mone.hive.roles.tool.ChatTool;
-import run.mone.hive.roles.tool.SpeechToTextTool;
-import run.mone.hive.roles.tool.TextToSpeechTool;
+import run.mone.hive.roles.tool.*;
+import run.mone.mcp.git.tool.GitCloneTool;
+import run.mone.mcp.git.tool.GitCommitTool;
+import run.mone.mcp.git.tool.GitPushTool;
+import run.mone.mcp.miline.tools.GetPipelineDetailTool;
+import run.mone.mcp.miline.tools.RunPipelineTool;
+
 
 @Configuration
 public class AgentConfig {
 
-    @Value("${trace.agent.name}")
+    @Value("${mcp.agent.name}")
     private String agentName;
 
     @Autowired
-    private TraceAnalysisFunction traceAnalysisFunction;
+    private CodeFixTool codeFixTool;
+
+    @Autowired
+    private GitCloneTool gitCloneTool;
+    @Autowired
+    private GitCommitTool gitCommitTool;
+    @Autowired
+    private GitPushTool gitPushTool;
+
+    private boolean isRemoteFile = false;
 
     @Bean
     public RoleMeta roleMeta() {
+        ChatFunction chat = new ChatFunction(agentName, 20);
+        
chat.setDesc("和%s聊天,问问%s关于OzHera可观测性的服务监控和链路追踪相关的数据。支持各种形式如:'%s'、'请%s告诉我监控数据'、'让%s帮我看看服务状态'、'%s你知道服务有什么问题'等。支持上下文连续对话。");
+
         return RoleMeta.builder()
-                .profile("你是一名优秀的工程师,你擅长分析logging tracing 
metrics,并且根据这些信息发现代码问题.")
-                .goal("你的目标是帮助用户发现线上问题")
-                .constraints("不要探讨任何和技术不相关的东西,如果用户问你,你可以直接拒绝掉")
+                .name("OzHera可观测系统专家")
+                .profile("你是OzHera可观测系统专家,精通分布式系统的监控和链路追踪,能够帮助用户诊断和解决复杂的系统问题")
+                
.goal("你的目标是根据用户输入返回OzHera中专业的监控数据和链路追踪数据,帮助用户快速定位和解决系统中的异常和性能问题")
+                .constraints("不要探讨一些负面的东西,如果用户问你,你可以直接拒绝掉")
                 //允许自动从知识库获取内容(意图识别的小模型)
-                
.webQuery(WebQuery.builder().autoWebQuery(false).modelType("bert").version("").releaseServiceName("").build())
-                
.rag(Rag.builder().autoRag(false).modelType("").version("").releaseServiceName("").build())
+//                
.webQuery(WebQuery.builder().autoWebQuery(true).modelType("bert").version("finetune-bert-20250605-73a29258").releaseServiceName("bert-is-network").build())
+//                
.rag(Rag.builder().autoRag(true).modelType("bert").version("finetune-bert-20250605-ed8acbcf").releaseServiceName("bert-is-knowledge-base").build())
                 //内部工具
                 .tools(Lists.newArrayList(
                         new ChatTool(),
                         new AskTool(),
                         new AttemptCompletionTool(),
-                        new SpeechToTextTool(),
-                        new TextToSpeechTool()))
+                        codeFixTool,
+                        new ListFilesTool(isRemoteFile),
+                        new ExecuteCommandToolOptimized(),
+                        new ReadFileTool(isRemoteFile),
+                        new SearchFilesTool(isRemoteFile),
+                        new ReplaceInFileTool(isRemoteFile),
+                        new ListCodeDefinitionNamesTool(),
+                        new WriteToFileTool(isRemoteFile),
+                        new RunPipelineTool(),
+                        new GetPipelineDetailTool(),
+                        gitCloneTool,
+                        gitCommitTool,
+                        gitPushTool
+                ))
                 //mcp工具
-                .mcpTools(Lists.newArrayList(new ChatFunction(agentName,60), 
traceAnalysisFunction))
+                .mcpTools(Lists.newArrayList(chat))
+                .workflow("""
+                    你是代码级自动异常修复系统,严格按照以下步骤执行: 
+                        1、根据traceId获取链路上根因节点的项目信息与异常信息 
+                        2、根据根因节点的projectId和envId获取流水线详情 
+                        
3、根据流水线详情中的gitUrl、gitBranch、gitCommitId调用git_clone工具进行git clone 
+                        4、根据trace链路上的异常信息,结合项目代码进行异常修复 
+                        5、修复完成后,将本地代码使用git_commit工具进行git 
commit,commit信息是自动代码修复, 使用git_push进行git push 
+                        6、根据projectId和envId调用RunPipelineTool进行发布
+                """)
                 .build();
     }
 }
diff --git 
a/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/agents/tool/CodeFixTool.java
 
b/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/agents/tool/CodeFixTool.java
new file mode 100644
index 00000000..5f42f7d7
--- /dev/null
+++ 
b/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/agents/tool/CodeFixTool.java
@@ -0,0 +1,319 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ozhera.intelligence.agents.tool;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.ozhera.intelligence.domain.rootanalysis.CodeFixInfo;
+import org.apache.ozhera.intelligence.domain.rootanalysis.TraceQueryParam;
+import org.apache.ozhera.intelligence.service.PromptService;
+import org.apache.ozhera.intelligence.service.TraceService;
+import org.apache.ozhera.trace.etl.domain.jaegeres.JaegerAttribute;
+import org.apache.ozhera.trace.etl.domain.jaegeres.JaegerLogs;
+import org.apache.ozhera.trace.etl.domain.tracequery.Span;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import run.mone.hive.roles.ReactorRole;
+import run.mone.hive.roles.tool.ITool;
+
+import java.util.List;
+
+/**
+ * Code fix tool for analyzing trace and extracting error information
+ * <p>
+ * This tool analyzes trace data to find the root cause of exceptions,
+ * and extracts project ID, environment ID and stack trace information
+ * for code fixing purposes.
+ */
+@Slf4j
+@Component
+public class CodeFixTool implements ITool {
+
+    @Value("${server.type}")
+    private String env;
+
+    /**
+     * Tool name
+     */
+    public static final String name = "code_fix";
+
+    /**
+     * Trace service for querying spans
+     */
+    @Autowired
+    private TraceService traceService;
+
+    /**
+     * Prompt service for AI analysis
+     */
+    @Autowired
+    private PromptService promptService;
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public boolean needExecute() {
+        return true;
+    }
+
+    @Override
+    public boolean show() {
+        return true;
+    }
+
+    @Override
+    public String description() {
+        return """
+                根据traceId智能分析trace链路,提取异常根因节点的相关信息用于代码修复。
+                该工具会自动识别异常节点,并提取项目ID、环境ID和异常堆栈信息。
+
+                **使用场景:**
+                - 分析异常trace链路,定位错误根因
+                - 提取异常信息用于自动化代码修复
+                - 获取项目和环境信息用于问题定位
+
+                **分析能力:**
+                - 自动识别链路中的异常节点
+                - 提取异常堆栈信息
+                - 解析项目ID和环境ID
+                - 返回完整的代码修复所需信息
+
+                **重要提示:**
+                - traceId必须是32位由0-9和a-f组成的随机字符串
+                - 确保traceId对应的链路数据已经采集完整
+                """;
+    }
+
+    @Override
+    public String parameters() {
+        return """
+                - traceId: (必填) 追踪ID,32位由0-9和a-f组成的随机字符串
+                """;
+    }
+
+    @Override
+    public String usage() {
+        String taskProgress = """
+                <task_progress>
+                任务进度记录(可选)
+                </task_progress>
+                """;
+        if (!taskProgress()) {
+            taskProgress = "";
+        }
+        return """
+                <code_fix>
+                <traceId>32位追踪ID</traceId>
+                %s
+                </code_fix>
+                """.formatted(taskProgress);
+    }
+
+    @Override
+    public String example() {
+        return """
+                示例: 分析异常trace并提取修复信息
+                <code_fix>
+                <traceId>a1b2c3d4e5f6789012345678abcdef01</traceId>
+                </code_fix>
+                """;
+    }
+
+    @Override
+    public JsonObject execute(ReactorRole role, JsonObject inputJson) {
+        JsonObject result = new JsonObject();
+
+        try {
+            // Validate required parameter
+            if (!inputJson.has("traceId") || 
StringUtils.isBlank(inputJson.get("traceId").getAsString())) {
+                log.error("code_fix operation missing required parameter 
traceId");
+                result.addProperty("error", "缺少必填参数 'traceId'");
+                return result;
+            }
+
+            // Get traceId parameter
+            String traceId = inputJson.get("traceId").getAsString().trim();
+
+            if (traceId.isEmpty()) {
+                log.warn("traceId parameter is empty");
+                result.addProperty("error", "参数错误:traceId不能为空");
+                return result;
+            }
+
+            // Validate traceId format (32-character hexadecimal string)
+            if (!isValidTraceId(traceId)) {
+                log.warn("Invalid traceId format: {}", traceId);
+                result.addProperty("error", 
"参数错误:traceId必须是32位由0-9和a-f组成的字符串");
+                return result;
+            }
+
+            log.info("Starting code fix analysis for traceId: {}", traceId);
+
+            // Query spans from trace service
+            TraceQueryParam queryParam = TraceQueryParam.builder()
+                    .traceId(traceId)
+                    .env(env)
+                    .build();
+            List<Span> spans = traceService.queryTraceRootAnalysis(queryParam);
+
+            if (spans == null || spans.isEmpty()) {
+                log.warn("No spans found for traceId: {}", traceId);
+                result.addProperty("error", "未找到对应的trace数据");
+                return result;
+            }
+
+            // Convert spans to JSON for AI analysis
+            Gson gson = new Gson();
+            String spansJson = gson.toJson(spans);
+
+            // Call AI to analyze and get root cause spanId
+            String rootCauseSpanId = promptService.codeFixAnalysis(spansJson);
+
+            if (StringUtils.isBlank(rootCauseSpanId)) {
+                log.warn("Failed to identify root cause spanId for traceId: 
{}", traceId);
+                result.addProperty("error", "无法识别异常根因节点");
+                return result;
+            }
+
+            log.info("Identified root cause spanId: {}", rootCauseSpanId);
+
+            // Find the span with matching spanId
+            Span rootCauseSpan = null;
+            for (Span span : spans) {
+                if (rootCauseSpanId.equals(span.getSpanID())) {
+                    rootCauseSpan = span;
+                    break;
+                }
+            }
+
+            if (rootCauseSpan == null) {
+                log.warn("Root cause span not found with spanId: {}", 
rootCauseSpanId);
+                result.addProperty("error", "未找到对应的根因节点");
+                return result;
+            }
+
+            // Extract information from the root cause span
+            CodeFixInfo codeFixInfo = extractCodeFixInfo(rootCauseSpan);
+
+            if (codeFixInfo == null) {
+                log.warn("Failed to extract code fix info from span");
+                result.addProperty("error", "提取代码修复信息失败");
+                return result;
+            }
+
+            // Set success response
+            result.addProperty("success", true);
+            result.addProperty("traceId", traceId);
+            result.addProperty("spanId", rootCauseSpanId);
+            result.addProperty("projectId", codeFixInfo.getProjectId());
+            result.addProperty("envId", codeFixInfo.getEnvId());
+            result.addProperty("stacktrace", codeFixInfo.getStacktrace());
+
+            log.info("Successfully analyzed code fix info for traceId: {}", 
traceId);
+
+            return result;
+
+        } catch (Exception e) {
+            log.error("Error executing code_fix operation", e);
+            result.addProperty("error", "代码修复分析失败:" + e.getMessage());
+            result.addProperty("success", false);
+            return result;
+        }
+    }
+
+    /**
+     * Extract code fix information from a span
+     *
+     * @param span the root cause span
+     * @return CodeFixInfo containing projectId, envId and stacktrace
+     */
+    private CodeFixInfo extractCodeFixInfo(Span span) {
+        try {
+            // Extract projectId from serviceName
+            String serviceName = span.getProcess().getServiceName();
+            String projectId = null;
+            if (serviceName != null && serviceName.contains("-")) {
+                projectId = serviceName.split("-")[0];
+            }
+
+            // Extract envId from process tags
+            String envId = null;
+            List<JaegerAttribute> tags = span.getProcess().getTags();
+            if (tags != null) {
+                for (JaegerAttribute tag : tags) {
+                    if ("service.env.id".equals(tag.getKey())) {
+                        envId = tag.getValue();
+                        break;
+                    }
+                }
+            }
+
+            // Extract stacktrace from logs
+            String stacktrace = null;
+            List<JaegerLogs> logs = span.getLogs();
+            if (logs != null) {
+                for (JaegerLogs log : logs) {
+                    List<JaegerAttribute> fields = log.getFields();
+                    if (fields != null) {
+                        for (JaegerAttribute field : fields) {
+                            if ("exception.stacktrace".equals(field.getKey())) 
{
+                                stacktrace = field.getValue();
+                                break;
+                            }
+                        }
+                        if (stacktrace != null) {
+                            break;
+                        }
+                    }
+                }
+            }
+
+            return CodeFixInfo.builder()
+                    .projectId(projectId)
+                    .envId(envId)
+                    .stacktrace(stacktrace)
+                    .build();
+
+        } catch (Exception e) {
+            log.error("Error extracting code fix info from span", e);
+            return null;
+        }
+    }
+
+    /**
+     * Validate traceId format
+     * TraceId should be a 32-character string composed of 0-9 and a-f
+     *
+     * @param traceId trace ID
+     * @return whether the format is correct
+     */
+    private boolean isValidTraceId(String traceId) {
+        if (traceId == null || traceId.length() != 32) {
+            return false;
+        }
+        // Check if it only contains 0-9 and a-f characters
+        return traceId.matches("[0-9a-fA-F]{32}");
+    }
+}
diff --git 
a/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/agents/tool/TraceAnalysisTool.java
 
b/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/agents/tool/TraceAnalysisTool.java
new file mode 100644
index 00000000..ba2dbc1a
--- /dev/null
+++ 
b/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/agents/tool/TraceAnalysisTool.java
@@ -0,0 +1,217 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ozhera.intelligence.agents.tool;
+
+import com.google.gson.JsonObject;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.ozhera.intelligence.domain.rootanalysis.TraceQueryParam;
+import org.apache.ozhera.intelligence.service.TraceAnalysisService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import run.mone.hive.roles.ReactorRole;
+import run.mone.hive.roles.tool.ITool;
+
+/**
+ * Trace链路分析工具
+ * <p>
+ * 该工具用于根据traceId分析trace链路上异常或慢查询出现的根本原因。
+ * 通过AI智能分析,帮助开发人员快速定位问题根源,提高问题排查效率。
+ * <p>
+ * 使用场景:
+ * - 分析异常trace链路,定位错误根因
+ * - 分析慢查询trace链路,找出性能瓶颈
+ * - 排查分布式系统中的链路问题
+ * - 辅助故障诊断和性能优化
+ */
+@Slf4j
+@Component
+public class TraceAnalysisTool implements ITool {
+
+    @Value("${server.type}")
+    private String env;
+
+    /**
+     * 工具名称
+     */
+    public static final String name = "trace_analysis";
+
+    /**
+     * Trace分析服务
+     */
+    @Autowired
+    private TraceAnalysisService traceAnalysisService;
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public boolean needExecute() {
+        return true;
+    }
+
+    @Override
+    public boolean show() {
+        return true;
+    }
+
+    @Override
+    public String description() {
+        return """
+                根据traceId智能分析trace链路上异常或慢查询出现的根本原因。该工具利用AI能力,
+                深度分析分布式链路追踪数据,帮助快速定位问题根源。
+
+                **使用场景:**
+                - 分析异常trace链路,快速定位错误根因
+                - 分析慢查询trace链路,找出性能瓶颈所在
+                - 排查分布式系统中的调用链路问题
+                - 辅助开发人员进行故障诊断
+                - 支持性能优化和系统调优
+
+                **分析能力:**
+                - 自动识别链路中的异常节点
+                - 分析慢查询的原因和影响范围
+                - 提供问题根因的详细说明
+                - 给出优化建议和解决方案
+
+                **重要提示:**
+                - traceId必须是32位由0-9和a-f组成的随机字符串
+                - 默认分析线上环境(online)的trace数据
+                - 确保traceId对应的链路数据已经采集完整
+                """;
+    }
+
+    @Override
+    public String parameters() {
+        return """
+                - traceId: (必填) 追踪ID,32位由0-9和a-f组成的随机字符串
+                """;
+    }
+
+    @Override
+    public String usage() {
+        String taskProgress = """
+                <task_progress>
+                任务进度记录(可选)
+                </task_progress>
+                """;
+        if (!taskProgress()) {
+            taskProgress = "";
+        }
+        return """
+                <trace_analysis>
+                <traceId>32位追踪ID</traceId>
+                %s
+                </trace_analysis>
+                """.formatted(taskProgress);
+    }
+
+    @Override
+    public String example() {
+        return """
+                示例 1: 分析异常trace链路
+                <trace_analysis>
+                <traceId>a1b2c3d4e5f6789012345678abcdef01</traceId>
+                </trace_analysis>
+
+                示例 2: 分析慢查询trace链路
+                <trace_analysis>
+                <traceId>fedcba9876543210f6e5d4c3b2a10000</traceId>
+                </trace_analysis>
+
+                示例 3: 排查分布式链路问题
+                <trace_analysis>
+                <traceId>123456789abcdef0123456789abcdef0</traceId>
+                </trace_analysis>
+                """;
+    }
+
+    @Override
+    public JsonObject execute(ReactorRole role, JsonObject inputJson) {
+        JsonObject result = new JsonObject();
+
+        try {
+            // 验证必填参数
+            if (!inputJson.has("traceId") || 
StringUtils.isBlank(inputJson.get("traceId").getAsString())) {
+                log.error("trace_analysis 操作缺少必填参数 traceId");
+                result.addProperty("error", "缺少必填参数 'traceId'");
+                return result;
+            }
+
+            // 获取traceId参数
+            String traceId = inputJson.get("traceId").getAsString().trim();
+
+            if (traceId.isEmpty()) {
+                log.warn("traceId 参数为空");
+                result.addProperty("error", "参数错误:traceId不能为空");
+                return result;
+            }
+
+            // 验证traceId格式(32位16进制字符串)
+            if (!isValidTraceId(traceId)) {
+                log.warn("traceId 格式不正确: {}", traceId);
+                result.addProperty("error", 
"参数错误:traceId必须是32位由0-9和a-f组成的字符串");
+                return result;
+            }
+
+            log.info("开始分析trace链路,traceId: {}", traceId);
+
+            // 调用服务分析trace根本原因,默认环境为online
+            TraceQueryParam queryParam = TraceQueryParam.builder()
+                    .traceId(traceId)
+                    .env(env)
+                    .build();
+            String analysisResult = 
traceAnalysisService.analyzeTraceRoot(queryParam);
+
+            // 设置成功响应
+            result.addProperty("result", analysisResult);
+            result.addProperty("traceId", traceId);
+            result.addProperty("environment", "online");
+            result.addProperty("success", true);
+
+            log.info("成功分析trace链路,traceId: {}", traceId);
+
+            return result;
+
+        } catch (Exception e) {
+            log.error("执行 trace_analysis 操作时发生异常", e);
+            result.addProperty("error", "分析trace链路失败:" + e.getMessage());
+            result.addProperty("success", false);
+            return result;
+        }
+    }
+
+    /**
+     * 验证traceId格式是否正确
+     * traceId应该是32位由0-9和a-f组成的字符串
+     *
+     * @param traceId 追踪ID
+     * @return 格式是否正确
+     */
+    private boolean isValidTraceId(String traceId) {
+        if (traceId == null || traceId.length() != 32) {
+            return false;
+        }
+        // 检查是否只包含0-9和a-f字符
+        return traceId.matches("[0-9a-fA-F]{32}");
+    }
+}
diff --git 
a/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/service/LogService.java
 
b/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/service/LogService.java
index 7502c4a8..0069f5af 100644
--- 
a/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/service/LogService.java
+++ 
b/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/service/LogService.java
@@ -30,7 +30,7 @@ import java.util.Map;
 @Service
 public class LogService {
 
-    @DubboReference(interfaceClass = HeraLogApiService.class, group = 
"${log.query.group}", version = "${log.query.version}")
+    @DubboReference(interfaceClass = HeraLogApiService.class, group = 
"${log.query.group}", version = "${log.query.version}", check = false)
     private HeraLogApiService heraLogApiService;
 
     /**
diff --git 
a/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/service/MetricsService.java
 
b/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/service/MetricsService.java
index 506fdf38..cf5a1330 100644
--- 
a/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/service/MetricsService.java
+++ 
b/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/service/MetricsService.java
@@ -18,7 +18,6 @@
  */
 package org.apache.ozhera.intelligence.service;
 
-import com.alibaba.nacos.api.config.annotation.NacosValue;
 import com.google.gson.Gson;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.http.client.utils.URIBuilder;
@@ -26,6 +25,7 @@ import 
org.apache.ozhera.intelligence.domain.rootanalysis.HeraRootCaseAnalyseRes
 import 
org.apache.ozhera.intelligence.domain.rootanalysis.MetricDataRangeSetVector;
 import 
org.apache.ozhera.intelligence.domain.rootanalysis.MetricRangeResponseVector;
 import org.apache.ozhera.intelligence.util.HttpClient;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 import org.apache.ozhera.intelligence.domain.rootanalysis.MetricsQueryParam;
 
@@ -46,7 +46,7 @@ import static 
org.apache.ozhera.intelligence.util.CommitPoolUtil.HERA_SOLUTION_M
 @Slf4j
 public class MetricsService {
 
-    @NacosValue("${prometheus.api.url}")
+    @Value("${prometheus.api.url}")
     private String prometheusUrl;
 
     private static final String URI_QUERY_RANGE = "/api/v1/query_range";
diff --git 
a/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/service/PromptService.java
 
b/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/service/PromptService.java
index 1456dcdd..ac06c16e 100644
--- 
a/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/service/PromptService.java
+++ 
b/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/service/PromptService.java
@@ -75,6 +75,7 @@ public class PromptService {
                 
.traceReason(keyValuePairs.get(TracePromptResult.TRACE_REASON_KEY))
                 .application(keyValuePairs.get(TracePromptResult.APPLICATION))
                 
.root(Boolean.parseBoolean(keyValuePairs.get(TracePromptResult.ROOT)))
+                .projectId(keyValuePairs.get(TracePromptResult.PROJECT_ID))
                 .envId(keyValuePairs.get(TracePromptResult.ENV_ID))
                 .startTime(keyValuePairs.get(TracePromptResult.START_TIME))
                 .duration(keyValuePairs.get(TracePromptResult.DURATION))
@@ -179,4 +180,30 @@ public class PromptService {
         // Return simplified analysis result
         return keyValuePairs.get("simpleReason");
     }
+
+    /**
+     * Perform LLM analysis based on trace data to find the root cause spanId 
for code fix
+     *
+     * @param trace trace link data
+     * @return spanId of the root cause node
+     */
+    public String codeFixAnalysis(String trace) {
+        // Get the corresponding prompt
+        String prompt = Prompts.CODE_FIX_ANALYSIS_PROMPT + "\n" + trace;
+
+        // Call LLM for analysis
+        String llmRes = llm.chat(prompt);
+
+        // Parse the XML result returned by LLM
+        List<ToolDataInfo> tools = new MultiXmlParser().parse(llmRes);
+        if (tools == null || tools.isEmpty()) {
+            // If parsing result is empty, return null
+            return null;
+        }
+
+        Map<String, String> keyValuePairs = tools.get(0).getKeyValuePairs();
+
+        // Return spanId
+        return keyValuePairs.get("spanId");
+    }
 }
diff --git 
a/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/service/TraceAnalysisService.java
 
b/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/service/TraceAnalysisService.java
index 12cafa7b..083d5aa5 100644
--- 
a/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/service/TraceAnalysisService.java
+++ 
b/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/service/TraceAnalysisService.java
@@ -18,12 +18,12 @@
  */
 package org.apache.ozhera.intelligence.service;
 
-import com.alibaba.nacos.api.config.annotation.NacosValue;
 import com.google.gson.Gson;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.ozhera.intelligence.domain.rootanalysis.*;
 import org.apache.ozhera.trace.etl.domain.tracequery.Span;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
 import java.util.List;
@@ -36,7 +36,7 @@ import java.util.Map;
 @Service
 public class TraceAnalysisService {
 
-    @NacosValue("${hera.trace.url}")
+    @Value("${hera.trace.url}")
     private String heraTraceUrl;
 
     @Autowired
@@ -148,6 +148,8 @@ public class TraceAnalysisService {
         // Get simplified root cause analysis results
         String application = traceResult != null ? 
traceResult.getApplication() : "";
         String traceReason = traceResult != null ? 
traceResult.getTraceReason() : "";
+        String projectId = traceResult != null ? traceResult.getProjectId() : 
"";
+        String envId = traceResult != null ? traceResult.getEnvId() : "";
         String logReason = logResult != null ? logResult.getLogReason() : "";
         String metricsReason = metricsResult != null ? 
metricsResult.getMetricsReason() : "";
         
@@ -155,6 +157,8 @@ public class TraceAnalysisService {
         
         // Build MarkDownParam parameters
         MarkDownParam markDownParam = MarkDownParam.builder()
+                .projectId(projectId)
+                .envId(envId)
                 .application(application)
                 .traceReason(traceReason)
                 .logReason(logReason)
diff --git 
a/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/service/TraceService.java
 
b/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/service/TraceService.java
index d2740da8..928709f4 100644
--- 
a/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/service/TraceService.java
+++ 
b/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/service/TraceService.java
@@ -18,17 +18,25 @@
  */
 package org.apache.ozhera.intelligence.service;
 
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import com.google.gson.reflect.TypeToken;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.dubbo.config.annotation.DubboReference;
+import org.apache.http.client.utils.URIBuilder;
 import org.apache.ozhera.intelligence.domain.rootanalysis.TraceTreeNode;
+import org.apache.ozhera.intelligence.util.HttpClient;
 import org.apache.ozhera.trace.etl.api.service.TraceQueryService;
 import org.apache.ozhera.trace.etl.domain.jaegeres.JaegerAttribute;
 import org.apache.ozhera.trace.etl.domain.tracequery.Span;
 import org.apache.ozhera.trace.etl.domain.tracequery.Trace;
 import org.apache.ozhera.trace.etl.domain.tracequery.TraceIdQueryVo;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 import org.apache.ozhera.intelligence.domain.rootanalysis.TraceQueryParam;
 import org.apache.ozhera.trace.etl.domain.jaegeres.JaegerProcess;
 
+import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
@@ -36,15 +44,28 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+@Slf4j
 @Service
 public class TraceService {
 
     /**
      * call trace-etl-manager TraceQueryService, The group and version in 
Dubbo should be consistent with the group and version in TraceQueryServiceImpl 
in trace-etl-manager.
      */
-    @DubboReference(interfaceClass = TraceQueryService.class, group = 
"${trace.query.group}", version = "${trace.query.version}")
+    @DubboReference(interfaceClass = TraceQueryService.class, group = 
"${trace.query.group}", version = "${trace.query.version}", check = false)
     private TraceQueryService traceQueryService;
 
+    /**
+     * Trace span sectional API URL
+     */
+    @Value("${trace.span.sectional.url}")
+    private String traceSpanSectionalUrl;
+
+    /**
+     * Trace query mode: http or dubbo
+     */
+    @Value("${trace.query.mode:dubbo}")
+    private String traceQueryMode;
+
     /**
      * The time range threshold for querying before and after the given 
timestamp.
      * The actual query range is calculated by subtracting and adding 
QUERY_TIME_RANGE to the given timestamp.
@@ -65,18 +86,106 @@ public class TraceService {
     /**
      * Query trace based on the specified trace query conditions.
      *
-     * @param param
-     * @return
+     * @param param trace query parameters
+     * @return list of filtered spans
      */
     public List<Span> queryTraceRootAnalysis(TraceQueryParam param) {
-        Trace traceResult = 
traceQueryService.getByTraceId(buildTraceIdQueryVo(param));
-        List<Span> result = new ArrayList<>();
-        if (traceResult != null && traceResult.getSpans() != null && 
!traceResult.getSpans().isEmpty()) {
-            // analyze and cut span
-            List<Span> analyze = analyzeTrace(traceResult.getSpans(), 
TRACE_DEEP);
-            result = getSpansFilter(analyze);
+        // Check query mode configuration
+        if ("http".equalsIgnoreCase(traceQueryMode)) {
+            // Use HTTP API - return result directly without filtering 
(already filtered by API)
+            log.info("Using HTTP mode to query trace spans");
+            try {
+                List<Span> spans = querySpansBySectionalApi(param);
+                if (spans != null) {
+                    log.info("Successfully fetched {} spans from sectional 
API", spans.size());
+                    return spans;
+                } else {
+                    log.warn("HTTP API returned null, returning empty list");
+                    return new ArrayList<>();
+                }
+            } catch (Exception e) {
+                log.error("Failed to fetch spans from sectional API", e);
+                return new ArrayList<>();
+            }
+        } else {
+            // Use Dubbo mode - apply analysis and filtering logic
+            log.info("Using Dubbo mode to query trace spans");
+            Trace traceResult = 
traceQueryService.getByTraceId(buildTraceIdQueryVo(param));
+            List<Span> result = new ArrayList<>();
+            if (traceResult != null && traceResult.getSpans() != null && 
!traceResult.getSpans().isEmpty()) {
+                // analyze and cut span
+                List<Span> analyze = analyzeTrace(traceResult.getSpans(), 
TRACE_DEEP);
+                result = getSpansFilter(analyze);
+            }
+            return result;
+        }
+    }
+
+    /**
+     * Query spans from the sectional API via HTTP
+     *
+     * @param param trace query parameters
+     * @return list of spans
+     */
+    private List<Span> querySpansBySectionalApi(TraceQueryParam param) {
+        try {
+            String url = buildSectionalApiUrl(param);
+            log.info("Calling sectional API: {}", url);
+
+            String response = HttpClient.get(url, new HashMap<>());
+            if (response == null || response.isEmpty()) {
+                log.error("Empty response from sectional API");
+                return null;
+            }
+
+            // Parse the JSON response into Result<List<Span>>
+            Gson gson = new Gson();
+            JsonObject jsonObject = gson.fromJson(response, JsonObject.class);
+
+            // Check if response is successful (code == 0 or code == 200)
+            if (jsonObject.has("code")) {
+                int code = jsonObject.get("code").getAsInt();
+                if (code != 0 && code != 200) {
+                    String message = jsonObject.has("message") ? 
jsonObject.get("message").getAsString() : "Unknown error";
+                    log.error("Failed to get spans from sectional API, code: 
{}, message: {}", code, message);
+                    return null;
+                }
+            }
+
+            // Extract data field and parse as List<Span>
+            if (jsonObject.has("data") && 
!jsonObject.get("data").isJsonNull()) {
+                TypeToken<List<Span>> typeToken = new TypeToken<List<Span>>() 
{};
+                List<Span> spans = gson.fromJson(jsonObject.get("data"), 
typeToken.getType());
+                return spans;
+            } else {
+                log.warn("No data field in response from sectional API");
+                return null;
+            }
+        } catch (Exception e) {
+            log.error("Error calling sectional API", e);
+            return null;
+        }
+    }
+
+    /**
+     * Build the URL for the sectional API
+     *
+     * @param param trace query parameters
+     * @return complete URL with query parameters
+     */
+    private String buildSectionalApiUrl(TraceQueryParam param) {
+        try {
+            URIBuilder builder = new URIBuilder(traceSpanSectionalUrl);
+            builder.addParameter("traceId", param.getTraceId());
+            builder.addParameter("env", param.getEnv());
+            if(param.getTimeStamp() != null) {
+                builder.addParameter("time", 
String.valueOf(param.getTimeStamp()));
+            }
+            return builder.build().toString();
+        } catch (URISyntaxException e) {
+            log.error("Error building sectional API URL", e);
+            throw new RuntimeException("Failed to build sectional API URL", e);
         }
-        return result;
     }
 
     /**


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to