This is an automated email from the ASF dual-hosted git repository.
gaoxihui 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 59102e10 fix: merge intelligence into master (#576)
59102e10 is described below
commit 59102e10b64e1d8c0268b9007d553804f8c3b02e
Author: EricDing <[email protected]>
AuthorDate: Mon Apr 7 14:49:11 2025 +0800
fix: merge intelligence into master (#576)
* fix: delete unused annotation
* fix: upgrade app-api and app-common version to 3
* fix: delete rocksDB unit test
* fix: update trace-etl file header, include java and md file
* fix: add trace-etl file header type, properties and xml
* fix: update webhook package
* feat: prepare for release
* feat: add binary tarball configuration
* fix: add liecense header to the newly added file
* fix: binary tarball adds instructions and scripts to the demo module
* feat: prepare to release version 2.2.5-incubating
* fix: update distribution configuration
* feat: Preparing to release version 2.2.5-incubating
* feat: update copyright year
* feat: Updated Copyright Notice
* feat: offer HeraLogApiService service (#528)
* feat: add HeraLogApiService
* feat: offer HeraLogApiService service
* refactor: optimize the log query code and add comments
* refactor: added query support for Doris storage type logs
* feat: add trace query and analyze filter
* feat: add log query
* feat: add metrics query
* feat: add controller layer code; improve the documentation
* feat: operator add intelligence yaml and nacos properties
* fix: transform en
* fix: add intelligence implementation (#533)
* feat: add trace query and analyze filter
* feat: add log query
* feat: add metrics query
* feat: add controller layer code; improve the documentation
* feat: operator add intelligence yaml and nacos properties
* fix: transform en
* fix: revert dist ozhera webhook dockerfile
---------
Co-authored-by: gaoxihui <[email protected]>
Co-authored-by: wtt <[email protected]>
---
.asf.yaml | 2 +-
dist/README.md | 62 +++++
dist/README_CN.md | 66 +++++
dist/dockerfiles/ozhera-webhook/Dockerfile | 2 +-
ozhera-intelligence/README.md | 12 +
ozhera-intelligence/README_cn.md | 14 +
.../ozhera-intelligence-domain/pom.xml | 4 +
...QueryParam.java => HeraRootCaseAnalyseRes.java} | 21 +-
.../intelligence/domain/rootanalysis/Metric.java | 94 +++++++
...eryParam.java => MetricDataRangeSetVector.java} | 13 +-
...eQueryParam.java => MetricDataRangeVector.java} | 12 +-
...ryParam.java => MetricRangeResponseVector.java} | 13 +-
.../domain/rootanalysis/MetricsQueryParam.java | 4 +
.../domain/rootanalysis/TraceQueryParam.java | 4 +-
.../{TraceQueryParam.java => TraceTreeNode.java} | 25 +-
.../ozhera-intelligence-server/pom.xml | 2 +-
.../intelligence/config/DubboConfiguration.java | 71 +++++
.../intelligence/config/NacosConfiguration.java} | 30 +--
.../controller/RootAnalysisController.java | 56 +++-
.../intelligence/filter/TokenValidationFilter.java | 53 ++++
.../src/main/resources/application.properties | 13 +-
.../resources/config/opensource-outer.properties | 13 +-
.../ozhera-intelligence-service/pom.xml | 80 +++++-
.../ozhera/intelligence/service/LogService.java | 42 ++-
.../intelligence/service/MetricsService.java | 220 +++++++++++++++-
.../ozhera/intelligence/service/TraceService.java | 286 ++++++++++++++++++++-
.../ozhera/intelligence/util/CommitPoolUtil.java | 48 ++++
.../ozhera/intelligence/util/HttpClient.java | 92 +++++++
ozhera-intelligence/pom.xml | 17 +-
.../ozhera/log/api/model/dto/LogFilterOptions.java | 36 +--
.../ozhera/log/api/model/dto/LogUrlParam.java | 22 +-
.../ozhera/log/api/service/HeraLogApiService.java | 25 +-
.../service/impl/HeraLogApiServiceImpl.java | 279 ++++++++++++++++++++
.../intelligence/ozhera_intelligence.yml | 33 ++-
..._intelligence_config_#_DEFAULT_GROUP.properties | 10 +-
ozhera-webhook/ozhera-webhook-server/Dockerfile | 2 +-
ozhera-webhook/pom.xml | 6 -
readme/images/ozhera-intelligence.png | Bin 0 -> 347752 bytes
.../trace/etl/api/service/TraceQueryService.java | 22 +-
trace-etl/trace-etl-manager/Dockerfile | 2 +-
.../etl/manager/dubbo/TraceQueryServiceImpl.java | 61 +++++
41 files changed, 1725 insertions(+), 144 deletions(-)
diff --git a/.asf.yaml b/.asf.yaml
index f4ea13b7..4c407968 100644
--- a/.asf.yaml
+++ b/.asf.yaml
@@ -19,4 +19,4 @@ github:
description: Apache OzHera is an About Application Observable Platform in
the Cloud Native Era.
homepage: https://ozhera.apache.org/
labels:
- - apm
+ - apm
\ No newline at end of file
diff --git a/dist/README.md b/dist/README.md
new file mode 100644
index 00000000..ee1a553f
--- /dev/null
+++ b/dist/README.md
@@ -0,0 +1,62 @@
+<!--
+
+ 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.
+
+-->
+
+## 1. Build the project
+You can use the following command to build the project from the source code
+mvn clean install -Papache-release -Dmaven.test.skip=true
+
+## 2. Resource usage instructions
+The binary tarball provides executable jar files according to the directory
hierarchy, and comes with the corresponding Dockerfile
+You can use the corresponding jar package and the corresponding Dockerfile to
build the image.
+
+## 3. Build the image
+The corresponding executable jar package and the corresponding Dockerfile are
provided in each directory. You need to switch to the directory corresponding
to the Dockerfile first, and execute the command:
+build . --build-arg SRC_PATH=. --build-arg APP_VERSION=2.2.5-incubating -t
${DOCKER_USERNAME}/${REPOSITORY_NAME}:${TAG}
+
+Note: Because the environment variables SRC_PATH and APP_VERSION are used in
Dockerfile, the corresponding parameter values need to be specified when
building the image
+SRC_PATH: The path where the executable jar package is located. If you have
switched to the directory corresponding to the Dockerfile, the executable jar
package and the Dockerfile are in the same directory, so you can specify the
current directory.
+APP_VERSION: This version is 2.2.5-incubating
+
+Example:
+cd ozhera-app/app-server
+docker build . --build-arg SRC_PATH=./target --build-arg
APP_VERSION=2.2.5-incubating -t
herahub/opensource-pub:app-server-2.2.5-incubating-beta-v1
+
+## 4. How to deploy the project
+
+During the startup process, OzHera's services rely on many basic services,
including: mysql, Nacos, elasticsearch, Redis, RocketMQ, grafana, prometheus,
alertManager, node-exporter, Cadvisor, etc.;
+In addition, the configuration items of each module and the dependencies
between projects make it a very complicated process to manually start each
application. Therefore, OzHera
+provides an operator that is convenient for users to use. You can follow the
instructions in the following link to make your deployment process simple and
easy.
+
+For the deployment process, you need to refer to the following documentation
+https://ozhera.apache.org/zh/docs/deployment.html
+https://ozhera.apache.org/en/docs/deployment.html
+
+Of course, before using the operator, you need to build the image of the
corresponding service module under OzHera for the operator to use during the
deployment process.
+
+## 5. How to build executable jar files from source code
+All executable jar files can be obtained through source code building;
+You can execute the following command in the root directory of the project
(ozhera) or the directory where the submodule is located to obtain the
corresponding executable jar package:
+mvn clean install -Papache-release -Dmaven.test.skip=true
+Note: The parameter -Papache-release must be added here
+
+### Build environment requirements
+You need to rely on the environment to build the project locally:
+maven3 and jdk21
\ No newline at end of file
diff --git a/dist/README_CN.md b/dist/README_CN.md
new file mode 100644
index 00000000..355bb3dd
--- /dev/null
+++ b/dist/README_CN.md
@@ -0,0 +1,66 @@
+<!--
+
+ 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.
+
+-->
+
+## 1、构建项目
+可使用如下命令从源代码构建项目
+mvn clean install -Papache-release -Dmaven.test.skip=true
+
+## 2、资源使用说明
+二进制tarball下按目录层次提供了可执行jar文件,并附带了对应的Dockerfile
+您可以使用对应的jar包和对应的Dockerfile构建镜像.
+
+## 3、构建镜像
+在每个目录下都提供了对应的可执行jar包和对应的Dockerfile,你需要先切换到Dockerfile对应的
+目录下,并且执行命令:
+build . --build-arg SRC_PATH=. --build-arg APP_VERSION=2.2.5-incubating -t
${DOCKER_USERNAME}/${REPOSITORY_NAME}:${TAG}
+
+
+说明:因为Dockerfile中使用了环境变量SRC_PATH和APP_VERSION,在构建镜像的时候需要指定相应的参数值
+SRC_PATH:
可执行jar包所在位置路径,如果已经切换到了Dockerfile对应的目录下,可执行jar包与Dockerfile在相同的目录下,所以指定当前目录即可。
+APP_VERSION: 本次版本是2.2.5-incubating
+
+例子:
+cd ozhera-app/app-server
+docker build . --build-arg SRC_PATH=./target --build-arg
APP_VERSION=2.2.5-incubating -t
herahub/opensource-pub:app-server-2.2.5-incubating-beta-v1
+
+## 4、如何部署项目
+
+OzHera的服务在启动过程中,依赖了众多基础服务,包括:mysql、Nacos、
+elasticsearch、Redis、RocketMQ、grafana、prometheus、
+alertManager、node-exporter、Cadvisor等;
+另,加之各个模块的配置项, 以及项目之前的依赖关系,使得手动启动各应用是一项很复杂的过程,因此OzHera
+提供了便利用户使用的operator,可以通过以下的链接按照说明文档界面化操作, 使您的部署过程变得简单易行。
+
+部署过程您需要参考以下说明文档
+https://ozhera.apache.org/zh/docs/deployment.html
+https://ozhera.apache.org/en/docs/deployment.html
+
+当然,在使用operator之前,您需要先构建OzHera下的相应的服务模块的镜像, 以供operator在部署过程中使用。
+
+## 5、如何通过源代码构建可执行jar文件
+所有的可执行jar文件,您都可以通过源码构建获取;
+你可以在项目的根目录(ozhera),或者子模块所在的目录执行以下命令,来获取对应的可执行jar包:
+mvn clean install -Papache-release -Dmaven.test.skip=true
+注意:这里一定要加上参数-Papache-release
+
+### 构建环境要求
+您在本地构建项目需要依赖的环境:
+maven3 和 jdk21
\ No newline at end of file
diff --git a/dist/dockerfiles/ozhera-webhook/Dockerfile
b/dist/dockerfiles/ozhera-webhook/Dockerfile
index 3c798269..32202ffb 100644
--- a/dist/dockerfiles/ozhera-webhook/Dockerfile
+++ b/dist/dockerfiles/ozhera-webhook/Dockerfile
@@ -22,4 +22,4 @@ COPY ${SRC_PATH}/ozhera-webhook-server-${APP_VERSION}.jar
/home/work/hera-webhoo
COPY ${LIB_PATH}/lib /home/work/lib/
COPY ${LIB_PATH}/ext-lib /home/work/lib/
-ENTRYPOINT
["java","-Duser.timezone=Asia/Shanghai","-cp","/home/work/hera-webhook-server.jar:/home/work/lib/*","org.apache.ozhera.webhook.Bootstrap","&&","tail","-f","/dev/null"]
+ENTRYPOINT
["java","-Duser.timezone=Asia/Shanghai","-cp","/home/work/hera-webhook-server.jar:/home/work/lib/*","org.apache.ozhera.webhook.Bootstrap","&&","tail","-f","/dev/null"]
\ No newline at end of file
diff --git a/ozhera-intelligence/README.md b/ozhera-intelligence/README.md
index fcbee8e4..6df452c4 100644
--- a/ozhera-intelligence/README.md
+++ b/ozhera-intelligence/README.md
@@ -30,4 +30,16 @@
## ozhera-intelligence-server
+ Service to initiate intelligent functionalities.
++ Access to the ozhera-intelligence-server requires the x-token to be included
in the header for authorized access to ozhera's data.
+## ozhera-intelligence-service
+
++ LogService: Retrieves log data
++ MetricsService: Retrieves monitoring metric data
++ TraceService: Retrieves trace data
+
+# Important Dependencies
+It relies on a Xiaomi open-source [Agent builder
platform--m78](https://github.com/XiaoMi/mone/tree/master/m78-all)
+
+# Intelligent Workflow (Sequence Diagram)
+
\ No newline at end of file
diff --git a/ozhera-intelligence/README_cn.md b/ozhera-intelligence/README_cn.md
index d1f3e85a..d2a448c2 100644
--- a/ozhera-intelligence/README_cn.md
+++ b/ozhera-intelligence/README_cn.md
@@ -29,3 +29,17 @@
## ozhera-intelligence-server
+ 智能化功能启动服务。
++ ozhera-intelligence-server访问需要header中带上x-token,实现有权限的访问ozhera的数据。
+
+## ozhera-intelligence-service
+
++ LogService,取日志数据
++ MetricsService,取监控指标数据
++ TraceService,取链路数据
+
+# 重要依赖
+会依赖小米开源的一款[Agent构建平台——m78](https://github.com/XiaoMi/mone/tree/master/m78-all)
+
+
+# 智能化工作流程(时序图)
+
\ No newline at end of file
diff --git a/ozhera-intelligence/ozhera-intelligence-domain/pom.xml
b/ozhera-intelligence/ozhera-intelligence-domain/pom.xml
index 0043cfc1..53843913 100644
--- a/ozhera-intelligence/ozhera-intelligence-domain/pom.xml
+++ b/ozhera-intelligence/ozhera-intelligence-domain/pom.xml
@@ -41,6 +41,10 @@
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.ozhera</groupId>
+ <artifactId>trace-etl-domain</artifactId>
+ </dependency>
</dependencies>
<build>
diff --git
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TraceQueryParam.java
b/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/HeraRootCaseAnalyseRes.java
similarity index 74%
copy from
ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TraceQueryParam.java
copy to
ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/HeraRootCaseAnalyseRes.java
index 18fdcdf1..bca831c3 100644
---
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TraceQueryParam.java
+++
b/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/HeraRootCaseAnalyseRes.java
@@ -18,15 +18,20 @@
*/
package org.apache.ozhera.intelligence.domain.rootanalysis;
-import lombok.Builder;
import lombok.Data;
+import lombok.ToString;
-import java.util.List;
-
+/**
+ * @author dingtao
+ * @date 2025/1/20 11:26
+ */
@Data
-@Builder
-public class TraceQueryParam {
- private String traceId;
- private String env;
- private List<String> timeStamp;
+@ToString
+public class HeraRootCaseAnalyseRes {
+ private Double maxCpuUsage;
+ private Double maxLoad;
+ private Double maxJvmHeapUsage;
+ private Double maxSTWCost;
+ private Double STWCountOf1m;
+ private Double cpuCount;
}
diff --git
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/Metric.java
b/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/Metric.java
new file mode 100644
index 00000000..d3cd46d8
--- /dev/null
+++
b/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/Metric.java
@@ -0,0 +1,94 @@
+/*
+ * 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.domain.rootanalysis;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class Metric implements Serializable {
+ private String application;
+ private String instance;
+ private String ip;
+ private String job;
+
+ private String replica;
+ private String serverIp;
+
+ //dubbo label
+ private String methodName;
+ private String serviceName;
+
+ //sql
+ private String sqlMethod;
+ private String sql;
+ private String dataSource;
+
+ //redis
+ private String host;
+ private String port;
+ private String dbindex;
+ private String method;
+
+ //env
+ private String serverEnv;
+
+ //container info
+ private String container_label_PROJECT_ID;
+ private String name;//container name eg:zzytest-20220323221926067
+ private String container;//container name for k8s
eg:youpin-gateway-dingtao-test2-900329(gitGroup-gitName-envId)
+ private String pod;//pod name for k8s
eg:91102-dingtao-test-644758f5b4-jk9t7
+ private String namespace;//namespace name for k8s eg:nrme
+
+ private String lastCreateTime;
+
+ private double value;
+
+ private String timestamp;
+
+ private String traceId;
+
+ private String service;
+
+ private String apiid;
+
+ private String serialid;
+
+ private String sceneid;
+
+ private String pod_ip;
+
+ private String calert;
+
+ private String alert_op;
+
+ private String alert_value;
+
+ private String detailRedirectUrl;
+
+ private String __priority__;
+
+ // downstream service information
+ private String clientProjectId;
+ private String clientProjectName;
+ private String clientEnv;
+ private String clientIp;
+
+}
diff --git
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TraceQueryParam.java
b/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/MetricDataRangeSetVector.java
similarity index 82%
copy from
ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TraceQueryParam.java
copy to
ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/MetricDataRangeSetVector.java
index 18fdcdf1..eac24817 100644
---
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TraceQueryParam.java
+++
b/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/MetricDataRangeSetVector.java
@@ -18,15 +18,16 @@
*/
package org.apache.ozhera.intelligence.domain.rootanalysis;
-import lombok.Builder;
import lombok.Data;
+import lombok.ToString;
+import java.io.Serializable;
import java.util.List;
@Data
-@Builder
-public class TraceQueryParam {
- private String traceId;
- private String env;
- private List<String> timeStamp;
+@ToString
+public class MetricDataRangeSetVector implements Serializable {
+ private Metric metric;
+ private List<List<String>> values;
}
+
diff --git
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TraceQueryParam.java
b/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/MetricDataRangeVector.java
similarity index 81%
copy from
ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TraceQueryParam.java
copy to
ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/MetricDataRangeVector.java
index 18fdcdf1..8f2e1d2d 100644
---
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TraceQueryParam.java
+++
b/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/MetricDataRangeVector.java
@@ -18,15 +18,15 @@
*/
package org.apache.ozhera.intelligence.domain.rootanalysis;
-import lombok.Builder;
import lombok.Data;
+import lombok.ToString;
+import java.io.Serializable;
import java.util.List;
@Data
-@Builder
-public class TraceQueryParam {
- private String traceId;
- private String env;
- private List<String> timeStamp;
+@ToString
+public class MetricDataRangeVector implements Serializable {
+ private String resultType;
+ private List<MetricDataRangeSetVector> result;
}
diff --git
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TraceQueryParam.java
b/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/MetricRangeResponseVector.java
similarity index 82%
copy from
ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TraceQueryParam.java
copy to
ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/MetricRangeResponseVector.java
index 18fdcdf1..70bc9343 100644
---
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TraceQueryParam.java
+++
b/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/MetricRangeResponseVector.java
@@ -18,15 +18,14 @@
*/
package org.apache.ozhera.intelligence.domain.rootanalysis;
-import lombok.Builder;
import lombok.Data;
+import lombok.ToString;
-import java.util.List;
+import java.io.Serializable;
@Data
-@Builder
-public class TraceQueryParam {
- private String traceId;
- private String env;
- private List<String> timeStamp;
+@ToString
+public class MetricRangeResponseVector implements Serializable {
+ private String status;
+ private MetricDataRangeVector data;
}
diff --git
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/MetricsQueryParam.java
b/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/MetricsQueryParam.java
index 96541b9d..98a64481 100644
---
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/MetricsQueryParam.java
+++
b/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/MetricsQueryParam.java
@@ -20,9 +20,11 @@ package org.apache.ozhera.intelligence.domain.rootanalysis;
import lombok.Builder;
import lombok.Data;
+import lombok.ToString;
@Data
@Builder
+@ToString
public class MetricsQueryParam {
private String env;
@@ -33,6 +35,8 @@ public class MetricsQueryParam {
private String startTime;
+ private String endTime;
+
private String duration;
// The error margin between the start time and end time,
diff --git
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TraceQueryParam.java
b/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TraceQueryParam.java
index 18fdcdf1..b9de7208 100644
---
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TraceQueryParam.java
+++
b/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TraceQueryParam.java
@@ -20,13 +20,15 @@ package org.apache.ozhera.intelligence.domain.rootanalysis;
import lombok.Builder;
import lombok.Data;
+import lombok.ToString;
import java.util.List;
@Data
@Builder
+@ToString
public class TraceQueryParam {
private String traceId;
private String env;
- private List<String> timeStamp;
+ private long timeStamp;
}
diff --git
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TraceQueryParam.java
b/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TraceTreeNode.java
similarity index 68%
copy from
ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TraceQueryParam.java
copy to
ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TraceTreeNode.java
index 18fdcdf1..14998c59 100644
---
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TraceQueryParam.java
+++
b/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TraceTreeNode.java
@@ -18,15 +18,28 @@
*/
package org.apache.ozhera.intelligence.domain.rootanalysis;
-import lombok.Builder;
import lombok.Data;
+import org.apache.ozhera.trace.etl.domain.tracequery.Span;
+import java.util.ArrayList;
import java.util.List;
@Data
-@Builder
-public class TraceQueryParam {
- private String traceId;
- private String env;
- private List<String> timeStamp;
+public class TraceTreeNode {
+
+ private Span span;
+ private List<TraceTreeNode> children;
+
+ public TraceTreeNode(Span span){
+ this.span = span;
+ this.children = new ArrayList<>();
+ }
+
+ public TraceTreeNode(){
+
+ }
+
+ public void addChild(TraceTreeNode child) {
+ children.add(child);
+ }
}
diff --git a/ozhera-intelligence/ozhera-intelligence-server/pom.xml
b/ozhera-intelligence/ozhera-intelligence-server/pom.xml
index 71487643..61d46514 100644
--- a/ozhera-intelligence/ozhera-intelligence-server/pom.xml
+++ b/ozhera-intelligence/ozhera-intelligence-server/pom.xml
@@ -80,7 +80,7 @@
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.7.15</version>
<configuration>
-
<mainClass>org.apache.ozhera.trace.etl.bootstrap.TraceEtlBootstrap</mainClass>
+
<mainClass>org.apache.ozhera.intelligence.bootstrap.IntelligenceBootStrap</mainClass>
</configuration>
<executions>
<execution>
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
new file mode 100644
index 00000000..f672299f
--- /dev/null
+++
b/ozhera-intelligence/ozhera-intelligence-server/src/main/java/org/apache/ozhera/intelligence/config/DubboConfiguration.java
@@ -0,0 +1,71 @@
+/*
+ * 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.config;
+
+import com.alibaba.nacos.api.config.annotation.NacosValue;
+import com.google.common.collect.Maps;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ProtocolConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class DubboConfiguration {
+
+ @Value("${dubbo.protocol.port}")
+ private int port;
+
+ @Value("${server.port}")
+ private String httpGateWayPort;
+
+ @NacosValue("${dubbo.registry.address}")
+ private String regAddress;
+
+ @Bean
+ public ApplicationConfig applicationConfig() {
+ ApplicationConfig applicationConfig = new ApplicationConfig();
+ applicationConfig.setName("Trace-etl-manager");
+ applicationConfig.setParameters(Maps.newHashMap());
+ applicationConfig.getParameters().put("http_gateway_port",
httpGateWayPort);
+ applicationConfig.getParameters().put("dubbo_version", "1.0");
+ applicationConfig.setQosEnable(false);
+ return applicationConfig;
+ }
+
+ @Bean
+ public RegistryConfig registryConfig() {
+ RegistryConfig registryConfig = new RegistryConfig();
+ registryConfig.setAddress(regAddress);
+ return registryConfig;
+ }
+
+ @Bean
+ public ProtocolConfig protocolConfig() {
+ ProtocolConfig protocolConfig = new ProtocolConfig();
+ protocolConfig.setPort(port);
+ protocolConfig.setTransporter("netty4");
+ protocolConfig.setThreadpool("fixed");
+ protocolConfig.setThreads(800);
+ return protocolConfig;
+ }
+
+}
\ No newline at end of file
diff --git
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/MetricsQueryParam.java
b/ozhera-intelligence/ozhera-intelligence-server/src/main/java/org/apache/ozhera/intelligence/config/NacosConfiguration.java
similarity index 60%
copy from
ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/MetricsQueryParam.java
copy to
ozhera-intelligence/ozhera-intelligence-server/src/main/java/org/apache/ozhera/intelligence/config/NacosConfiguration.java
index 96541b9d..cb7d29d4 100644
---
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/MetricsQueryParam.java
+++
b/ozhera-intelligence/ozhera-intelligence-server/src/main/java/org/apache/ozhera/intelligence/config/NacosConfiguration.java
@@ -16,26 +16,16 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.ozhera.intelligence.domain.rootanalysis;
-import lombok.Builder;
-import lombok.Data;
+package org.apache.ozhera.intelligence.config;
-@Data
-@Builder
-public class MetricsQueryParam {
+import com.alibaba.nacos.api.annotation.NacosProperties;
+import com.alibaba.nacos.spring.context.annotation.config.EnableNacosConfig;
+import com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource;
+import org.springframework.context.annotation.Configuration;
- private String env;
-
- private String application;
-
- private String ip;
-
- private String startTime;
-
- private String duration;
-
- // The error margin between the start time and end time,
- // the actual query time range is [startTime - gap, endTime + gap]
- private String gap;
-}
+@Configuration
+@EnableNacosConfig(globalProperties = @NacosProperties(serverAddr =
"${nacos.address}"))
+@NacosPropertySource(dataId = "hera_intelligence_config", autoRefreshed = true)
+public class NacosConfiguration {
+}
\ No newline at end of file
diff --git
a/ozhera-intelligence/ozhera-intelligence-server/src/main/java/org/apache/ozhera/intelligence/controller/RootAnalysisController.java
b/ozhera-intelligence/ozhera-intelligence-server/src/main/java/org/apache/ozhera/intelligence/controller/RootAnalysisController.java
index 62ba03c2..aad511cc 100644
---
a/ozhera-intelligence/ozhera-intelligence-server/src/main/java/org/apache/ozhera/intelligence/controller/RootAnalysisController.java
+++
b/ozhera-intelligence/ozhera-intelligence-server/src/main/java/org/apache/ozhera/intelligence/controller/RootAnalysisController.java
@@ -19,13 +19,23 @@
package org.apache.ozhera.intelligence.controller;
import com.xiaomi.youpin.infra.rpc.Result;
+import com.xiaomi.youpin.infra.rpc.errors.GeneralCodes;
import lombok.extern.slf4j.Slf4j;
+import
org.apache.ozhera.intelligence.domain.rootanalysis.HeraRootCaseAnalyseRes;
+import org.apache.ozhera.intelligence.domain.rootanalysis.LogParam;
+import org.apache.ozhera.intelligence.domain.rootanalysis.MetricsQueryParam;
+import org.apache.ozhera.intelligence.service.LogService;
+import org.apache.ozhera.intelligence.service.MetricsService;
+import org.apache.ozhera.intelligence.service.TraceService;
+import org.apache.ozhera.trace.etl.domain.tracequery.Span;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.apache.ozhera.intelligence.domain.rootanalysis.TraceQueryParam;
-import org.apache.ozhera.intelligence.service.RootAnalysisService;
+
+import java.util.List;
+import java.util.Map;
@RestController
@RequestMapping("/analysis")
@@ -33,10 +43,44 @@ import
org.apache.ozhera.intelligence.service.RootAnalysisService;
public class RootAnalysisController {
@Autowired
- private RootAnalysisService rootAnalysisService;
+ private TraceService traceService;
+
+ @Autowired
+ private LogService logService;
+
+ @Autowired
+ private MetricsService metricsService;
+
+ @PostMapping("/trace/sectional/span")
+ public Result<List<Span>> traceRootAnalysis(TraceQueryParam param) {
+ try {
+ List<Span> spans = traceService.queryTraceRootAnalysis(param);
+ return Result.success(spans);
+ }catch (Exception e){
+ log.error("trace analyze error , ", e);
+ return Result.fail(GeneralCodes.InternalError, "trace analyze
error");
+ }
+ }
+
+ @PostMapping("/log/condition")
+ public Result<List<Map<String, Object>>> logCondition(LogParam param) {
+ try {
+ List<Map<String, Object>> logs =
logService.queryLogRootAnalysis(param);
+ return Result.success(logs);
+ }catch (Exception e){
+ log.error("log analyze error , ", e);
+ return Result.fail(GeneralCodes.InternalError, "log analyze
error");
+ }
+ }
- @GetMapping("/trace")
- public Result<String> traceRootAnalysis(TraceQueryParam param) {
- return rootAnalysisService.traceRootAnalysis(param);
+ @PostMapping("/metrics")
+ public Result<HeraRootCaseAnalyseRes> metrics(MetricsQueryParam param) {
+ try {
+ HeraRootCaseAnalyseRes metrics =
metricsService.queryMetricsRootAnalysis(param);
+ return Result.success(metrics);
+ }catch (Exception e){
+ log.error("metrics analyze error , ", e);
+ return Result.fail(GeneralCodes.InternalError, "metrics analyze
error");
+ }
}
}
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
new file mode 100644
index 00000000..572da052
--- /dev/null
+++
b/ozhera-intelligence/ozhera-intelligence-server/src/main/java/org/apache/ozhera/intelligence/filter/TokenValidationFilter.java
@@ -0,0 +1,53 @@
+/*
+ * 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.filter;
+
+import com.alibaba.nacos.api.config.annotation.NacosValue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+@Component
+public class TokenValidationFilter extends OncePerRequestFilter {
+
+ private static final Logger logger =
LoggerFactory.getLogger(TokenValidationFilter.class);
+
+ @NacosValue("${analyze.token}")
+ private String validToken;
+
+ @Override
+ protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
+ throws ServletException, IOException {
+ String token = request.getHeader("x-token");
+
+ if (token != null && token.equals(validToken)) {
+ filterChain.doFilter(request, response);
+ } else {
+ logger.warn("Token incorrect, illegal request!");
+ response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+ }
+ }
+}
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 a38e97e5..56919051 100644
---
a/ozhera-intelligence/ozhera-intelligence-server/src/main/resources/application.properties
+++
b/ozhera-intelligence/ozhera-intelligence-server/src/main/resources/application.properties
@@ -18,4 +18,15 @@ app.name=${app.name}
server.type=${server.type}
server.port=${server.port}
-log.path=${log.path}
\ No newline at end of file
+log.path=${log.path}
+
+dubbo.group=${dubbo.group}
+dubbo.protocol.id=${dubbo.protocol.id}
+dubbo.protocol.name=${dubbo.protocol.name}
+dubbo.protocol.port=${dubbo.protocol.port}
+trace.query.group=${trace.query.group}
+trace.query.version=${trace.query.version}
+log.query.group=${log.query.group}
+log.query.version=${log.query.version}
+
+nacos.address=${nacos.address}
\ 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 5ad085dd..08fdc828 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
@@ -18,4 +18,15 @@ app.name=ozhera-intelligence
server.type=staging
server.port=8080
-log.path=/tmp/work/log
\ No newline at end of file
+log.path=/tmp/work/log
+
+dubbo.group=staging
+dubbo.protocol.id=dubbo
+dubbo.protocol.name=dubbo
+dubbo.protocol.port=-1
+trace.query.group=staging
+trace.query.version=1.0
+log.query.group=
+log.query.version=1.0
+
+nacos.address=nacos:80
\ 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 63d98966..fd07f762 100644
--- a/ozhera-intelligence/ozhera-intelligence-service/pom.xml
+++ b/ozhera-intelligence/ozhera-intelligence-service/pom.xml
@@ -72,11 +72,16 @@
<artifactId>spring-test</artifactId>
</dependency>
- <!-- trace domain -->
+ <!-- trace api -->
<dependency>
<groupId>org.apache.ozhera</groupId>
- <artifactId>trace-etl-domain</artifactId>
- <version>2.2.6-SNAPSHOT</version>
+ <artifactId>trace-etl-api</artifactId>
+ </dependency>
+
+ <!-- log api -->
+ <dependency>
+ <groupId>org.apache.ozhera</groupId>
+ <artifactId>log-api</artifactId>
</dependency>
<dependency>
@@ -88,6 +93,75 @@
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
+
+ <dependency>
+ <groupId>run.mone</groupId>
+ <artifactId>dubbo</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>com.alibaba.spring</groupId>
+ <artifactId>spring-context-support</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <!-- nacos -->
+ <dependency>
+ <groupId>run.mone</groupId>
+ <artifactId>spring-context-support</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>run.mone</groupId>
+ <artifactId>nacos-client</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-core</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>run.mone</groupId>
+ <artifactId>dubbo-registry-nacos</artifactId>
+ <exclusions>
+ <exclusion>
+ <artifactId>spring-context-support</artifactId>
+ <groupId>com.alibaba.spring</groupId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>com.alibaba.nacos</groupId>
+ <artifactId>nacos-spring-context</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-core</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>com.alibaba.spring</groupId>
+ <artifactId>spring-context-support</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <!-- okhttp -->
+ <dependency>
+ <groupId>com.squareup.okhttp3</groupId>
+ <artifactId>okhttp</artifactId>
+ </dependency>
</dependencies>
<build>
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 4a1075d4..a59402f2 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
@@ -18,18 +18,54 @@
*/
package org.apache.ozhera.intelligence.service;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.apache.ozhera.log.api.model.dto.LogFilterOptions;
+import org.apache.ozhera.log.api.service.HeraLogApiService;
import org.springframework.stereotype.Service;
import org.apache.ozhera.intelligence.domain.rootanalysis.LogParam;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author dingtao
+ * @date 2025/1/20 11:26
+ */
@Service
public class LogService {
+ @DubboReference(interfaceClass = HeraLogApiService.class, group =
"${log.query.group}", version = "${log.query.version}")
+ private HeraLogApiService heraLogApiService;
+
/**
+ * To cover the trace time in the log, we extend the trace time by 5
minutes before and after as a condition to query the log
+ */
+ private static final int LOG_QUERY_TIME_GAP = 1000 * 60 * 5;
+
+
+ /**
* Query logs based on the specified log query conditions.
+ *
* @param param
* @return
*/
- public String queryLogRootAnalysis(LogParam param){
- return null;
+ public List<Map<String, Object>> queryLogRootAnalysis(LogParam param) {
+ List<Map<String, Object>> maps =
heraLogApiService.queryLogData(buildLogFilterOptions(param));
+ return maps;
+ }
+
+
+ private LogFilterOptions buildLogFilterOptions(LogParam param) {
+ LogFilterOptions logFilterOptions = new LogFilterOptions();
+ logFilterOptions.setProjectId(Long.parseLong(param.getApplication()));
+ logFilterOptions.setEnvId(Long.parseLong(param.getEnvId()));
+ logFilterOptions.setTraceId(param.getTraceId());
+ Long startTime = Long.parseLong(param.getStartTime());
+ Long duration = Long.parseLong(param.getDuration());
+ Long endTime = startTime + duration;
+ logFilterOptions.setStartTime(String.valueOf(startTime / 1000 -
LOG_QUERY_TIME_GAP));
+ logFilterOptions.setEndTime(String.valueOf(endTime / 1000 +
LOG_QUERY_TIME_GAP));
+ logFilterOptions.setLevel(param.getLevel());
+ return logFilterOptions;
}
-}
+}
\ No newline at end of file
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 9b17a893..0207be19 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,21 +18,231 @@
*/
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;
+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.stereotype.Service;
import org.apache.ozhera.intelligence.domain.rootanalysis.MetricsQueryParam;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+import static
org.apache.ozhera.intelligence.util.CommitPoolUtil.HERA_SOLUTION_METRICS_POOL;
+
/**
- *
+ * @author dingtao
+ * @date 2025/1/20 11:26
*/
@Service
+@Slf4j
public class MetricsService {
+ @NacosValue("${prometheus.api.url}")
+ private String prometheusUrl;
+
+ private static final String URI_QUERY_RANGE = "/api/v1/query_range";
+ private static final String P_QUERY = "query";
+ private static final String P_STEP = "step";
+ private static final String P_START = "start";
+ private static final String P_END = "end";
+
/**
* Query metrics based on the specified metric query conditions.
- * @param param
+ *
+ * @param req
* @return
*/
- public String queryMetricsRootAnalysis(MetricsQueryParam param){
- return null;
+ public HeraRootCaseAnalyseRes queryMetricsRootAnalysis(MetricsQueryParam
req) {
+ HeraRootCaseAnalyseRes res = new HeraRootCaseAnalyseRes();
+ try {
+ updateParam(req);
+ log.info("updated param is : " + req);
+ String kubePodInfoPromQl = getKubePodInfoPromQl(req.getIp());
+ log.info("getPodNameByKubePodInfo.kubePodInfoPromQl:{}",
kubePodInfoPromQl);
+ MetricRangeResponseVector podPodIpListVector =
requestPrometheusRangeV2(kubePodInfoPromQl,
+ req.getStartTime(), req.getEndTime(), req.getEnv());
+ List<MetricDataRangeSetVector> kubePodInfo =
podPodIpListVector.getData().getResult();
+ MetricDataRangeSetVector kubePodInfoMetrics =
kubePodInfo.get(kubePodInfo.size() - 1);
+ String podName = kubePodInfoMetrics.getMetric().getPod();
+ String cpuPromQl =
"max(rate(container_cpu_user_seconds_total{system=\"mione\",application=\"" +
req.getApplication() + "\", pod=\"" + podName + "\", image!=\"\", container =~
\"^(?:\\\\d+-0-\\\\d+|faas-sidecar)$\"}[30s]) * 100)";
+ String loadPromQl =
"max(container_cpu_load_average_10s{system=\"mione\",application=\"" +
req.getApplication() + "\", pod=\"" + podName + "\", image!=\"\", container =~
\"^(?:\\\\d+-0-\\\\d+|faas-sidecar)$\"} / 1000)";
+ String gcMaxTimes =
"max(delta(jvm_gc_pause_seconds_count{serverIp=\"" + req.getIp() + "\",
application=\"" + req.getApplication() + "\",containerName=\"main\"}[1m]))";
+ String memoryUsedRate =
"avg(sum(jvm_memory_used_bytes{application=\"" + req.getApplication() +
"\",area=\"heap\",ip=\"" + req.getIp() + "\",containerName=\"main\"}) /
sum(jvm_memory_max_bytes{application=\"" + req.getApplication() +
"\",area=\"heap\",ip=\"" + req.getIp() + "\",containerName=\"main\"})) * 100";
+ String maxGCDuration =
"max(max_over_time(jvm_gc_pause_seconds_max{serverIp=~\"" + req.getIp() + "\",
application=\"" + req.getApplication() + "\",containerName=\"main\"}[1m]))";
+ String cpuCount = "system_cpu_count{serverIp=~\"" + req.getIp() +
"\", application=\"" + req.getApplication() + "\",containerName=~\".*\"}";
+ log.info("getPodNameByKubePodInfo.cpuPromQl:{}", cpuPromQl);
+ log.info("getPodNameByKubePodInfo.loadPromQl:{}", loadPromQl);
+ log.info("getPodNameByKubePodInfo.gcMaxTimes:{}", gcMaxTimes);
+ log.info("getPodNameByKubePodInfo.memoryUsedRate:{}",
memoryUsedRate);
+ log.info("getPodNameByKubePodInfo.maxGCDuration:{}",
maxGCDuration);
+ log.info("getPodNameByKubePodInfo.cpuCount:{}", cpuCount);
+ CompletableFuture<MetricRangeResponseVector> cpuFuture =
CompletableFuture.supplyAsync(() -> requestPrometheusRangeV2(cpuPromQl,
+ req.getStartTime(), req.getEndTime(), req.getEnv()),
HERA_SOLUTION_METRICS_POOL);
+ CompletableFuture<MetricRangeResponseVector> loadFuture =
CompletableFuture.supplyAsync(() -> requestPrometheusRangeV2(loadPromQl,
+ req.getStartTime(), req.getEndTime(), req.getEnv()),
HERA_SOLUTION_METRICS_POOL);
+ CompletableFuture<MetricRangeResponseVector> gcMaxTimesFuture =
CompletableFuture.supplyAsync(() -> requestPrometheusRangeV2(gcMaxTimes,
+ req.getStartTime(), req.getEndTime(), req.getEnv()),
HERA_SOLUTION_METRICS_POOL);
+ CompletableFuture<MetricRangeResponseVector> memoryFuture =
CompletableFuture.supplyAsync(() -> requestPrometheusRangeV2(memoryUsedRate,
+ req.getStartTime(), req.getEndTime(), req.getEnv()),
HERA_SOLUTION_METRICS_POOL);
+ CompletableFuture<MetricRangeResponseVector> maxGCFuture =
CompletableFuture.supplyAsync(() -> requestPrometheusRangeV2(maxGCDuration,
+ req.getStartTime(), req.getEndTime(), req.getEnv()),
HERA_SOLUTION_METRICS_POOL);
+ CompletableFuture<MetricRangeResponseVector> cpuCountFuture =
CompletableFuture.supplyAsync(() -> requestPrometheusRangeV2(cpuCount,
+ req.getStartTime(), req.getEndTime(), req.getEnv()),
HERA_SOLUTION_METRICS_POOL);
+ CompletableFuture<Void> allComplete =
CompletableFuture.allOf(cpuFuture, loadFuture, gcMaxTimesFuture, memoryFuture,
maxGCFuture);
+ allComplete.get(8000, TimeUnit.MILLISECONDS);
+ MetricRangeResponseVector cpuMetrics = cpuFuture.get();
+ if (cpuMetrics != null) {
+ log.info("getPodNameByKubePodInfo cpuMetrics : " + cpuMetrics);
+ List<MetricDataRangeSetVector> cpuResult =
cpuMetrics.getData().getResult();
+ if (cpuResult != null && cpuResult.size() > 0) {
+ List<List<String>> values = cpuResult.get(0).getValues();
+ res.setMaxCpuUsage(getMaxValue(values));
+ }
+ }
+ MetricRangeResponseVector loadMetrics = loadFuture.get();
+ if (loadMetrics != null) {
+ log.info("getPodNameByKubePodInfo loadMetrics : " +
loadMetrics);
+ List<MetricDataRangeSetVector> loadResult =
loadMetrics.getData().getResult();
+ if (loadResult != null && loadResult.size() > 0) {
+ List<List<String>> values = loadResult.get(0).getValues();
+ res.setMaxLoad(getMaxValue(values));
+ }
+ }
+ MetricRangeResponseVector gcMaxTimesMetrics =
gcMaxTimesFuture.get();
+ if (gcMaxTimesMetrics != null) {
+ log.info("getPodNameByKubePodInfo gcMaxTimesMetrics : " +
gcMaxTimesMetrics);
+ List<MetricDataRangeSetVector> gcMaxTimesResult =
gcMaxTimesMetrics.getData().getResult();
+ if (gcMaxTimesResult != null && gcMaxTimesResult.size() > 0) {
+ List<List<String>> values =
gcMaxTimesResult.get(0).getValues();
+ res.setMaxSTWCost(getMaxValue(values));
+ }
+ }
+ MetricRangeResponseVector memoryMetrics = memoryFuture.get();
+ if (memoryMetrics != null) {
+ log.info("getPodNameByKubePodInfo memoryMetrics : " +
memoryMetrics);
+ List<MetricDataRangeSetVector> memoryResult =
memoryMetrics.getData().getResult();
+ if (memoryResult != null && memoryResult.size() > 0) {
+ List<List<String>> values =
memoryResult.get(0).getValues();
+ res.setMaxJvmHeapUsage(getMaxValue(values));
+ }
+ }
+ MetricRangeResponseVector maxGCMetrics = maxGCFuture.get();
+ if (maxGCMetrics != null) {
+ log.info("getPodNameByKubePodInfo maxGCMetrics : " +
maxGCMetrics);
+ List<MetricDataRangeSetVector> maxGCResult =
maxGCMetrics.getData().getResult();
+ if (maxGCResult != null && maxGCResult.size() > 0) {
+ List<List<String>> values = maxGCResult.get(0).getValues();
+ res.setSTWCountOf1m(getMaxValue(values));
+ }
+ }
+ MetricRangeResponseVector cpuCountMetrics = cpuCountFuture.get();
+ if (cpuCountMetrics != null) {
+ log.info("getPodNameByKubePodInfo maxGCMetrics : " +
cpuCountMetrics);
+ List<MetricDataRangeSetVector> cpuCountResult =
cpuCountMetrics.getData().getResult();
+ if (cpuCountResult != null && cpuCountResult.size() > 0) {
+ List<List<String>> values =
cpuCountResult.get(0).getValues();
+ res.setCpuCount(getMaxValue(values));
+ }
+ }
+ } catch (Exception e) {
+ log.error("get root cause analysis error , ", e);
+ }
+ return res;
+ }
+
+ private void updateParam(MetricsQueryParam req) {
+ Long startTime = Long.parseLong(req.getStartTime());
+ Long duration = Long.parseLong(req.getDuration());
+ Long endTime = startTime + duration;
+ Long gap = Long.parseLong(req.getGap());
+ // startTime is in microseconds, convert to milliseconds
+ Long startTimeMs = startTime / 1000;
+ Long endTimeMs = endTime / 1000;
+ req.setStartTime(addGap(startTimeMs, gap * -1));
+ req.setEndTime(addGap(endTimeMs, gap));
+ req.setApplication(convertApp(req.getApplication()));
+ }
+
+ private String getKubePodInfoPromQl(String hostIp) {
+ return "count(kube_pod_info{system=\"mione\",pod_ip=~\"" + hostIp +
"\"}) by (pod_ip,pod)";
+ }
+
+ private MetricRangeResponseVector requestPrometheusRangeV2(String promQl,
String startTime, String endTime, String env) {
+ try {
+ Map<String, String> map = new HashMap<>();
+ map.put(P_QUERY, promQl); // Metric parameter
+ // step: 1h = 15, 2h = 2 * 15
+ Long multi = (Long.parseLong(endTime) - Long.parseLong(startTime))
/ 3600;
+ if (multi < 1) {
+ multi = 1L;
+
+ }
+ map.put(P_STEP, String.valueOf(multi * 15));
+ map.put(P_START, startTime);
+ map.put(P_END, endTime);
+ String url = completeQueryUrl(prometheusUrl, URI_QUERY_RANGE,
promQl, map);
+ System.out.println(url);
+ Map<String, String> headers = new HashMap<>();
+ headers.put("Accept", "*/*");
+ log.info("queryPrometheusRangeResponse : {}", url.toString());
+ String data = HttpClient.get(url.toString(), headers);
+ MetricRangeResponseVector metricResult = new Gson().fromJson(data,
MetricRangeResponseVector.class);
+ if (metricResult == null ||
!"success".equals(metricResult.getStatus())) {
+ return null;
+ } else {
+ return metricResult;
+ }
+ } catch (Exception e) {
+ log.error("requestPrometheusRange err", e);
+ return null;
+ }
+ }
+
+ private String completeQueryUrl(String domain, String path, String query,
Map<String, String> map) {
+ URIBuilder builder = new URIBuilder();
+ builder.setScheme("http");
+ builder.setHost(domain);
+ builder.setPath(path);
+ map.forEach(builder::addParameter);
+ URL url = null;
+ try {
+ url = builder.build().toURL();
+ } catch (MalformedURLException e) {
+ throw new RuntimeException(e);
+ } catch (URISyntaxException e) {
+ throw new RuntimeException(e);
+ }
+ return url.toString();
+ }
+
+ private double getMaxValue(List<List<String>> values) {
+ List<Double> temValues = new ArrayList<>();
+ for (List<String> value : values) {
+ temValues.add(Double.valueOf(value.get(1)));
+ }
+ Collections.sort(temValues);
+ return temValues.get(temValues.size() - 1);
+ }
+
+ private String addGap(long time, long gap) {
+ // After calculating the time interval, convert ms to s
+ return String.valueOf((time + gap) / 1000);
+ }
+
+ private String convertApp(String application) {
+ return application.replaceAll("-", "_");
}
-}
+}
\ No newline at end of file
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 0705d049..b2ec745e 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,18 +18,298 @@
*/
package org.apache.ozhera.intelligence.service;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.apache.ozhera.intelligence.domain.rootanalysis.TraceTreeNode;
+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.stereotype.Service;
import org.apache.ozhera.intelligence.domain.rootanalysis.TraceQueryParam;
+import org.apache.ozhera.trace.etl.domain.jaegeres.JaegerProcess;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author dingtao
+ * @date 2025/1/20 11:26
+ */
@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}")
+ private TraceQueryService traceQueryService;
+
+ /**
+ * 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.
+ */
+ private static final long QUERY_TIME_RANGE = 30 * 60 * 1000;
+
+ /**
+ * The maximum depth of the analyzed trace to be retrieved.
+ */
+ private static final int TRACE_DEEP = 5;
+
+
+ private static final String SERVICE_ENV_ID_KEY = "service.env.id";
+ private static final List<String> NOT_RETAIN_SPAN_NAMES = List.of("UDS");
+ private static final List<String> RETAIN_TAGS =
Arrays.asList("net.sock.peer.addr", "span.kind", "net.sock.peer.port",
"http.target", "net.host.name", "net.peer.name", "net.peer.port",
"rpc.service", "rpc.method", "rpc.system", "db.statement", "error", "http.url");
+ private static final List<String> RETAIN_PROCESS_TAGS =
Arrays.asList(SERVICE_ENV_ID_KEY, "ip", "service.env", "service.env.id",
"service.container.name", "host.name");
+
/**
* Query trace based on the specified trace query conditions.
+ *
* @param param
* @return
*/
- public String queryTraceRootAnalysis(TraceQueryParam param){
- return null;
+ 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);
+ }
+ return result;
+ }
+
+ /**
+ * Analyze trace information and return a list of key Spans
+ * <p>
+ * This method first builds a TraceTreeNode tree, then analyzes the trace
information based on whether errors exist.
+ * If there are errors, it will find and return the most recent error node
and its child nodes.
+ * If there are no errors, it will search for time-consuming nodes.
+ *
+ * @param spans The list of Spans to be analyzed
+ * @param N The number of child nodes to return in case of errors
+ * @return A list containing key Spans, representing error nodes or
time-consuming nodes
+ */
+ public List<Span> analyzeTrace(List<Span> spans, int N) {
+ // Build TraceTreeNode tree
+
+ // Build TraceTreeNode tree
+ Map<String, TraceTreeNode> nodeMap = new HashMap<>();
+ boolean hasError = false;
+ for (Span span : spans) {
+ if (hasException(span)) {
+ hasError = true;
+ }
+ TraceTreeNode node = new TraceTreeNode(span);
+
+ nodeMap.put(span.getSpanID(), node);
+ }
+ List<TraceTreeNode> roots = new ArrayList<>();
+ for (TraceTreeNode node : nodeMap.values()) {
+ if (node.getSpan().getReferences().isEmpty() ||
+
!nodeMap.containsKey(node.getSpan().getReferences().get(0).getSpanID())) {
+ roots.add(node);
+ } else {
+ TraceTreeNode parentNode =
nodeMap.get(node.getSpan().getReferences().get(0).getSpanID());
+ parentNode.addChild(node);
+ }
+ }
+ // Sort sibling nodes by startTime
+ for (TraceTreeNode root : roots) {
+ sortChildren(root);
+ }
+ List<Span> result = new ArrayList<>();
+ if (hasError) {
+ // Find error nodes
+ List<TraceTreeNode> errorNodes = new ArrayList<>();
+ for (TraceTreeNode root : roots) {
+ findErrorTargetNode(root, errorNodes);
+ if (errorNodes != null && errorNodes.size() > 0) {
+ int currentChildCount = 0;
+ // Sort by Span.startTime, analyze the Span with the
latest start time, which is likely the most relevant
+ errorNodes.sort(Comparator.comparing(s ->
s.getSpan().getStartTime()));
+ TraceTreeNode lastErrorNode =
errorNodes.get(errorNodes.size() - 1);
+ result.add(lastErrorNode.getSpan());
+ addNChild(result, lastErrorNode, N, currentChildCount);
+ }
+ }
+ } else {
+ // Finding time-consuming nodes is more complex. We start with the
root node's duration as a baseline,
+ // and search level by level until there are no more child nodes
or no child nodes with significantly high duration.
+ List<TraceTreeNode> slowNodes = new ArrayList<>();
+ for (TraceTreeNode root : roots) {
+ long rootDuration = root.getSpan().getDuration();
+ slowNodes.add(root);
+ findSlowNode(root, slowNodes, rootDuration);
+ for (TraceTreeNode node : slowNodes) {
+ result.add(node.getSpan());
+
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Filter and process the given list of Spans
+ *
+ * @param spans The list of Spans to be processed
+ * @return The filtered and processed list of Spans
+ * <p>
+ * This method mainly performs the following operations:
+ * 1. Filters out Spans that don't need to be retained based on
NOT_RETAIN_SPAN_NAMES
+ * 2. For retained Spans, only keeps tags specified in RETAIN_TAGS
+ * 3. For each Span's Process, only keeps tags specified in
RETAIN_PROCESS_TAGS
+ * If the input spans is null or empty, it returns the original spans
directly
+ */
+ private List<Span> getSpansFilter(List<Span> spans) {
+ if (spans != null && spans.size() > 0) {
+ List<Span> newSpans = new ArrayList<>();
+ for (Span span : spans) {
+ String operationName = span.getOperationName();
+
+ boolean isRetain = true;
+ for (String filter : NOT_RETAIN_SPAN_NAMES) {
+ if (operationName.contains(filter)) {
+ isRetain = false;
+ }
+ }
+ if (isRetain) {
+ newSpans.add(span);
+ }
+ }
+ for (Span span : newSpans) {
+ List<JaegerAttribute> newTags = new ArrayList<>();
+ for (JaegerAttribute attribute : span.getTags()) {
+ if (RETAIN_TAGS.contains(attribute.getKey())) {
+ newTags.add(attribute);
+ }
+ }
+ span.setTags(newTags);
+ List<JaegerAttribute> newProcessTags = new ArrayList<>();
+ JaegerProcess process = span.getProcess();
+ List<JaegerAttribute> processTags = process.getTags();
+ for (JaegerAttribute processTag : processTags) {
+ if (RETAIN_PROCESS_TAGS.contains(processTag.getKey())) {
+ newProcessTags.add(processTag);
+ }
+ }
+ process.setTags(newProcessTags);
+ }
+ return newSpans;
+ }
+ return spans;
+ }
+
+ private boolean hasException(Span span) {
+ // Determine if the span contains any errors based on the actual
situation
+ for (JaegerAttribute tag : span.getTags()) {
+ if ("error".equals(tag.getKey())) {
+ return true;
+
+
+ }
+ }
+ return false;
+ }
+
+ private void sortChildren(TraceTreeNode node) {
+ if (node.getChildren() != null) {
+ node.getChildren().sort(Comparator.comparingLong(n ->
n.getSpan().getStartTime()));
+ for (TraceTreeNode child : node.getChildren()) {
+ sortChildren(child);
+ }
+ }
+ }
+
+ private void findSlowNode(TraceTreeNode root, List<TraceTreeNode>
slowNodes, long rootDuration) {
+ // Find nodes with duration greater than 80% of the parent node's
duration.
+ // If none found, look for 50%, then 30%, 20%, and finally 10%.
+ if (!root.getChildren().isEmpty()) {
+ for (TraceTreeNode childNode : root.getChildren()) {
+ if (findByPercent(childNode, slowNodes, rootDuration, 0.8)) {
+
+ findSlowNode(childNode, slowNodes,
childNode.getSpan().getDuration());
+ } else if (findByPercent(childNode, slowNodes, rootDuration,
0.5)) {
+ findSlowNode(childNode, slowNodes,
childNode.getSpan().getDuration());
+ } else if (findByPercent(childNode, slowNodes, rootDuration,
0.3)) {
+ findSlowNode(childNode, slowNodes,
childNode.getSpan().getDuration());
+ } else if (findByPercent(childNode, slowNodes, rootDuration,
0.2)) {
+ findSlowNode(childNode, slowNodes,
childNode.getSpan().getDuration());
+ } else if (findByPercent(childNode, slowNodes, rootDuration,
0.1)) {
+ findSlowNode(childNode, slowNodes,
childNode.getSpan().getDuration());
+ }
+ }
+ }
+ }
+
+ private boolean findByPercent(TraceTreeNode parent, List<TraceTreeNode>
slowNodes, long rootDuration, double percent) {
+ boolean result = false;
+ for (TraceTreeNode childNode : parent.getChildren()) {
+ if (childNode.getSpan().getDuration() > rootDuration * percent) {
+ result = true;
+ slowNodes.add(childNode);
+ }
+ }
+ return result;
+ }
+
+ private void findErrorTargetNode(TraceTreeNode node, List<TraceTreeNode>
errorNodes) {
+ if (hasException(node.getSpan())) {
+ errorNodes.add(node);
+ }
+
+ if (node.getChildren() != null) {
+ for (TraceTreeNode child : node.getChildren()) {
+ findErrorTargetNode(child, errorNodes);
+ }
+ }
+ }
+
+ /**
+ * Add the specified number of child nodes of the targetNode to the result.
+ * First, add the first-level child nodes; if the quantity is not
sufficient,
+ * then add the second-level child nodes. If the number of child nodes
exceeds afterNumber,
+ * or if there are no more child nodes, the method returns.
+ *
+ * @param result List to store the resulting Span objects
+ * @param targetNode
+ * @param afterNumber
+ */
+ private void addNChild(List<Span> result, TraceTreeNode targetNode, int
afterNumber, int currentChildCount) {
+ List<TraceTreeNode> children = targetNode.getChildren();
+ if (!children.isEmpty()) {
+ List<TraceTreeNode> childs = new ArrayList<>();
+ for (TraceTreeNode treeNode : children) {
+ result.add(treeNode.getSpan());
+ currentChildCount++;
+ if (currentChildCount >= afterNumber) {
+ return;
+ }
+ if (!treeNode.getChildren().isEmpty()) {
+ childs.add(treeNode);
+ }
+ }
+ // If the number of first-level child nodes is less than
afterNumber, continue adding second-level child nodes
+ for (TraceTreeNode secondChild : childs) {
+ addNChild(result, secondChild, afterNumber, currentChildCount);
+ }
+ }
+ }
+
+ private TraceIdQueryVo buildTraceIdQueryVo(TraceQueryParam param) {
+
+ TraceIdQueryVo vo = new TraceIdQueryVo();
+ vo.setTraceId(param.getTraceId());
+ long startTime = param.getTimeStamp() - QUERY_TIME_RANGE;
+ long endTime = param.getTimeStamp() + QUERY_TIME_RANGE;
+ vo.setStartTime(startTime);
+ vo.setEndTime(endTime);
+ return vo;
}
-}
+}
\ No newline at end of file
diff --git
a/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/util/CommitPoolUtil.java
b/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/util/CommitPoolUtil.java
new file mode 100644
index 00000000..ce873e96
--- /dev/null
+++
b/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/util/CommitPoolUtil.java
@@ -0,0 +1,48 @@
+/*
+ * 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.util;
+
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class CommitPoolUtil {
+
+ public static final ThreadPoolExecutor HERA_SOLUTION_METRICS_POOL;
+ private static final BlockingQueue<Runnable> heraSolutionMetricsQueue =
new ArrayBlockingQueue<>(30);
+ private static final AtomicInteger heraSolutionThreadNumber = new
AtomicInteger(1);
+
+ static {
+ HERA_SOLUTION_METRICS_POOL = new ThreadPoolExecutor(15, 20,
+ 0L, TimeUnit.MILLISECONDS,
+ heraSolutionMetricsQueue, new ThreadFactory() {
+ @Override
+ public Thread newThread(Runnable r) {
+ Thread thread = new Thread(r);
+ thread.setDaemon(false);
+ thread.setName("hera-solution-metrics" +
heraSolutionThreadNumber.getAndIncrement());
+ return thread;
+ }
+ });
+ }
+
+}
diff --git
a/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/util/HttpClient.java
b/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/util/HttpClient.java
new file mode 100644
index 00000000..f250ff1f
--- /dev/null
+++
b/ozhera-intelligence/ozhera-intelligence-service/src/main/java/org/apache/ozhera/intelligence/util/HttpClient.java
@@ -0,0 +1,92 @@
+/*
+ * 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.util;
+
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import lombok.extern.slf4j.Slf4j;
+import okhttp3.MediaType;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author dingtao
+ * @date 2025/1/20 11:26
+ */
+@Slf4j
+public class HttpClient {
+
+ private static final OkHttpClient client;
+
+ static {
+ client = new OkHttpClient.Builder()
+ .connectTimeout(10, TimeUnit.SECONDS)
+ .writeTimeout(10, TimeUnit.SECONDS)
+ .readTimeout(60, TimeUnit.SECONDS)
+ .build();
+ }
+
+ public static JsonObject postRequest(String url, JsonObject jsonObject) {
+ MediaType JSON = MediaType.parse("application/json; charset=utf-8");
+ RequestBody body = RequestBody.create(JSON, jsonObject.toString());
+ Request request = new Request.Builder()
+ .url(url)
+ .post(body)
+ .build();
+ try (Response response = client.newCall(request).execute()) {
+ if (!response.isSuccessful()) {
+ throw new IOException("Unexpected code " + response);
+ }
+ return new
JsonParser().parse(response.body().string()).getAsJsonObject();
+ } catch (Exception e) {
+ log.error("HttpClient post error, ", e);
+ return null;
+ }
+ }
+
+
+ public static String get(String url, Map<String, String> headers) {
+ Request.Builder requestBuilder = new Request.Builder().url(url);
+
+ if (headers != null) {
+ for (Map.Entry<String, String> entry : headers.entrySet()) {
+ requestBuilder.addHeader(entry.getKey(), entry.getValue());
+ }
+ }
+
+ Request request = requestBuilder.build();
+
+ try (Response response = client.newCall(request).execute()) {
+ if (!response.isSuccessful()) {
+ throw new IOException("Unexpected code " + response);
+ }
+ return response.body().string();
+ } catch (Exception e) {
+ log.error("HttpClient get error, ", e);
+ return null;
+ }
+
+ }
+}
diff --git a/ozhera-intelligence/pom.xml b/ozhera-intelligence/pom.xml
index a3cd27af..02241488 100644
--- a/ozhera-intelligence/pom.xml
+++ b/ozhera-intelligence/pom.xml
@@ -68,6 +68,21 @@
<artifactId>trace-etl-domain</artifactId>
<version>2.2.6-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.ozhera</groupId>
+ <artifactId>trace-etl-api</artifactId>
+ <version>2.2.6-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.ozhera</groupId>
+ <artifactId>log-api</artifactId>
+ <version>2.2.6-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>com.squareup.okhttp3</groupId>
+ <artifactId>okhttp</artifactId>
+ <version>4.12.0</version>
+ </dependency>
</dependencies>
</dependencyManagement>
@@ -159,7 +174,7 @@
</goals>
<configuration>
<executable>gpg</executable>
-
<keyname>C962B99B87C5B41E79940E4BE72ADFA74291C3C0</keyname>
+ <keyname>your-gpg-key</keyname>
</configuration>
</execution>
</executions>
diff --git
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/MetricsQueryParam.java
b/ozhera-log/log-api/src/main/java/org/apache/ozhera/log/api/model/dto/LogFilterOptions.java
similarity index 65%
copy from
ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/MetricsQueryParam.java
copy to
ozhera-log/log-api/src/main/java/org/apache/ozhera/log/api/model/dto/LogFilterOptions.java
index 96541b9d..d28209bf 100644
---
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/MetricsQueryParam.java
+++
b/ozhera-log/log-api/src/main/java/org/apache/ozhera/log/api/model/dto/LogFilterOptions.java
@@ -16,26 +16,28 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.ozhera.intelligence.domain.rootanalysis;
+package org.apache.ozhera.log.api.model.dto;
-import lombok.Builder;
+import lombok.AllArgsConstructor;
import lombok.Data;
+import lombok.NoArgsConstructor;
-@Data
-@Builder
-public class MetricsQueryParam {
-
- private String env;
-
- private String application;
-
- private String ip;
+import java.io.Serializable;
+/**
+ * @author wtt
+ * @version 1.0
+ * @description
+ * @date 2024/3/6 16:15
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class LogFilterOptions implements Serializable {
+ private Long projectId;
+ private Long envId;
+ private String traceId;
+ private String level;
private String startTime;
-
- private String duration;
-
- // The error margin between the start time and end time,
- // the actual query time range is [startTime - gap, endTime + gap]
- private String gap;
+ private String endTime;
}
diff --git
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TraceQueryParam.java
b/ozhera-log/log-api/src/main/java/org/apache/ozhera/log/api/model/dto/LogUrlParam.java
similarity index 70%
copy from
ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TraceQueryParam.java
copy to
ozhera-log/log-api/src/main/java/org/apache/ozhera/log/api/model/dto/LogUrlParam.java
index 18fdcdf1..157892f2 100644
---
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TraceQueryParam.java
+++
b/ozhera-log/log-api/src/main/java/org/apache/ozhera/log/api/model/dto/LogUrlParam.java
@@ -16,17 +16,25 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.ozhera.intelligence.domain.rootanalysis;
+package org.apache.ozhera.log.api.model.dto;
-import lombok.Builder;
+import lombok.AllArgsConstructor;
import lombok.Data;
+import lombok.NoArgsConstructor;
-import java.util.List;
+import java.io.Serializable;
+/**
+ * @author wtt
+ * @version 1.0
+ * @description
+ * @date 2024/3/6 16:15
+ */
@Data
-@Builder
-public class TraceQueryParam {
+@NoArgsConstructor
+@AllArgsConstructor
+public class LogUrlParam implements Serializable {
+ private Long projectId;
+ private Long envId;
private String traceId;
- private String env;
- private List<String> timeStamp;
}
diff --git
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TraceQueryParam.java
b/ozhera-log/log-api/src/main/java/org/apache/ozhera/log/api/service/HeraLogApiService.java
similarity index 65%
copy from
ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TraceQueryParam.java
copy to
ozhera-log/log-api/src/main/java/org/apache/ozhera/log/api/service/HeraLogApiService.java
index 18fdcdf1..eccbcf6a 100644
---
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TraceQueryParam.java
+++
b/ozhera-log/log-api/src/main/java/org/apache/ozhera/log/api/service/HeraLogApiService.java
@@ -16,17 +16,24 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.ozhera.intelligence.domain.rootanalysis;
+package org.apache.ozhera.log.api.service;
-import lombok.Builder;
-import lombok.Data;
+import org.apache.ozhera.log.api.model.dto.LogFilterOptions;
+import org.apache.ozhera.log.api.model.dto.LogUrlParam;
import java.util.List;
+import java.util.Map;
+
+/**
+ * @author wtt
+ * @version 1.0
+ * @description
+ * @date 2024/3/6 16:12
+ */
+public interface HeraLogApiService {
+
+ List<String> queryLogUrl(LogUrlParam logUrlParam);
+
+ List<Map<String, Object>> queryLogData(LogFilterOptions filterOptions);
-@Data
-@Builder
-public class TraceQueryParam {
- private String traceId;
- private String env;
- private List<String> timeStamp;
}
diff --git
a/ozhera-log/log-manager/src/main/java/org/apache/ozhera/log/manager/service/impl/HeraLogApiServiceImpl.java
b/ozhera-log/log-manager/src/main/java/org/apache/ozhera/log/manager/service/impl/HeraLogApiServiceImpl.java
new file mode 100644
index 00000000..a5019c7e
--- /dev/null
+++
b/ozhera-log/log-manager/src/main/java/org/apache/ozhera/log/manager/service/impl/HeraLogApiServiceImpl.java
@@ -0,0 +1,279 @@
+/*
+ * 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.log.manager.service.impl;
+
+import com.xiaomi.youpin.docean.Ioc;
+import com.xiaomi.youpin.docean.plugin.config.anno.Value;
+import com.xiaomi.youpin.docean.plugin.dubbo.anno.Service;
+import com.xiaomi.youpin.docean.plugin.es.EsService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.ozhera.log.api.enums.LogStorageTypeEnum;
+import org.apache.ozhera.log.api.model.dto.LogFilterOptions;
+import org.apache.ozhera.log.api.model.dto.LogUrlParam;
+import org.apache.ozhera.log.api.service.HeraLogApiService;
+import org.apache.ozhera.log.common.Constant;
+import org.apache.ozhera.log.manager.dao.MilogLogTailDao;
+import org.apache.ozhera.log.manager.dao.MilogLogstoreDao;
+import org.apache.ozhera.log.manager.domain.EsCluster;
+import org.apache.ozhera.log.manager.model.Pair;
+import org.apache.ozhera.log.manager.model.pojo.MilogEsClusterDO;
+import org.apache.ozhera.log.manager.model.pojo.MilogLogStoreDO;
+import org.apache.ozhera.log.manager.model.pojo.MilogLogTailDo;
+import org.elasticsearch.action.search.SearchRequest;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.common.unit.TimeValue;
+import org.elasticsearch.index.query.BoolQueryBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.search.SearchHit;
+import org.elasticsearch.search.builder.SearchSourceBuilder;
+import org.elasticsearch.search.sort.SortOrder;
+
+import javax.annotation.Resource;
+import javax.sql.DataSource;
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.time.Clock;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+import static org.apache.ozhera.log.manager.user.MoneUserDetailService.GSON;
+
+
+/**
+ * @author wtt
+ * @version 1.0
+ * @description
+ * @date 2024/3/6 16:17
+ */
+@Slf4j
+@Service(interfaceClass = HeraLogApiService.class, group = "$dubbo.group",
timeout = 10000)
+public class HeraLogApiServiceImpl implements HeraLogApiService {
+
+ private static final int QUERY_LIMIT = 20;
+ private static final String TIMESTAMP_FIELD = "timestamp";
+ private static final String LOG_TIME_FIELD = "log_time";
+ private static final String STORE_ID_FIELD = "storeId";
+ private static final String LEVEL_FIELD = "level";
+ private static final String TRACE_ID_FIELD = "traceId";
+
+ @Resource
+ private MilogLogTailDao milogLogTailDao;
+
+ @Resource
+ private MilogLogstoreDao milogLogstoreDao;
+
+ @Resource
+ private EsCluster esCluster;
+
+ @Value(value = "$hera.url")
+ private String heraUrl;
+
+ @Override
+ public List<String> queryLogUrl(LogUrlParam logUrlParam) {
+ List<String> urlList = new ArrayList<>();
+
+ List<MilogLogTailDo> logTailDos =
milogLogTailDao.queryByAppId(logUrlParam.getProjectId());
+ if (CollectionUtils.isEmpty(logTailDos)) {
+ return urlList;
+ }
+ List<MilogLogTailDo> filteredLogTailDos = logTailDos.stream()
+ .filter(tailDo -> logUrlParam.getEnvId() == null ||
tailDo.getEnvId().equals(logUrlParam.getEnvId()))
+ .toList();
+
+ long curTimestamp = Clock.systemUTC().instant().toEpochMilli();
+ long fiveMinutesInMillis = TimeUnit.MINUTES.toMillis(5);
+
+ List<Pair<Long, Long>> pairList = filteredLogTailDos.stream()
+ .map(tail -> Pair.of(tail.getSpaceId(), tail.getStoreId()))
+ .distinct()
+ .toList();
+
+ String timeParam = buildTimeParam(curTimestamp, fiveMinutesInMillis);
+
+ for (Pair<Long, Long> pair : pairList) {
+ try {
+ String commonParam = buildCommonParam(pair,
logUrlParam.getTraceId());
+
+ urlList.add(buildUrl(commonParam, timeParam));
+ } catch (Exception e) {
+ log.info("queryAccessLogList build data error,tail:{}",
GSON.toJson(pair), e);
+ }
+ }
+
+ return urlList;
+ }
+
+ @Override
+ public List<Map<String, Object>> queryLogData(LogFilterOptions
filterOptions) {
+ try {
+ List<MilogLogTailDo> milogLogTailDos =
milogLogTailDao.queryByAppAndEnv(filterOptions.getProjectId(),
filterOptions.getEnvId());
+ if (CollectionUtils.isEmpty(milogLogTailDos)) {
+ log.warn("No log tails found for projectId={}, envId={}",
filterOptions.getProjectId(), filterOptions.getEnvId());
+ return Collections.emptyList();
+ }
+
+ MilogLogTailDo milogLogTailDo =
milogLogTailDos.get(milogLogTailDos.size() - 1);
+ MilogLogStoreDO logStoreDO =
milogLogstoreDao.queryById(milogLogTailDo.getStoreId());
+ MilogEsClusterDO cluster =
esCluster.getById(logStoreDO.getEsClusterId());
+
+ LogStorageTypeEnum storageType =
LogStorageTypeEnum.queryByName(cluster.getLogStorageType());
+ if (storageType == LogStorageTypeEnum.ELASTICSEARCH) {
+ return queryFromElasticsearch(filterOptions, logStoreDO);
+ } else if (storageType == LogStorageTypeEnum.DORIS) {
+ return queryFromDoris(filterOptions, logStoreDO);
+ } else {
+ log.error("unsupported log storage type: {}", storageType);
+ return Collections.emptyList();
+ }
+ } catch (Exception e) {
+ log.error("failed to query log data", e);
+ return Collections.emptyList();
+ }
+ }
+
+ private List<Map<String, Object>> queryFromElasticsearch(LogFilterOptions
filterOptions, MilogLogStoreDO logStoreDO) throws IOException {
+ EsService esService =
esCluster.getEsService(logStoreDO.getEsClusterId());
+ SearchSourceBuilder builder = buildSearchSourceBuilder(filterOptions,
logStoreDO);
+ SearchRequest searchRequest = new
SearchRequest(logStoreDO.getEsIndex()).source(builder);
+ SearchResponse searchResponse = esService.search(searchRequest);
+ return extractLogDataFromResponse(searchResponse);
+ }
+
+ private List<Map<String, Object>> queryFromDoris(LogFilterOptions
filterOptions, MilogLogStoreDO logStoreDO) {
+ DataSource dataSource =
Ioc.ins().getBean(Constant.LOG_STORAGE_SERV_BEAN_PRE +
logStoreDO.getEsClusterId());
+ if (dataSource == null) {
+ log.error("DataSource not found for clusterId={}",
logStoreDO.getEsClusterId());
+ return Collections.emptyList();
+ }
+
+ StringBuilder sqlBuilder = new StringBuilder("SELECT * FROM " +
logStoreDO.getEsIndex() + " WHERE ")
+ .append("project_id = ? AND ")
+ .append("env_id = ? AND ")
+ .append(LOG_TIME_FIELD + " >= ? AND ")
+ .append(LOG_TIME_FIELD + " <= ?");
+
+ if (StringUtils.isNotBlank(filterOptions.getTraceId())) {
+ sqlBuilder.append(" AND " + TRACE_ID_FIELD + " = ?");
+ }
+ if (StringUtils.isNotBlank(filterOptions.getLevel())) {
+ sqlBuilder.append(" AND " + LEVEL_FIELD + " = ?");
+ }
+
+ sqlBuilder.append(" ORDER BY " + LOG_TIME_FIELD + " DESC LIMIT " +
QUERY_LIMIT);
+
+ try (Connection connection = dataSource.getConnection();
+ PreparedStatement preparedStatement =
connection.prepareStatement(sqlBuilder.toString())) {
+
+ setPreparedStatementParameters(preparedStatement, filterOptions);
+ return executeDorisQuery(preparedStatement);
+ } catch (SQLException e) {
+ throw new RuntimeException("Failed to execute Doris query", e);
+ }
+ }
+
+ private void setPreparedStatementParameters(PreparedStatement
preparedStatement, LogFilterOptions filterOptions) throws SQLException {
+ preparedStatement.setLong(1, filterOptions.getProjectId());
+ preparedStatement.setLong(2, filterOptions.getEnvId());
+ preparedStatement.setString(3, filterOptions.getStartTime());
+ preparedStatement.setString(4, filterOptions.getEndTime());
+
+ int paramIndex = 5;
+ if (StringUtils.isNotBlank(filterOptions.getTraceId())) {
+ preparedStatement.setString(paramIndex++,
filterOptions.getTraceId());
+ }
+ if (StringUtils.isNotBlank(filterOptions.getLevel())) {
+ preparedStatement.setString(paramIndex, filterOptions.getLevel());
+ }
+ }
+
+ private List<Map<String, Object>> executeDorisQuery(PreparedStatement
preparedStatement) throws SQLException {
+ List<Map<String, Object>> logs = new ArrayList<>();
+ try (ResultSet resultSet = preparedStatement.executeQuery()) {
+ java.sql.ResultSetMetaData metaData = resultSet.getMetaData();
+ int columnCount = metaData.getColumnCount();
+ while (resultSet.next()) {
+ Map<String, Object> logEntry = new HashMap<>();
+ for (int i = 1; i <= columnCount; i++) {
+ String columnName = metaData.getColumnName(i);
+ Object columnValue = resultSet.getObject(i);
+ logEntry.put(columnName, columnValue);
+ }
+ logs.add(logEntry);
+ }
+ }
+ return logs;
+ }
+
+ private SearchSourceBuilder buildSearchSourceBuilder(LogFilterOptions
filterOptions, MilogLogStoreDO logStoreDO) {
+ BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
+ .filter(QueryBuilders.rangeQuery("timestamp")
+ .from(filterOptions.getStartTime())
+ .to(filterOptions.getEndTime()))
+ .filter(QueryBuilders.termQuery("storeId",
logStoreDO.getId()));
+
+ if (StringUtils.isNotBlank(filterOptions.getLevel())) {
+ boolQueryBuilder.filter(QueryBuilders.matchPhraseQuery("level",
filterOptions.getLevel()));
+ }
+
+ if (StringUtils.isNotBlank(filterOptions.getTraceId())) {
+ boolQueryBuilder.filter(QueryBuilders.matchPhraseQuery("traceId",
filterOptions.getTraceId()));
+ }
+
+ return new SearchSourceBuilder().query(boolQueryBuilder)
+ .sort("timestamp", SortOrder.DESC)
+ .from(0)
+ .size(20)
+ .timeout(TimeValue.timeValueMinutes(2L));
+ }
+
+ private List<Map<String, Object>>
extractLogDataFromResponse(SearchResponse searchResponse) {
+ return Arrays.stream(searchResponse.getHits().getHits())
+ .map(SearchHit::getSourceAsMap)
+ .collect(Collectors.toList());
+ }
+
+ private String buildCommonParam(Pair<Long, Long> pair, String keyword) {
+ if (StringUtils.isEmpty(keyword)) {
+ return String.format("spaceId=%s&storeId=%s&type=search",
+ pair.getKey(), pair.getValue());
+ }
+ return String.format("spaceId=%s&storeId=%s&type=search&inputV=%s",
+ pair.getKey(), pair.getValue(), keyword);
+ }
+
+ private String buildTimeParam(long curTimestamp, long fiveMinutesInMillis)
{
+ long startTime = curTimestamp - fiveMinutesInMillis;
+ long endTime = curTimestamp + fiveMinutesInMillis;
+ return String.format("&startTime=%s&endTime=%s", startTime, endTime);
+ }
+
+ private String buildUrl(String commonParam, String timeParam) {
+ return new StringBuilder(heraUrl)
+ .append("/project-milog/user/space-tree?")
+ .append(commonParam)
+ .append(timeParam)
+ .toString();
+ }
+}
diff --git a/.asf.yaml
b/ozhera-operator/ozhera-operator-server/src/main/resources/ozhera_init/intelligence/ozhera_intelligence.yml
similarity index 56%
copy from .asf.yaml
copy to
ozhera-operator/ozhera-operator-server/src/main/resources/ozhera_init/intelligence/ozhera_intelligence.yml
index f4ea13b7..90cb38a6 100644
--- a/.asf.yaml
+++
b/ozhera-operator/ozhera-operator-server/src/main/resources/ozhera_init/intelligence/ozhera_intelligence.yml
@@ -1,4 +1,3 @@
-#
# 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.
@@ -13,10 +12,30 @@
# 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.
-#
-
-github:
- description: Apache OzHera is an About Application Observable Platform in
the Cloud Native Era.
- homepage: https://ozhera.apache.org/
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: ozhera-intelligence
+ namespace: ozhera-namespace
labels:
- - apm
+ app: ozhera-intelligence
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: ozhera-intelligence
+ template:
+ metadata:
+ labels:
+ app: ozhera-intelligence
+ spec:
+ containers:
+ - name: ozhera-intelligence-container
+ image:
herahub/opensource-pub:ozhera-intelligence-2.2.5-incubating-beta-v1
+ imagePullPolicy: Always
+ ports:
+ - containerPort: 4446
+ resources:
+ limits:
+ cpu: '500m'
+ memory: 1Gi
diff --git
a/ozhera-intelligence/ozhera-intelligence-server/src/main/resources/application.properties
b/ozhera-operator/ozhera-operator-server/src/main/resources/ozhera_init/nacos/config/hera_intelligence_config_#_DEFAULT_GROUP.properties
similarity index 87%
copy from
ozhera-intelligence/ozhera-intelligence-server/src/main/resources/application.properties
copy to
ozhera-operator/ozhera-operator-server/src/main/resources/ozhera_init/nacos/config/hera_intelligence_config_#_DEFAULT_GROUP.properties
index a38e97e5..5bf79dad 100644
---
a/ozhera-intelligence/ozhera-intelligence-server/src/main/resources/application.properties
+++
b/ozhera-operator/ozhera-operator-server/src/main/resources/ozhera_init/nacos/config/hera_intelligence_config_#_DEFAULT_GROUP.properties
@@ -12,10 +12,6 @@
# 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.
-
-#server
-app.name=${app.name}
-server.type=${server.type}
-server.port=${server.port}
-
-log.path=${log.path}
\ No newline at end of file
+analyze.token=
+dubbo.registry.address=nacos://${hera.nacos.address}
+prometheus.api.url=${hera.prometheus.url}
diff --git a/ozhera-webhook/ozhera-webhook-server/Dockerfile
b/ozhera-webhook/ozhera-webhook-server/Dockerfile
index a25974d8..31b147f1 100644
--- a/ozhera-webhook/ozhera-webhook-server/Dockerfile
+++ b/ozhera-webhook/ozhera-webhook-server/Dockerfile
@@ -20,4 +20,4 @@ COPY ${SRC_PATH}/ozhera-webhook-server-${APP_VERSION}.jar
/home/work/hera-webhoo
COPY ${SRC_PATH}/lib /home/work/lib/
-ENTRYPOINT
["java","-Duser.timezone=Asia/Shanghai","-cp","/home/work/hera-webhook-server.jar:/home/work/lib/*","org.apache.ozhera.webhook.Bootstrap","&&","tail","-f","/dev/null"]
+ENTRYPOINT
["java","-Duser.timezone=Asia/Shanghai","-cp","/home/work/hera-webhook-server.jar:/home/work/lib/*","org.apache.ozhera.webhook.Bootstrap","&&","tail","-f","/dev/null"]
\ No newline at end of file
diff --git a/ozhera-webhook/pom.xml b/ozhera-webhook/pom.xml
index 536e46a3..0f8ca831 100644
--- a/ozhera-webhook/pom.xml
+++ b/ozhera-webhook/pom.xml
@@ -68,12 +68,6 @@
<version>1.0.10-mone</version>
</dependency>
- <!--<dependency>
- <groupId>org.yaml</groupId>
- <artifactId>snakeyaml</artifactId>
- <version>1.30</version>
- </dependency>-->
-
</dependencies>
</dependencyManagement>
diff --git a/readme/images/ozhera-intelligence.png
b/readme/images/ozhera-intelligence.png
new file mode 100644
index 00000000..79d9020c
Binary files /dev/null and b/readme/images/ozhera-intelligence.png differ
diff --git
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TraceQueryParam.java
b/trace-etl/trace-etl-api/src/main/java/org/apache/ozhera/trace/etl/api/service/TraceQueryService.java
similarity index 66%
copy from
ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TraceQueryParam.java
copy to
trace-etl/trace-etl-api/src/main/java/org/apache/ozhera/trace/etl/api/service/TraceQueryService.java
index 18fdcdf1..d657d5d7 100644
---
a/ozhera-intelligence/ozhera-intelligence-domain/src/main/java/org/apache/ozhera/intelligence/domain/rootanalysis/TraceQueryParam.java
+++
b/trace-etl/trace-etl-api/src/main/java/org/apache/ozhera/trace/etl/api/service/TraceQueryService.java
@@ -16,17 +16,21 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.ozhera.intelligence.domain.rootanalysis;
+package org.apache.ozhera.trace.etl.api.service;
-import lombok.Builder;
-import lombok.Data;
+import org.apache.ozhera.trace.etl.domain.tracequery.Trace;
+import org.apache.ozhera.trace.etl.domain.tracequery.TraceIdQueryVo;
+import org.apache.ozhera.trace.etl.domain.tracequery.TraceListQueryVo;
import java.util.List;
-@Data
-@Builder
-public class TraceQueryParam {
- private String traceId;
- private String env;
- private List<String> timeStamp;
+/**
+ * @author dingtao
+ * @date 2025/1/20 11:26
+ */
+public interface TraceQueryService {
+
+ List<Trace> getList(TraceListQueryVo vo);
+
+ Trace getByTraceId(TraceIdQueryVo vo);
}
diff --git a/trace-etl/trace-etl-manager/Dockerfile
b/trace-etl/trace-etl-manager/Dockerfile
index 240358f6..180e1cd8 100644
--- a/trace-etl/trace-etl-manager/Dockerfile
+++ b/trace-etl/trace-etl-manager/Dockerfile
@@ -22,4 +22,4 @@ COPY ${SRC_PATH}/trace-etl-manager-${APP_VERSION}.jar
/home/work/trace-etl-manag
COPY ${SRC_PATH}/lib /home/work/lib/
-ENTRYPOINT ["java", "-XX:+UseZGC",
"--add-opens=java.base/java.lang=ALL-UNNAMED",
"--add-opens=java.base/java.util=ALL-UNNAMED",
"--add-opens=java.base/java.math=ALL-UNNAMED",
"--add-opens=java.base/sun.reflect=ALL-UNNAMED",
"--add-opens=java.base/java.xml=ALL-UNNAMED",
"--add-exports=java.base/sun.reflect.annotation=ALL-UNNAMED",
"--add-opens=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED",
"--add-exports=java.xml/com.sun.org.apache.xerces.internal.impl.dv.util=ALL-UNNAMED",
"- [...]
+ENTRYPOINT ["java", "-XX:+UseZGC",
"--add-opens=java.base/java.lang=ALL-UNNAMED",
"--add-opens=java.base/java.util=ALL-UNNAMED",
"--add-opens=java.base/java.math=ALL-UNNAMED",
"--add-opens=java.base/sun.reflect=ALL-UNNAMED",
"--add-opens=java.base/java.xml=ALL-UNNAMED",
"--add-exports=java.base/sun.reflect.annotation=ALL-UNNAMED",
"--add-opens=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED",
"--add-exports=java.xml/com.sun.org.apache.xerces.internal.impl.dv.util=ALL-UNNAMED",
"- [...]
\ No newline at end of file
diff --git
a/trace-etl/trace-etl-manager/src/main/java/org/apache/ozhera/trace/etl/manager/dubbo/TraceQueryServiceImpl.java
b/trace-etl/trace-etl-manager/src/main/java/org/apache/ozhera/trace/etl/manager/dubbo/TraceQueryServiceImpl.java
new file mode 100644
index 00000000..bc8bc30c
--- /dev/null
+++
b/trace-etl/trace-etl-manager/src/main/java/org/apache/ozhera/trace/etl/manager/dubbo/TraceQueryServiceImpl.java
@@ -0,0 +1,61 @@
+/*
+ * 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.trace.etl.manager.dubbo;
+
+import org.apache.dubbo.config.annotation.Service;
+import org.apache.ozhera.trace.etl.api.service.DataSourceService;
+import org.apache.ozhera.trace.etl.api.service.TraceQueryService;
+import org.apache.ozhera.trace.etl.domain.tracequery.Trace;
+import org.apache.ozhera.trace.etl.domain.tracequery.TraceIdQueryVo;
+import org.apache.ozhera.trace.etl.domain.tracequery.TraceListQueryVo;
+import org.apache.ozhera.trace.etl.domain.tracequery.TraceQueryResult;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.util.List;
+
+/**
+ * @author dingtao
+ * @date 2025/1/20 11:26
+ */
+@Service(interfaceClass = TraceQueryService.class, group = "${dubbo.group}",
version = "1.0")
+public class TraceQueryServiceImpl implements TraceQueryService {
+
+ @Autowired
+ private DataSourceService dataSourceService;
+
+ @Override
+ public List<Trace> getList(TraceListQueryVo vo) {
+ TraceQueryResult<List<Trace>> result = dataSourceService.getList(vo);
+ if (result != null) {
+ return result.getData();
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public Trace getByTraceId(TraceIdQueryVo vo) {
+ TraceQueryResult<List<Trace>> result =
dataSourceService.getByTraceId(vo);
+ if (result != null) {
+ return result.getData().getFirst();
+ } else {
+ return null;
+ }
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]