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

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


The following commit(s) were added to refs/heads/master by this push:
     new 2ea341b  Add missed profiled segment query (#4413)
2ea341b is described below

commit 2ea341b890b3c89bc6420e1a59be2b4aa0c8ec75
Author: mrproliu <741550...@qq.com>
AuthorDate: Tue Feb 25 10:12:16 2020 +0800

    Add missed profiled segment query (#4413)
    
    * add profiled segment query
    
    * fix query field error
---
 .../server/core/query/ProfileTaskQueryService.java | 127 +++++++++++++++++++++
 .../server/core/query/entity/ProfiledSegment.java  |  37 ++++++
 .../oap/server/core/query/entity/ProfiledSpan.java |  49 ++++++++
 .../profile/IProfileThreadSnapshotQueryDAO.java    |   6 +
 .../core/profile/analyze/ProfileStackAnalyze.java  |   6 +
 .../oap/query/graphql/resolver/ProfileQuery.java   |   5 +
 .../src/main/resources/query-protocol              |   2 +-
 .../query/ProfileThreadSnapshotQueryEsDAO.java     |  31 +++++
 .../influxdb/query/ProfileThreadSnapshotQuery.java |  42 +++++++
 .../h2/dao/H2ProfileThreadSnapshotQueryDAO.java    |  32 ++++++
 .../skywalking/e2e/profile/ProfileClient.java      |  21 ++++
 .../e2e/profile/query/ProfiledSegment.java         |  36 ++++++
 .../e2e/profile/query/ProfiledSegmentMatcher.java  |  45 ++++++++
 .../skywalking/e2e/profile/query/ProfiledSpan.java |  40 +++++++
 .../e2e/profile/query/ProfiledSpanMatcher.java     |  43 +++++++
 ...2e.ProfileVerificationITCase.profileSegment.yml |  47 ++++++++
 .../src/main/resources/getProfiledSegment.gql      |  28 +++++
 .../skywalking/e2e/ProfileVerificationITCase.java  |  11 ++
 18 files changed, 607 insertions(+), 1 deletion(-)

diff --git 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/ProfileTaskQueryService.java
 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/ProfileTaskQueryService.java
index 72012cc..7d02ef9 100644
--- 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/ProfileTaskQueryService.java
+++ 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/ProfileTaskQueryService.java
@@ -20,18 +20,31 @@ package org.apache.skywalking.oap.server.core.query;
 
 import com.google.common.base.Objects;
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.stream.Collectors;
+
+import org.apache.skywalking.apm.network.language.agent.v2.SegmentObject;
+import org.apache.skywalking.oap.server.core.Const;
 import org.apache.skywalking.oap.server.core.CoreModule;
 import org.apache.skywalking.oap.server.core.CoreModuleConfig;
+import 
org.apache.skywalking.oap.server.core.analysis.manual.segment.SegmentRecord;
+import org.apache.skywalking.oap.server.core.cache.EndpointInventoryCache;
+import 
org.apache.skywalking.oap.server.core.cache.NetworkAddressInventoryCache;
 import 
org.apache.skywalking.oap.server.core.cache.ServiceInstanceInventoryCache;
 import org.apache.skywalking.oap.server.core.cache.ServiceInventoryCache;
+import 
org.apache.skywalking.oap.server.core.config.IComponentLibraryCatalogService;
 import org.apache.skywalking.oap.server.core.profile.analyze.ProfileAnalyzer;
 import org.apache.skywalking.oap.server.core.query.entity.BasicTrace;
+import org.apache.skywalking.oap.server.core.query.entity.KeyValue;
+import org.apache.skywalking.oap.server.core.query.entity.LogEntity;
 import org.apache.skywalking.oap.server.core.query.entity.ProfileAnalyzation;
 import org.apache.skywalking.oap.server.core.query.entity.ProfileTask;
 import org.apache.skywalking.oap.server.core.query.entity.ProfileTaskLog;
+import org.apache.skywalking.oap.server.core.query.entity.ProfiledSegment;
+import org.apache.skywalking.oap.server.core.query.entity.ProfiledSpan;
+import org.apache.skywalking.oap.server.core.register.EndpointInventory;
 import org.apache.skywalking.oap.server.core.register.ServiceInstanceInventory;
 import org.apache.skywalking.oap.server.core.register.ServiceInventory;
 import org.apache.skywalking.oap.server.core.storage.StorageModule;
@@ -43,6 +56,7 @@ import 
org.apache.skywalking.oap.server.library.module.Service;
 import org.apache.skywalking.oap.server.library.util.CollectionUtils;
 
 import static java.util.Objects.isNull;
+import static java.util.Objects.nonNull;
 
 /**
  * handle profile task queries
@@ -54,6 +68,9 @@ public class ProfileTaskQueryService implements Service {
     private IProfileThreadSnapshotQueryDAO profileThreadSnapshotQueryDAO;
     private ServiceInventoryCache serviceInventoryCache;
     private ServiceInstanceInventoryCache serviceInstanceInventoryCache;
+    private NetworkAddressInventoryCache networkAddressInventoryCache;
+    private IComponentLibraryCatalogService componentLibraryCatalogService;
+    private EndpointInventoryCache endpointInventoryCache;
 
     private final ProfileAnalyzer profileAnalyzer;
 
@@ -107,6 +124,33 @@ public class ProfileTaskQueryService implements Service {
         return profileThreadSnapshotQueryDAO;
     }
 
+    private NetworkAddressInventoryCache getNetworkAddressInventoryCache() {
+        if (networkAddressInventoryCache == null) {
+            this.networkAddressInventoryCache = 
moduleManager.find(CoreModule.NAME)
+                                                             .provider()
+                                                             
.getService(NetworkAddressInventoryCache.class);
+        }
+        return networkAddressInventoryCache;
+    }
+
+    private IComponentLibraryCatalogService 
getComponentLibraryCatalogService() {
+        if (componentLibraryCatalogService == null) {
+            this.componentLibraryCatalogService = 
moduleManager.find(CoreModule.NAME)
+                                                               .provider()
+                                                               
.getService(IComponentLibraryCatalogService.class);
+        }
+        return componentLibraryCatalogService;
+    }
+
+    private EndpointInventoryCache getEndpointInventoryCache() {
+        if (endpointInventoryCache == null) {
+            this.endpointInventoryCache = moduleManager.find(CoreModule.NAME)
+                                                       .provider()
+                                                       
.getService(EndpointInventoryCache.class);
+        }
+        return endpointInventoryCache;
+    }
+
     /**
      * search profile task list
      *
@@ -158,4 +202,87 @@ public class ProfileTaskQueryService implements Service {
         return profileAnalyzer.analyze(segmentId, start, end);
     }
 
+    public ProfiledSegment getProfiledSegment(String segmentId) throws 
IOException {
+        SegmentRecord segmentRecord = 
getProfileThreadSnapshotQueryDAO().getProfiledSegment(segmentId);
+        if (segmentRecord == null) {
+            return null;
+        }
+
+        ProfiledSegment profiledSegment = new ProfiledSegment();
+        SegmentObject segmentObject = 
SegmentObject.parseFrom(segmentRecord.getDataBinary());
+        
profiledSegment.getSpans().addAll(buildProfiledSpanList(segmentObject));
+
+        return profiledSegment;
+    }
+
+    private List<ProfiledSpan> buildProfiledSpanList(SegmentObject 
segmentObject) {
+        List<ProfiledSpan> spans = new ArrayList<>();
+
+        segmentObject.getSpansList().forEach(spanObject -> {
+            ProfiledSpan span = new ProfiledSpan();
+            span.setSpanId(spanObject.getSpanId());
+            span.setParentSpanId(spanObject.getParentSpanId());
+            span.setStartTime(spanObject.getStartTime());
+            span.setEndTime(spanObject.getEndTime());
+            span.setError(spanObject.getIsError());
+            span.setLayer(spanObject.getSpanLayer().name());
+            span.setType(spanObject.getSpanType().name());
+
+            if (spanObject.getPeerId() == 0) {
+                span.setPeer(spanObject.getPeer());
+            } else {
+                
span.setPeer(getNetworkAddressInventoryCache().get(spanObject.getPeerId()).getName());
+            }
+
+            String endpointName = spanObject.getOperationName();
+            if (spanObject.getOperationNameId() != 0) {
+                EndpointInventory endpointInventory = 
getEndpointInventoryCache().get(spanObject.getOperationNameId());
+                if (nonNull(endpointInventory)) {
+                    endpointName = endpointInventory.getName();
+                } else {
+                    endpointName = Const.EMPTY_STRING;
+                }
+            }
+            span.setEndpointName(endpointName);
+
+            final ServiceInventory serviceInventory = 
getServiceInventoryCache().get(segmentObject.getServiceId());
+            if (serviceInventory != null) {
+                span.setServiceCode(serviceInventory.getName());
+            } else {
+                span.setServiceCode("unknown");
+            }
+
+            if (spanObject.getComponentId() == 0) {
+                span.setComponent(spanObject.getComponent());
+            } else {
+                
span.setComponent(getComponentLibraryCatalogService().getComponentName(spanObject.getComponentId()));
+            }
+
+            spanObject.getTagsList().forEach(tag -> {
+                KeyValue keyValue = new KeyValue();
+                keyValue.setKey(tag.getKey());
+                keyValue.setValue(tag.getValue());
+                span.getTags().add(keyValue);
+            });
+
+            spanObject.getLogsList().forEach(log -> {
+                LogEntity logEntity = new LogEntity();
+                logEntity.setTime(log.getTime());
+
+                log.getDataList().forEach(data -> {
+                    KeyValue keyValue = new KeyValue();
+                    keyValue.setKey(data.getKey());
+                    keyValue.setValue(data.getValue());
+                    logEntity.getData().add(keyValue);
+                });
+
+                span.getLogs().add(logEntity);
+            });
+
+            spans.add(span);
+        });
+
+        return spans;
+    }
+
 }
diff --git 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/entity/ProfiledSegment.java
 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/entity/ProfiledSegment.java
new file mode 100644
index 0000000..271dcdc
--- /dev/null
+++ 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/entity/ProfiledSegment.java
@@ -0,0 +1,37 @@
+/*
+ * 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.skywalking.oap.server.core.query.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Getter
+@Setter
+public class ProfiledSegment {
+
+    private final List<ProfiledSpan> spans;
+
+    public ProfiledSegment() {
+        this.spans = new ArrayList<>();
+    }
+
+}
diff --git 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/entity/ProfiledSpan.java
 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/entity/ProfiledSpan.java
new file mode 100644
index 0000000..4e7f521
--- /dev/null
+++ 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/entity/ProfiledSpan.java
@@ -0,0 +1,49 @@
+/*
+ * 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.skywalking.oap.server.core.query.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Getter
+@Setter
+public class ProfiledSpan {
+
+    private int spanId;
+    private int parentSpanId;
+    private String serviceCode;
+    private long startTime;
+    private long endTime;
+    private String endpointName;
+    private String type;
+    private String peer;
+    private String component;
+    private boolean isError;
+    private String layer;
+    private final List<KeyValue> tags;
+    private final List<LogEntity> logs;
+
+    public ProfiledSpan() {
+        this.tags = new ArrayList<>();
+        this.logs = new ArrayList<>();
+    }
+}
diff --git 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/profile/IProfileThreadSnapshotQueryDAO.java
 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/profile/IProfileThreadSnapshotQueryDAO.java
index dedda80..907a418 100644
--- 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/profile/IProfileThreadSnapshotQueryDAO.java
+++ 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/profile/IProfileThreadSnapshotQueryDAO.java
@@ -20,6 +20,8 @@ package org.apache.skywalking.oap.server.core.storage.profile;
 
 import java.io.IOException;
 import java.util.List;
+
+import 
org.apache.skywalking.oap.server.core.analysis.manual.segment.SegmentRecord;
 import 
org.apache.skywalking.oap.server.core.profile.ProfileThreadSnapshotRecord;
 import org.apache.skywalking.oap.server.core.query.entity.BasicTrace;
 import org.apache.skywalking.oap.server.core.storage.DAO;
@@ -56,4 +58,8 @@ public interface IProfileThreadSnapshotQueryDAO extends DAO {
      */
     List<ProfileThreadSnapshotRecord> queryRecords(String segmentId, int 
minSequence, int maxSequence) throws IOException;
 
+    /**
+     * search segment data
+     */
+    SegmentRecord getProfiledSegment(String segmentId) throws IOException;
 }
diff --git 
a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/profile/analyze/ProfileStackAnalyze.java
 
b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/profile/analyze/ProfileStackAnalyze.java
index 82ecf2b..7ceddb3 100644
--- 
a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/profile/analyze/ProfileStackAnalyze.java
+++ 
b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/profile/analyze/ProfileStackAnalyze.java
@@ -23,6 +23,7 @@ import java.util.List;
 import java.util.stream.Collectors;
 
 import lombok.Data;
+import 
org.apache.skywalking.oap.server.core.analysis.manual.segment.SegmentRecord;
 import 
org.apache.skywalking.oap.server.core.profile.ProfileThreadSnapshotRecord;
 import org.apache.skywalking.oap.server.core.query.entity.BasicTrace;
 import org.apache.skywalking.oap.server.core.query.entity.ProfileStackTree;
@@ -86,6 +87,11 @@ public class ProfileStackAnalyze {
                     .collect(Collectors.toList());
         }
 
+        @Override
+        public SegmentRecord getProfiledSegment(String segmentId) throws 
IOException {
+            return null;
+        }
+
     }
 
 }
diff --git 
a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/ProfileQuery.java
 
b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/ProfileQuery.java
index 750f33d..0f2dff9 100644
--- 
a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/ProfileQuery.java
+++ 
b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/ProfileQuery.java
@@ -24,6 +24,7 @@ import 
org.apache.skywalking.oap.server.core.query.ProfileTaskQueryService;
 import org.apache.skywalking.oap.server.core.query.entity.BasicTrace;
 import org.apache.skywalking.oap.server.core.query.entity.ProfileAnalyzation;
 import org.apache.skywalking.oap.server.core.query.entity.ProfileTask;
+import org.apache.skywalking.oap.server.core.query.entity.ProfiledSegment;
 import org.apache.skywalking.oap.server.library.module.ModuleManager;
 
 import java.io.IOException;
@@ -58,6 +59,10 @@ public class ProfileQuery implements GraphQLQueryResolver {
         return getProfileTaskQueryService().getTaskTraces(taskID);
     }
 
+    public ProfiledSegment getProfiledSegment(final String segmentId) throws 
IOException {
+        return getProfileTaskQueryService().getProfiledSegment(segmentId);
+    }
+
     public ProfileAnalyzation getProfileAnalyze(final String segmentId, final 
long start,
         final long end) throws IOException {
         return getProfileTaskQueryService().getProfileAnalyze(segmentId, 
start, end);
diff --git 
a/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol
 
b/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol
index 1018b79..6b26dda 160000
--- 
a/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol
+++ 
b/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol
@@ -1 +1 @@
-Subproject commit 1018b795021e0d96e6c131c8695fb9ddc9d66916
+Subproject commit 6b26ddad2099b8782b2e298fd0df02dfd1d6609f
diff --git 
a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/ProfileThreadSnapshotQueryEsDAO.java
 
b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/ProfileThreadSnapshotQueryEsDAO.java
index fc35250..ce17d57 100644
--- 
a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/ProfileThreadSnapshotQueryEsDAO.java
+++ 
b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/ProfileThreadSnapshotQueryEsDAO.java
@@ -18,6 +18,7 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query;
 
+import com.google.common.base.Strings;
 import 
org.apache.skywalking.oap.server.core.analysis.manual.segment.SegmentRecord;
 import 
org.apache.skywalking.oap.server.core.profile.ProfileThreadSnapshotRecord;
 import org.apache.skywalking.oap.server.core.query.entity.BasicTrace;
@@ -39,6 +40,7 @@ import org.elasticsearch.search.sort.SortOrder;
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Base64;
 import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
@@ -146,6 +148,35 @@ public class ProfileThreadSnapshotQueryEsDAO extends EsDAO 
implements IProfileTh
         return result;
     }
 
+    @Override
+    public SegmentRecord getProfiledSegment(String segmentId) throws 
IOException {
+        SearchSourceBuilder sourceBuilder = SearchSourceBuilder.searchSource();
+        sourceBuilder.query(QueryBuilders.termQuery(SegmentRecord.SEGMENT_ID, 
segmentId));
+        sourceBuilder.size(1);
+
+        SearchResponse response = getClient().search(SegmentRecord.INDEX_NAME, 
sourceBuilder);
+
+        if (response.getHits().getHits().length == 0) {
+            return null;
+        }
+        SearchHit searchHit = response.getHits().getHits()[0];
+        SegmentRecord segmentRecord = new SegmentRecord();
+        segmentRecord.setSegmentId((String) 
searchHit.getSourceAsMap().get(SegmentRecord.SEGMENT_ID));
+        segmentRecord.setTraceId((String) 
searchHit.getSourceAsMap().get(SegmentRecord.TRACE_ID));
+        segmentRecord.setServiceId(((Number) 
searchHit.getSourceAsMap().get(SegmentRecord.SERVICE_ID)).intValue());
+        segmentRecord.setEndpointName((String) 
searchHit.getSourceAsMap().get(SegmentRecord.ENDPOINT_NAME));
+        segmentRecord.setStartTime(((Number) 
searchHit.getSourceAsMap().get(SegmentRecord.START_TIME)).longValue());
+        segmentRecord.setEndTime(((Number) 
searchHit.getSourceAsMap().get(SegmentRecord.END_TIME)).longValue());
+        segmentRecord.setLatency(((Number) 
searchHit.getSourceAsMap().get(SegmentRecord.LATENCY)).intValue());
+        segmentRecord.setIsError(((Number) 
searchHit.getSourceAsMap().get(SegmentRecord.IS_ERROR)).intValue());
+        String dataBinaryBase64 = (String) 
searchHit.getSourceAsMap().get(SegmentRecord.DATA_BINARY);
+        if (!Strings.isNullOrEmpty(dataBinaryBase64)) {
+            
segmentRecord.setDataBinary(Base64.getDecoder().decode(dataBinaryBase64));
+        }
+        segmentRecord.setVersion(((Number) 
searchHit.getSourceAsMap().get(SegmentRecord.VERSION)).intValue());
+        return segmentRecord;
+    }
+
     protected int querySequenceWithAgg(AbstractAggregationBuilder 
aggregationBuilder, String segmentId, long start, long end) throws IOException {
         SearchSourceBuilder sourceBuilder = SearchSourceBuilder.searchSource();
 
diff --git 
a/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/query/ProfileThreadSnapshotQuery.java
 
b/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/query/ProfileThreadSnapshotQuery.java
index 753ef58..83bd9a4 100644
--- 
a/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/query/ProfileThreadSnapshotQuery.java
+++ 
b/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/query/ProfileThreadSnapshotQuery.java
@@ -33,6 +33,7 @@ import 
org.apache.skywalking.oap.server.core.query.entity.BasicTrace;
 import 
org.apache.skywalking.oap.server.core.storage.profile.IProfileThreadSnapshotQueryDAO;
 import org.apache.skywalking.oap.server.library.util.BooleanUtils;
 import org.apache.skywalking.oap.server.storage.plugin.influxdb.InfluxClient;
+import org.elasticsearch.common.Strings;
 import org.influxdb.dto.QueryResult;
 import org.influxdb.querybuilder.WhereQueryImpl;
 
@@ -148,6 +149,47 @@ public class ProfileThreadSnapshotQuery implements 
IProfileThreadSnapshotQueryDA
         return result;
     }
 
+    @Override
+    public SegmentRecord getProfiledSegment(String segmentId) throws 
IOException {
+        WhereQueryImpl query = select().column(SegmentRecord.SEGMENT_ID)
+                .column(SegmentRecord.TRACE_ID)
+                .column(SegmentRecord.SERVICE_ID)
+                .column(SegmentRecord.ENDPOINT_NAME)
+                .column(SegmentRecord.START_TIME)
+                .column(SegmentRecord.END_TIME)
+                .column(SegmentRecord.LATENCY)
+                .column(SegmentRecord.IS_ERROR)
+                .column(SegmentRecord.DATA_BINARY)
+                .column(SegmentRecord.VERSION)
+                .from(client.getDatabase(), SegmentRecord.INDEX_NAME)
+                .where()
+                .and(eq(SegmentRecord.SEGMENT_ID, segmentId));
+        List<QueryResult.Series> series = client.queryForSeries(query);
+        if (series == null || series.isEmpty()) {
+            return null;
+        }
+
+        List<Object> values = series.get(0).getValues().get(0);
+        SegmentRecord segmentRecord = new SegmentRecord();
+
+        segmentRecord.setSegmentId((String) values.get(1));
+        segmentRecord.setTraceId((String) values.get(2));
+        segmentRecord.setServiceId((int) values.get(3));
+        segmentRecord.setEndpointName((String) values.get(4));
+        segmentRecord.setStartTime((long) values.get(5));
+        segmentRecord.setEndTime((long) values.get(6));
+        segmentRecord.setLatency((int) values.get(7));
+        segmentRecord.setIsError((int) values.get(8));
+        segmentRecord.setVersion((int) values.get(10));
+
+        String base64 = (String) values.get(9);
+        if (!Strings.isNullOrEmpty(base64)) {
+            segmentRecord.setDataBinary(Base64.getDecoder().decode(base64));
+        }
+
+        return segmentRecord;
+    }
+
     private int querySequenceWithAgg(String function, String segmentId, long 
start, long end) throws IOException {
         WhereQueryImpl query = select()
             .function(function, ProfileThreadSnapshotRecord.SEQUENCE)
diff --git 
a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2ProfileThreadSnapshotQueryDAO.java
 
b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2ProfileThreadSnapshotQueryDAO.java
index 53ceb93..58214e4 100644
--- 
a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2ProfileThreadSnapshotQueryDAO.java
+++ 
b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2ProfileThreadSnapshotQueryDAO.java
@@ -27,6 +27,8 @@ import java.util.Base64;
 import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
+
+import com.google.common.base.Strings;
 import org.apache.skywalking.apm.util.StringUtil;
 import 
org.apache.skywalking.oap.server.core.analysis.manual.segment.SegmentRecord;
 import 
org.apache.skywalking.oap.server.core.profile.ProfileThreadSnapshotRecord;
@@ -155,6 +157,36 @@ public class H2ProfileThreadSnapshotQueryDAO implements 
IProfileThreadSnapshotQu
         return result;
     }
 
+    @Override
+    public SegmentRecord getProfiledSegment(String segmentId) throws 
IOException {
+        try (Connection connection = h2Client.getConnection()) {
+
+            try (ResultSet resultSet = h2Client.executeQuery(connection, 
"select * from " + SegmentRecord.INDEX_NAME + " where " + 
SegmentRecord.SEGMENT_ID + " = ?", segmentId)) {
+                if (resultSet.next()) {
+                    SegmentRecord segmentRecord = new SegmentRecord();
+                    
segmentRecord.setSegmentId(resultSet.getString(SegmentRecord.SEGMENT_ID));
+                    
segmentRecord.setTraceId(resultSet.getString(SegmentRecord.TRACE_ID));
+                    
segmentRecord.setServiceId(resultSet.getInt(SegmentRecord.SERVICE_ID));
+                    
segmentRecord.setEndpointName(resultSet.getString(SegmentRecord.ENDPOINT_NAME));
+                    
segmentRecord.setStartTime(resultSet.getLong(SegmentRecord.START_TIME));
+                    
segmentRecord.setEndTime(resultSet.getLong(SegmentRecord.END_TIME));
+                    
segmentRecord.setLatency(resultSet.getInt(SegmentRecord.LATENCY));
+                    
segmentRecord.setIsError(resultSet.getInt(SegmentRecord.IS_ERROR));
+                    String dataBinaryBase64 = 
resultSet.getString(SegmentRecord.DATA_BINARY);
+                    if (!Strings.isNullOrEmpty(dataBinaryBase64)) {
+                        
segmentRecord.setDataBinary(Base64.getDecoder().decode(dataBinaryBase64));
+                    }
+                    
segmentRecord.setVersion(resultSet.getInt(SegmentRecord.VERSION));
+                    return segmentRecord;
+                }
+            }
+        } catch (SQLException e) {
+            throw new IOException(e);
+        }
+
+        return null;
+    }
+
     private int querySequenceWithAgg(String aggType, String segmentId, long 
start, long end) throws IOException {
         StringBuilder sql = new StringBuilder();
         sql.append("select 
").append(aggType).append("(").append(ProfileThreadSnapshotRecord.SEQUENCE).append(")
 from ").append(ProfileThreadSnapshotRecord.INDEX_NAME).append(" where ");
diff --git 
a/test/e2e/e2e-profile/e2e-profile-test-runner/src/main/java/org/apache/skywalking/e2e/profile/ProfileClient.java
 
b/test/e2e/e2e-profile/e2e-profile-test-runner/src/main/java/org/apache/skywalking/e2e/profile/ProfileClient.java
index 29261fe..ce9843e 100644
--- 
a/test/e2e/e2e-profile/e2e-profile-test-runner/src/main/java/org/apache/skywalking/e2e/profile/ProfileClient.java
+++ 
b/test/e2e/e2e-profile/e2e-profile-test-runner/src/main/java/org/apache/skywalking/e2e/profile/ProfileClient.java
@@ -121,6 +121,26 @@ public class ProfileClient extends SimpleQueryClient {
         return 
Objects.requireNonNull(responseEntity.getBody()).getData().getTraces();
     }
 
+    public ProfiledSegment.ProfiledSegmentData getProfiledSegment(final String 
segmentId) throws IOException {
+        final URL queryFileUrl = 
Resources.getResource("getProfiledSegment.gql");
+        final String queryString = Resources.readLines(queryFileUrl, 
StandardCharsets.UTF_8)
+                .stream()
+                .filter(it -> !it.startsWith("#"))
+                .collect(Collectors.joining())
+                .replace("{segmentId}", segmentId);
+        final ResponseEntity<GQLResponse<ProfiledSegment>> responseEntity = 
restTemplate.exchange(
+                new RequestEntity<>(queryString, HttpMethod.POST, 
URI.create(endpointUrl)),
+                new ParameterizedTypeReference<GQLResponse<ProfiledSegment>>() 
{
+                }
+        );
+
+        if (responseEntity.getStatusCode() != HttpStatus.OK) {
+            throw new RuntimeException("Response status != 200, actual: " + 
responseEntity.getStatusCode());
+        }
+
+        return 
Objects.requireNonNull(responseEntity.getBody()).getData().getSegment();
+    }
+
     public ProfileAnalyzation getProfileAnalyzation(final String segmentId, 
long start, long end) throws IOException {
         final URL queryFileUrl = 
Resources.getResource("getProfileAnalyzation.gql");
         final String queryString = Resources.readLines(queryFileUrl, 
StandardCharsets.UTF_8)
@@ -143,4 +163,5 @@ public class ProfileClient extends SimpleQueryClient {
         return Objects.requireNonNull(responseEntity.getBody()).getData();
     }
 
+
 }
diff --git 
a/test/e2e/e2e-profile/e2e-profile-test-runner/src/main/java/org/apache/skywalking/e2e/profile/query/ProfiledSegment.java
 
b/test/e2e/e2e-profile/e2e-profile-test-runner/src/main/java/org/apache/skywalking/e2e/profile/query/ProfiledSegment.java
new file mode 100644
index 0000000..b36e4a6
--- /dev/null
+++ 
b/test/e2e/e2e-profile/e2e-profile-test-runner/src/main/java/org/apache/skywalking/e2e/profile/query/ProfiledSegment.java
@@ -0,0 +1,36 @@
+/*
+ * 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.skywalking.e2e.profile.query;
+
+import lombok.Data;
+import lombok.ToString;
+
+import java.util.List;
+
+@Data
+public class ProfiledSegment {
+
+    private ProfiledSegmentData segment;
+
+    @Data
+    @ToString
+    public static class ProfiledSegmentData {
+        private List<ProfiledSpan> spans;
+    }
+}
diff --git 
a/test/e2e/e2e-profile/e2e-profile-test-runner/src/main/java/org/apache/skywalking/e2e/profile/query/ProfiledSegmentMatcher.java
 
b/test/e2e/e2e-profile/e2e-profile-test-runner/src/main/java/org/apache/skywalking/e2e/profile/query/ProfiledSegmentMatcher.java
new file mode 100644
index 0000000..25cf661
--- /dev/null
+++ 
b/test/e2e/e2e-profile/e2e-profile-test-runner/src/main/java/org/apache/skywalking/e2e/profile/query/ProfiledSegmentMatcher.java
@@ -0,0 +1,45 @@
+/*
+ * 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.skywalking.e2e.profile.query;
+
+import com.google.common.primitives.Ints;
+import lombok.Data;
+import org.apache.skywalking.e2e.verification.AbstractMatcher;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@Data
+public class ProfiledSegmentMatcher extends 
AbstractMatcher<ProfiledSegment.ProfiledSegmentData> {
+
+    private List<ProfiledSpanMatcher> spans;
+
+    @Override
+    public void verify(ProfiledSegment.ProfiledSegmentData 
profiledSegmentData) {
+        assertThat(spans).hasSameSizeAs(profiledSegmentData.getSpans());
+
+        
profiledSegmentData.setSpans(profiledSegmentData.getSpans().stream().sorted().collect(Collectors.toList()));
+
+        for (int i = 0; i < profiledSegmentData.getSpans().size(); i++) {
+            spans.get(i).verify(profiledSegmentData.getSpans().get(i));
+        }
+    }
+}
diff --git 
a/test/e2e/e2e-profile/e2e-profile-test-runner/src/main/java/org/apache/skywalking/e2e/profile/query/ProfiledSpan.java
 
b/test/e2e/e2e-profile/e2e-profile-test-runner/src/main/java/org/apache/skywalking/e2e/profile/query/ProfiledSpan.java
new file mode 100644
index 0000000..3d6dd20
--- /dev/null
+++ 
b/test/e2e/e2e-profile/e2e-profile-test-runner/src/main/java/org/apache/skywalking/e2e/profile/query/ProfiledSpan.java
@@ -0,0 +1,40 @@
+/*
+ * 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.skywalking.e2e.profile.query;
+
+import com.google.common.primitives.Ints;
+import lombok.Data;
+import lombok.ToString;
+
+@Data
+@ToString
+public class ProfiledSpan implements Comparable<ProfiledSpan> {
+
+    private String spanId;
+    private String parentSpanId;
+    private String serviceCode;
+    private String startTime;
+    private String endTime;
+    private String endpointName;
+
+    @Override
+    public int compareTo(ProfiledSpan o) {
+        return Ints.compare(Integer.parseInt(spanId), 
Integer.parseInt(o.spanId));
+    }
+}
diff --git 
a/test/e2e/e2e-profile/e2e-profile-test-runner/src/main/java/org/apache/skywalking/e2e/profile/query/ProfiledSpanMatcher.java
 
b/test/e2e/e2e-profile/e2e-profile-test-runner/src/main/java/org/apache/skywalking/e2e/profile/query/ProfiledSpanMatcher.java
new file mode 100644
index 0000000..93aca7e
--- /dev/null
+++ 
b/test/e2e/e2e-profile/e2e-profile-test-runner/src/main/java/org/apache/skywalking/e2e/profile/query/ProfiledSpanMatcher.java
@@ -0,0 +1,43 @@
+/*
+ * 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.skywalking.e2e.profile.query;
+
+import lombok.Data;
+import org.apache.skywalking.e2e.verification.AbstractMatcher;
+
+@Data
+public class ProfiledSpanMatcher extends AbstractMatcher<ProfiledSpan> {
+
+    private String spanId;
+    private String parentSpanId;
+    private String serviceCode;
+    private String startTime;
+    private String endTime;
+    private String endpointName;
+
+    @Override
+    public void verify(ProfiledSpan span) {
+        doVerify(spanId, span.getSpanId());
+        doVerify(parentSpanId, span.getParentSpanId());
+        doVerify(serviceCode, span.getServiceCode());
+        doVerify(startTime, span.getStartTime());
+        doVerify(endTime, span.getEndTime());
+        doVerify(endpointName, span.getEndpointName());
+    }
+}
diff --git 
a/test/e2e/e2e-profile/e2e-profile-test-runner/src/main/resources/expected-data/org.apache.skywalking.e2e.ProfileVerificationITCase.profileSegment.yml
 
b/test/e2e/e2e-profile/e2e-profile-test-runner/src/main/resources/expected-data/org.apache.skywalking.e2e.ProfileVerificationITCase.profileSegment.yml
new file mode 100644
index 0000000..a7246f2
--- /dev/null
+++ 
b/test/e2e/e2e-profile/e2e-profile-test-runner/src/main/resources/expected-data/org.apache.skywalking.e2e.ProfileVerificationITCase.profileSegment.yml
@@ -0,0 +1,47 @@
+# 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.
+
+spans:
+  - spanId: 0
+    parentSpanId: -1
+    serviceCode: not null
+    startTime: gt 0
+    endTime: gt 0
+    endpointName: /e2e/users
+  - spanId: 1
+    parentSpanId: 0
+    serviceCode: not null
+    startTime: gt 0
+    endTime: gt 0
+    endpointName: H2/JDBI/PreparedStatement/executeQuery
+  - spanId: 2
+    parentSpanId: 0
+    serviceCode: not null
+    startTime: gt 0
+    endTime: gt 0
+    endpointName: H2/JDBI/PreparedStatement/executeUpdate
+  - spanId: 3
+    parentSpanId: 0
+    serviceCode: not null
+    startTime: gt 0
+    endTime: gt 0
+    endpointName: H2/JDBI/Connection/commit
+  - spanId: 4
+    parentSpanId: 0
+    serviceCode: not null
+    startTime: gt 0
+    endTime: gt 0
+    endpointName: H2/JDBI/Connection/commit
diff --git 
a/test/e2e/e2e-profile/e2e-profile-test-runner/src/main/resources/getProfiledSegment.gql
 
b/test/e2e/e2e-profile/e2e-profile-test-runner/src/main/resources/getProfiledSegment.gql
new file mode 100644
index 0000000..27a31d8
--- /dev/null
+++ 
b/test/e2e/e2e-profile/e2e-profile-test-runner/src/main/resources/getProfiledSegment.gql
@@ -0,0 +1,28 @@
+# 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.
+
+{
+  "query":"query getProfiledSegment($segmentId: String!) {
+    segment: getProfiledSegment(segmentId: $segmentId) {
+        spans {
+           spanId parentSpanId serviceCode startTime endTime endpointName type 
peer component isError layer
+        }
+    }
+  }",
+  "variables": {
+    "segmentId": "{segmentId}"
+  }
+}
\ No newline at end of file
diff --git 
a/test/e2e/e2e-profile/e2e-profile-test-runner/src/test/java/org/apache/skywalking/e2e/ProfileVerificationITCase.java
 
b/test/e2e/e2e-profile/e2e-profile-test-runner/src/test/java/org/apache/skywalking/e2e/ProfileVerificationITCase.java
index cfba209..5f6ea7f 100644
--- 
a/test/e2e/e2e-profile/e2e-profile-test-runner/src/test/java/org/apache/skywalking/e2e/ProfileVerificationITCase.java
+++ 
b/test/e2e/e2e-profile/e2e-profile-test-runner/src/test/java/org/apache/skywalking/e2e/ProfileVerificationITCase.java
@@ -34,6 +34,8 @@ import 
org.apache.skywalking.e2e.profile.query.ProfileAnalyzation;
 import org.apache.skywalking.e2e.profile.query.ProfileStackTreeMatcher;
 import org.apache.skywalking.e2e.profile.query.ProfileTaskQuery;
 import org.apache.skywalking.e2e.profile.query.ProfileTasks;
+import org.apache.skywalking.e2e.profile.query.ProfiledSegment;
+import org.apache.skywalking.e2e.profile.query.ProfiledSegmentMatcher;
 import org.apache.skywalking.e2e.profile.query.ProfilesTasksMatcher;
 import org.apache.skywalking.e2e.service.Service;
 import org.apache.skywalking.e2e.service.ServicesMatcher;
@@ -192,6 +194,15 @@ public class ProfileVerificationITCase {
         }
 
         String segmentId = foundedTrace.getKey();
+
+        // verify segment
+        ProfiledSegment.ProfiledSegmentData segmentData = 
profileClient.getProfiledSegment(foundedTrace.getKey());
+        LOGGER.info("get profiled segment : {}", segmentData);
+        InputStream inputStream = new ClassPathResource(
+                
"expected-data/org.apache.skywalking.e2e.ProfileVerificationITCase.profileSegment.yml").getInputStream();
+        final ProfiledSegmentMatcher tracesMatcher = new 
Yaml().loadAs(inputStream, ProfiledSegmentMatcher.class);
+        tracesMatcher.verify(segmentData);
+
         long start = Long.parseLong(foundedTrace.getStart());
         long end = start + foundedTrace.getDuration();
         ProfileAnalyzation analyzation = 
profileClient.getProfileAnalyzation(segmentId, start, end);

Reply via email to