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 5afbc290d9 feat(add go profile data collect and analyze) (#13524)
5afbc290d9 is described below

commit 5afbc290d90976cbba97e9bc1333a4e306e2ceca
Author: hao <[email protected]>
AuthorDate: Fri Oct 31 18:59:35 2025 +0800

    feat(add go profile data collect and analyze) (#13524)
---
 .github/workflows/skywalking.yaml                  |   5 +-
 docs/en/changes/changes.md                         |   4 +-
 .../core/profiling/trace/ProfileLanguageType.java  |  45 +++
 .../trace/ProfileThreadSnapshotRecord.java         |   7 +
 .../profiling/trace/analyze/GoProfileAnalyzer.java | 243 +++++++++++++++
 .../profiling/trace/analyze/ProfileAnalyzer.java   | 112 ++++++-
 .../server/library/pprof/parser/PprofParser.java   |  27 ++
 .../library/pprof/parser/PprofSegmentParser.java   | 326 +++++++++++++++++++++
 .../library/pprof/type/FrameTreeBuilder.java       |  11 +-
 .../skywalking-profile-receiver-plugin/pom.xml     |   6 +
 .../handler/ProfileTaskServiceHandler.java         | 146 +++++++++
 .../storage/plugin/banyandb/BanyanDBConverter.java |   9 +
 .../elasticsearch/base/ColumnTypeEsMapping.java    |   3 +-
 .../plugin/jdbc/common/JDBCTableInstaller.java     |   3 +-
 .../jdbc/postgresql/PostgreSQLTableInstaller.java  |   3 +-
 test/e2e-v2/cases/go/service/e2e.go                |  20 ++
 test/e2e-v2/cases/go/service/go.mod                |   1 -
 .../cases/profiling/trace/go/docker-compose.yml    |  65 ++++
 test/e2e-v2/cases/profiling/trace/go/e2e.yaml      |  92 ++++++
 .../profiling/trace/go/expected/profile-create.yml |  17 ++
 .../trace/go/expected/profile-list-finished.yml    |  34 +++
 .../trace/go/expected/profile-list-notified.yml    |  34 +++
 .../trace/go/expected/profile-segment-analyze.yml  |  32 ++
 .../trace/go/expected/profile-segment-list.yml     |  52 ++++
 24 files changed, 1266 insertions(+), 31 deletions(-)

diff --git a/.github/workflows/skywalking.yaml 
b/.github/workflows/skywalking.yaml
index 0850b6750d..57bd56f15f 100644
--- a/.github/workflows/skywalking.yaml
+++ b/.github/workflows/skywalking.yaml
@@ -492,6 +492,9 @@ jobs:
             config: test/e2e-v2/cases/profiling/trace/opensearch/e2e.yaml
             env: OPENSEARCH_VERSION=2.4.0
 
+          - name: Go Trace Profiling
+            config: test/e2e-v2/cases/profiling/trace/go/e2e.yaml
+
           - name: eBPF Profiling On CPU BanyanDB
             config: test/e2e-v2/cases/profiling/ebpf/oncpu/banyandb/e2e.yaml
             docker:
@@ -1118,4 +1121,4 @@ jobs:
           [[ ${e2eJavaVersionResults} == 'success' ]] || [[ ${execute} != 
'true' && ${e2eJavaVersionResults} == 'skipped' ]] || exit -7;
           [[ ${timeConsumingITResults} == 'success' ]] || [[ ${execute} != 
'true' && ${timeConsumingITResults} == 'skipped' ]] || exit -8;
 
-          exit 0;
+          exit 0;
\ No newline at end of file
diff --git a/docs/en/changes/changes.md b/docs/en/changes/changes.md
index caa250e63c..d1219e1a17 100644
--- a/docs/en/changes/changes.md
+++ b/docs/en/changes/changes.md
@@ -113,7 +113,9 @@
 * Update Grafana dashboards for OAP observability.
 * BanyanDB: fix query `getInstance` by instance ID.
 * Support the go agent(0.7.0 release) bundled pprof profiling feature. 
-
+* Library-pprof-parser: feat: add PprofSegmentParser.
+* Storage: feat: add languageType column to ProfileThreadSnapshotRecord.
+* Feat: add go profile analyzer
 
 #### UI
 
diff --git 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/trace/ProfileLanguageType.java
 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/trace/ProfileLanguageType.java
new file mode 100644
index 0000000000..8faf53b810
--- /dev/null
+++ 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/trace/ProfileLanguageType.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.oap.server.core.profiling.trace;
+
+/**
+ * Language type for profile records. Stored as int in storage for 
compatibility.
+ */
+public enum ProfileLanguageType {
+    JAVA(0),
+    GO(1);
+
+    private final int value;
+
+    ProfileLanguageType(int value) {
+        this.value = value;
+    }
+
+    public int getValue() {
+        return value;
+    }
+
+    public static ProfileLanguageType fromValue(int value) {
+        for (ProfileLanguageType language : values()) {
+            if (language.value == value) {
+                return language;
+            }
+        }
+        return JAVA; // default to Java
+    }
+}
\ No newline at end of file
diff --git 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/trace/ProfileThreadSnapshotRecord.java
 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/trace/ProfileThreadSnapshotRecord.java
index bd04334a1c..98d048e84e 100644
--- 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/trace/ProfileThreadSnapshotRecord.java
+++ 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/trace/ProfileThreadSnapshotRecord.java
@@ -52,6 +52,7 @@ public class ProfileThreadSnapshotRecord extends Record {
     public static final String DUMP_TIME = "dump_time";
     public static final String SEQUENCE = "sequence";
     public static final String STACK_BINARY = "stack_binary";
+    public static final String LANGUAGE_TYPE = "language_type";
 
     @Column(name = TASK_ID)
     @SQLDatabase.CompositeIndex(withColumns = {SEGMENT_ID})
@@ -69,6 +70,8 @@ public class ProfileThreadSnapshotRecord extends Record {
     private int sequence;
     @Column(name = STACK_BINARY)
     private byte[] stackBinary;
+    @Column(name = LANGUAGE_TYPE) // NoIndexing
+    private ProfileLanguageType language = ProfileLanguageType.JAVA;
 
     @Override
     public StorageID id() {
@@ -88,6 +91,8 @@ public class ProfileThreadSnapshotRecord extends Record {
             snapshot.setSequence(((Number) 
converter.get(SEQUENCE)).intValue());
             snapshot.setTimeBucket(((Number) 
converter.get(TIME_BUCKET)).intValue());
             snapshot.setStackBinary(converter.getBytes(STACK_BINARY));
+            final Number languageTypeNum = (Number) 
converter.get(LANGUAGE_TYPE);
+            snapshot.setLanguage(ProfileLanguageType.fromValue(languageTypeNum 
!= null ? languageTypeNum.intValue() : 0));
             return snapshot;
         }
 
@@ -99,6 +104,8 @@ public class ProfileThreadSnapshotRecord extends Record {
             converter.accept(SEQUENCE, storageData.getSequence());
             converter.accept(TIME_BUCKET, storageData.getTimeBucket());
             converter.accept(STACK_BINARY, storageData.getStackBinary());
+            ProfileLanguageType language = storageData.getLanguage();
+            converter.accept(LANGUAGE_TYPE, language != null ? 
language.getValue() : ProfileLanguageType.JAVA.getValue());
         }
     }
 }
diff --git 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/trace/analyze/GoProfileAnalyzer.java
 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/trace/analyze/GoProfileAnalyzer.java
new file mode 100644
index 0000000000..fe2a9e53b6
--- /dev/null
+++ 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/trace/analyze/GoProfileAnalyzer.java
@@ -0,0 +1,243 @@
+/*
+ * 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.profiling.trace.analyze;
+
+import com.google.perftools.profiles.ProfileProto;
+import java.util.Collections;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.ArrayDeque;
+import 
org.apache.skywalking.oap.server.core.profiling.trace.ProfileThreadSnapshotRecord;
+import 
org.apache.skywalking.oap.server.core.query.input.SegmentProfileAnalyzeQuery;
+import org.apache.skywalking.oap.server.core.query.type.ProfileAnalyzation;
+import org.apache.skywalking.oap.server.core.query.type.ProfileStackElement;
+import org.apache.skywalking.oap.server.core.query.type.ProfileStackTree;
+import 
org.apache.skywalking.oap.server.library.pprof.parser.PprofSegmentParser;
+import org.apache.skywalking.oap.server.library.pprof.parser.PprofParser;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Analyzer for Go pprof samples. Builds a stack tree with total/self 
durations using sampling period.
+ * This works independently from ThreadSnapshot, for Go profiles only.
+ */
+public class GoProfileAnalyzer {
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(GoProfileAnalyzer.class);
+
+    /**
+     * Analyze a pprof profile for a specific segment and time window.
+     */
+    public ProfileAnalyzation analyze(final String segmentId,
+                                      final ProfileProto.Profile profile) {
+        final long periodMs = PprofSegmentParser.resolvePeriodMillis(profile);
+
+        // Build ProfileStackElement directly (reuse FrameTreeBuilder's 
mergeSample logic)
+        Map<String, Integer> key2Id = new HashMap<>(); // "parentId|name" -> id
+        List<ProfileStackElement> elements = new ArrayList<>();
+
+        // Strict per-segment filtering
+        final List<String> stringTable = profile.getStringTableList();
+
+        for (ProfileProto.Sample sample : profile.getSampleList()) {
+            final String seg = 
PprofSegmentParser.extractSegmentIdFromLabels(sample.getLabelList(), 
stringTable);
+            if (seg == null || !seg.equals(segmentId)) {
+                continue;
+            }
+            long sampleCount = sample.getValueCount() > 0 ? sample.getValue(0) 
: 1L;
+            long weightMs = sampleCount * periodMs;
+            
+            // Build function stack then ensure root->leaf order for 
aggregation
+            List<String> stack = 
PprofSegmentParser.extractStackFromSample(sample, profile);
+            Collections.reverse(stack);
+            
+            // Aggregate along path (similar to FrameTreeBuilder.mergeSample)
+            int parentId = -1; // root
+            for (String fn : stack) {
+                String key = parentId + "|" + fn;
+                Integer nodeId = key2Id.get(key);
+                
+                if (nodeId == null) {
+                    ProfileStackElement element = new ProfileStackElement();
+                    element.setId(elements.size());
+                    element.setParentId(parentId);
+                    element.setCodeSignature(fn);
+                    element.setDuration(0);
+                    element.setDurationChildExcluded(0);
+                    element.setCount(0);
+                    elements.add(element);
+                    nodeId = element.getId();
+                    key2Id.put(key, nodeId);
+                }
+                
+                ProfileStackElement element = elements.get(nodeId);
+                element.setDuration(element.getDuration() + (int) weightMs);
+                element.setCount(element.getCount() + (int) sampleCount);
+                
+                parentId = nodeId;
+            }
+        }
+        
+        int rootCount = 0;
+        for (ProfileStackElement e : elements) {
+            if (e.getParentId() == -1) {
+                rootCount++;
+            }
+        }
+        if (rootCount > 1) {
+            int virtualRootId = elements.size();
+            ProfileStackElement virtualRoot = new ProfileStackElement();
+            virtualRoot.setId(virtualRootId);
+            virtualRoot.setParentId(-1);
+            virtualRoot.setCodeSignature("root");
+            virtualRoot.setDuration(0);
+            virtualRoot.setDurationChildExcluded(0);
+            virtualRoot.setCount(0);
+            elements.add(virtualRoot);
+
+            for (ProfileStackElement e : elements) {
+                if (e.getId() == virtualRootId) {
+                    continue;
+                }
+                if (e.getParentId() == -1) {
+                    e.setParentId(virtualRootId);
+                    virtualRoot.setDuration(virtualRoot.getDuration() + 
e.getDuration());
+                    virtualRoot.setCount(virtualRoot.getCount() + 
e.getCount());
+                }
+            }
+        }
+
+        Map<Integer, Integer> childDurSum = new HashMap<>();
+        for (ProfileStackElement child : elements) {
+            int pid = child.getParentId();
+            if (pid != -1) {
+                childDurSum.put(pid, childDurSum.getOrDefault(pid, 0) + 
child.getDuration());
+            }
+        }
+        for (ProfileStackElement elem : elements) {
+            int childrenSum = childDurSum.getOrDefault(elem.getId(), 0);
+            elem.setDurationChildExcluded(Math.max(0, elem.getDuration() - 
childrenSum));
+        }
+        
+        Integer rootId = null;
+        for (ProfileStackElement e : elements) {
+            if (e.getParentId() == -1) {
+                rootId = e.getId();
+                break;
+            }
+        }
+        if (rootId != null) {
+            Map<Integer, List<ProfileStackElement>> childrenMap = new 
HashMap<>();
+            for (ProfileStackElement e : elements) {
+                childrenMap.computeIfAbsent(e.getParentId(), k -> new 
ArrayList<>()).add(e);
+            }
+
+            List<ProfileStackElement> ordered = new ArrayList<>();
+            ArrayDeque<ProfileStackElement> queue = new ArrayDeque<>();
+            // start from root
+            for (ProfileStackElement e : elements) {
+                if (e.getId() == rootId) {
+                    queue.add(e);
+                    break;
+                }
+            }
+            while (!queue.isEmpty()) {
+                ProfileStackElement cur = queue.removeFirst();
+                ordered.add(cur);
+                List<ProfileStackElement> children = 
childrenMap.get(cur.getId());
+                if (children != null) {
+                    // sort children by duration desc to make primary path 
first
+                    children.sort((a, b) -> Integer.compare(b.getDuration(), 
a.getDuration()));
+                    queue.addAll(children);
+                }
+            }
+
+            Map<Integer, Integer> idRemap = new HashMap<>();
+            for (int i = 0; i < ordered.size(); i++) {
+                idRemap.put(ordered.get(i).getId(), i);
+            }
+            for (ProfileStackElement e : ordered) {
+                int newId = idRemap.get(e.getId());
+                int parentId = e.getParentId();
+                e.setId(newId);
+                if (parentId == -1) {
+                    e.setParentId(-1);
+                } else {
+                    e.setParentId(idRemap.getOrDefault(parentId, -1));
+                }
+            }
+            elements = ordered;
+        }
+
+        ProfileStackTree tree = new ProfileStackTree();
+        tree.setElements(elements);
+        
+        ProfileAnalyzation result = new ProfileAnalyzation();
+        result.getTrees().add(tree);
+        return result;
+    }
+
+    /**
+     * Analyze multiple Go profile records and return combined results
+     */
+    public ProfileAnalyzation analyzeRecords(List<ProfileThreadSnapshotRecord> 
records, List<SegmentProfileAnalyzeQuery> queries) {
+        ProfileAnalyzation result = new ProfileAnalyzation();
+        
+        // Build query map for O(1) lookup
+        Map<String, SegmentProfileAnalyzeQuery> queryMap = queries.stream()
+            
.collect(Collectors.toMap(SegmentProfileAnalyzeQuery::getSegmentId, q -> q));
+        
+        for (ProfileThreadSnapshotRecord record : records) {
+            try {
+                // Find the corresponding query for this segment
+                SegmentProfileAnalyzeQuery query = 
queryMap.get(record.getSegmentId());
+                
+                if (query == null) {
+                    LOGGER.warn("No query found for Go profile segment: {}", 
record.getSegmentId());
+                    continue;
+                }
+
+                // Parse pprof data from stackBinary
+                ProfileProto.Profile profile = 
PprofParser.parseProfile(record.getStackBinary());
+                
+                // Analyze this record
+                ProfileAnalyzation recordAnalyzation = analyze(
+                    record.getSegmentId(),
+                    profile
+                );
+
+                if (recordAnalyzation != null && 
!recordAnalyzation.getTrees().isEmpty()) {
+                    result.getTrees().addAll(recordAnalyzation.getTrees());
+                    
+                    if (LOGGER.isInfoEnabled()) {
+                        LOGGER.info("Go profile analysis completed: 
segmentId={}, window=[{}-{}], trees={}",
+                            record.getSegmentId(), 
query.getTimeRange().getStart(), query.getTimeRange().getEnd(),
+                            recordAnalyzation.getTrees().size());
+                    }
+                }
+            } catch (Exception e) {
+                LOGGER.error("Failed to analyze Go profile record: 
segmentId={}, sequence={}, dumpTime={}",
+                    record.getSegmentId(), record.getSequence(), 
record.getDumpTime(), e);
+            }
+        }
+        
+        return result;
+    }
+}
diff --git 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/trace/analyze/ProfileAnalyzer.java
 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/trace/analyze/ProfileAnalyzer.java
index 65d67cd454..6a80e6f10d 100644
--- 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/trace/analyze/ProfileAnalyzer.java
+++ 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/trace/analyze/ProfileAnalyzer.java
@@ -28,6 +28,7 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.stream.Collectors;
 import 
org.apache.skywalking.oap.server.core.profiling.trace.ProfileThreadSnapshotRecord;
+import 
org.apache.skywalking.oap.server.core.profiling.trace.ProfileLanguageType;
 import 
org.apache.skywalking.oap.server.core.query.input.SegmentProfileAnalyzeQuery;
 import org.apache.skywalking.oap.server.core.query.type.ProfileAnalyzation;
 import org.apache.skywalking.oap.server.core.query.type.ProfileStackTree;
@@ -67,30 +68,99 @@ public class ProfileAnalyzer {
     public ProfileAnalyzation analyze(final List<SegmentProfileAnalyzeQuery> 
queries) throws IOException {
         ProfileAnalyzation analyzation = new ProfileAnalyzation();
 
-        // query sequence range list
+        // Step 1: Try Java profile analysis first (original logic with time 
window)
         SequenceSearch sequenceSearch = getAllSequenceRange(queries);
-        if (sequenceSearch == null) {
-            analyzation.setTip("Data not found");
-            return analyzation;
+        List<ProfileThreadSnapshotRecord> javaRecords = new ArrayList<>();
+        
+        if (sequenceSearch != null) {
+            if (sequenceSearch.getTotalSequenceCount() > 
analyzeSnapshotMaxSize) {
+                analyzation.setTip("Out of snapshot analyze limit, " + 
sequenceSearch.getTotalSequenceCount() + " snapshots found, but analysis first 
" + analyzeSnapshotMaxSize + " snapshots only.");
+            }
+
+            // query snapshots within time window
+            List<ProfileThreadSnapshotRecord> records = 
sequenceSearch.getRanges().parallelStream().map(r -> {
+                try {
+                    return 
getProfileThreadSnapshotQueryDAO().queryRecords(r.getSegmentId(), 
r.getMinSequence(), r.getMaxSequence());
+                } catch (IOException e) {
+                    LOGGER.warn(e.getMessage(), e);
+                    return 
Collections.<ProfileThreadSnapshotRecord>emptyList();
+                }
+            }).flatMap(Collection::stream)
+                .collect(Collectors.toList());
+
+            if (LOGGER.isDebugEnabled()) {
+                final int totalRanges = sequenceSearch.getRanges().size();
+                LOGGER.debug("Profile analyze fetched records, 
segmentId(s)={}, ranges={}, recordsCount={}",
+                    
sequenceSearch.getRanges().stream().map(SequenceRange::getSegmentId).distinct().collect(Collectors.toList()),
+                    totalRanges, records.size());
+            }
+
+            // Filter Java records
+            javaRecords = records.stream()
+                .filter(rec -> rec.getLanguage() == ProfileLanguageType.JAVA)
+                .collect(Collectors.toList());
+        } else {
+            if (LOGGER.isInfoEnabled()) {
+                LOGGER.info("Profile analyze: no Java records found in time 
window, will try Go fallback");
+            }
         }
-        if (sequenceSearch.getTotalSequenceCount() > analyzeSnapshotMaxSize) {
-            analyzation.setTip("Out of snapshot analyze limit, " + 
sequenceSearch.getTotalSequenceCount() + " snapshots found, but analysis first 
" + analyzeSnapshotMaxSize + " snapshots only.");
+
+        // Analyze Java profiles if found
+        if (!javaRecords.isEmpty()) {
+            LOGGER.info("Analyzing {} Java profile records", 
javaRecords.size());
+            List<ProfileStack> stacks = javaRecords.stream()
+                .map(rec -> {
+                    try {
+                        return ProfileStack.deserialize(rec);
+                    } catch (Exception ex) {
+                        LOGGER.warn("Deserialize stack failed, segmentId={}, 
sequence={}, dumpTime={}",
+                            rec.getSegmentId(), rec.getSequence(), 
rec.getDumpTime(), ex);
+                        return null;
+                    }
+                })
+                .filter(java.util.Objects::nonNull)
+                .distinct()
+                .collect(Collectors.toList());
+
+            final List<ProfileStackTree> trees = analyzeByStack(stacks);
+            if (trees != null && !trees.isEmpty()) {
+                analyzation.getTrees().addAll(trees);
+                // Java analysis found data, return early
+                return analyzation;
+            }
         }
 
-        // query snapshots
-        List<ProfileStack> stacks = 
sequenceSearch.getRanges().parallelStream().map(r -> {
+        // Step 2: Fallback to Go profile analysis if Java found no data
+        // For Go profiles, ignore time window and fetch all records per 
segment
+        List<ProfileThreadSnapshotRecord> goRecords = new ArrayList<>();
+        for (SegmentProfileAnalyzeQuery q : queries) {
+            final String segId = q.getSegmentId();
             try {
-                return 
getProfileThreadSnapshotQueryDAO().queryRecords(r.getSegmentId(), 
r.getMinSequence(), r.getMaxSequence());
+                int minSeq = 
getProfileThreadSnapshotQueryDAO().queryMinSequence(segId, 0L, Long.MAX_VALUE);
+                int maxSeqExclusive = 
getProfileThreadSnapshotQueryDAO().queryMaxSequence(segId, 0L, Long.MAX_VALUE) 
+ 1;
+                if (maxSeqExclusive > minSeq) {
+                    List<ProfileThreadSnapshotRecord> full = 
getProfileThreadSnapshotQueryDAO().queryRecords(segId, minSeq, maxSeqExclusive);
+                    for (ProfileThreadSnapshotRecord r : full) {
+                        if (r.getLanguage() == ProfileLanguageType.GO) {
+                            goRecords.add(r);
+                        }
+                    }
+                }
             } catch (IOException e) {
-                LOGGER.warn(e.getMessage(), e);
-                return Collections.<ProfileThreadSnapshotRecord>emptyList();
+                LOGGER.warn("Go fallback: full-range fetch failed for 
segmentId={}", segId, e);
             }
-        
}).flatMap(Collection::stream).map(ProfileStack::deserialize).distinct().collect(Collectors.toList());
+        }
 
-        // analyze
-        final List<ProfileStackTree> trees = analyzeByStack(stacks);
-        if (trees != null) {
-            analyzation.getTrees().addAll(trees);
+        if (!goRecords.isEmpty()) {
+            LOGGER.info("Java analysis found no data, fallback to Go: 
analyzing {} Go profile records", goRecords.size());
+            GoProfileAnalyzer goAnalyzer = new GoProfileAnalyzer();
+            ProfileAnalyzation goAnalyzation = 
goAnalyzer.analyzeRecords(goRecords, queries);
+            if (goAnalyzation != null && !goAnalyzation.getTrees().isEmpty()) {
+                analyzation.getTrees().addAll(goAnalyzation.getTrees());
+            }
+        } else if (sequenceSearch == null && javaRecords.isEmpty()) {
+            // Both Java (time window) and Go (full range) found nothing
+            analyzation.setTip("Data not found");
         }
 
         return analyzation;
@@ -115,8 +185,17 @@ public class ProfileAnalyzer {
         int minSequence = 
getProfileThreadSnapshotQueryDAO().queryMinSequence(segmentId, start, end);
         int maxSequence = 
getProfileThreadSnapshotQueryDAO().queryMaxSequence(segmentId, start, end) + 1;
 
+        if (LOGGER.isDebugEnabled()) {
+            LOGGER.debug("Profile analyze sequence window: segmentId={}, 
start={}, end={}, minSeq={}, maxSeq(exclusive)={}",
+                segmentId, start, end, minSequence, maxSequence);
+        }
+
         // data not found
         if (maxSequence <= 0) {
+            if (LOGGER.isDebugEnabled()) {
+                LOGGER.debug("Profile analyze not found any sequence in 
window: segmentId={}, start={}, end={}",
+                    segmentId, start, end);
+            }
             return null;
         }
 
@@ -207,4 +286,5 @@ public class ProfileAnalyzer {
         }
 
     }
+
 }
diff --git 
a/oap-server/server-library/library-pprof-parser/src/main/java/org/apache/skywalking/oap/server/library/pprof/parser/PprofParser.java
 
b/oap-server/server-library/library-pprof-parser/src/main/java/org/apache/skywalking/oap/server/library/pprof/parser/PprofParser.java
index 2475a19694..260b235232 100644
--- 
a/oap-server/server-library/library-pprof-parser/src/main/java/org/apache/skywalking/oap/server/library/pprof/parser/PprofParser.java
+++ 
b/oap-server/server-library/library-pprof-parser/src/main/java/org/apache/skywalking/oap/server/library/pprof/parser/PprofParser.java
@@ -54,4 +54,31 @@ public class PprofParser {
         FrameTree tree = new FrameTreeBuilder(profile).build();
         return tree;
     }
+
+    /**
+     * Resolve function signature for a given location id. The signature 
format matches FrameTreeBuilder
+     * (functionName:line;... when inlined, joined by ';').
+     */
+    public static String resolveSignature(long locationId, 
ProfileProto.Profile profile) {
+        if (locationId == 0) {
+            return "root";
+        }
+        ProfileProto.Location location = profile.getLocation((int) locationId 
- 1);
+        return location.getLineList().stream().map(line -> {
+            ProfileProto.Function function = profile.getFunction((int) 
line.getFunctionId() - 1);
+            String functionName = profile.getStringTable((int) 
function.getName());
+            return functionName + ":" + line.getLine();
+        }).collect(java.util.stream.Collectors.joining(";"));
+    }
+
+    public static ProfileProto.Profile parseProfile(byte[] payload) throws 
IOException {
+        if (payload == null) {
+            throw new IOException("pprof payload is null");
+        }
+        java.io.InputStream input = new java.io.ByteArrayInputStream(payload);
+        if (payload.length >= 2 && (payload[0] == (byte) 0x1F) && (payload[1] 
== (byte) 0x8B)) {
+            input = new GZIPInputStream(input);
+        }
+        return ProfileProto.Profile.parseFrom(input);
+    }
 }
diff --git 
a/oap-server/server-library/library-pprof-parser/src/main/java/org/apache/skywalking/oap/server/library/pprof/parser/PprofSegmentParser.java
 
b/oap-server/server-library/library-pprof-parser/src/main/java/org/apache/skywalking/oap/server/library/pprof/parser/PprofSegmentParser.java
new file mode 100644
index 0000000000..7fcba93be2
--- /dev/null
+++ 
b/oap-server/server-library/library-pprof-parser/src/main/java/org/apache/skywalking/oap/server/library/pprof/parser/PprofSegmentParser.java
@@ -0,0 +1,326 @@
+/*
+ * 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.library.pprof.parser;
+
+import com.google.perftools.profiles.ProfileProto;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+
+/**
+ * Parse pprof profile data and extract segment information
+ */
+public class PprofSegmentParser {
+
+    /**
+     * Segment information extracted from pprof labels
+     */
+    public static class SegmentInfo {
+        private String segmentId;
+        private String traceId;
+        private String spanId;
+        private String serviceInstanceId;
+        private List<String> stack;
+        private long count;
+
+        public String getSegmentId() {
+            return segmentId;
+        }
+
+        public void setSegmentId(String segmentId) {
+            this.segmentId = segmentId;
+        }
+
+        public String getTraceId() {
+            return traceId;
+        }
+
+        public void setTraceId(String traceId) {
+            this.traceId = traceId;
+        }
+
+        public String getSpanId() {
+            return spanId;
+        }
+
+        public void setSpanId(String spanId) {
+            this.spanId = spanId;
+        }
+
+        public String getServiceInstanceId() {
+            return serviceInstanceId;
+        }
+
+        public void setServiceInstanceId(String serviceInstanceId) {
+            this.serviceInstanceId = serviceInstanceId;
+        }
+
+        public List<String> getStack() {
+            return stack;
+        }
+
+        public void setStack(List<String> stack) {
+            this.stack = stack;
+        }
+
+        public long getCount() {
+            return count;
+        }
+
+        public void setCount(long count) {
+            this.count = count;
+        }
+    }
+
+    /**
+     * Parse pprof profile and extract all segment information
+     */
+    public static List<SegmentInfo> parseSegments(ProfileProto.Profile 
profile) {
+        List<String> stringTable = profile.getStringTableList();
+
+        // Group samples by segmentId
+        Map<String, List<ProfileProto.Sample>> segmentSamples = new 
HashMap<>();
+
+        for (ProfileProto.Sample sample : profile.getSampleList()) {
+            String segmentId = 
extractSegmentIdFromLabels(sample.getLabelList(), stringTable);
+            if (segmentId != null) {
+                segmentSamples.computeIfAbsent(segmentId, k -> new 
ArrayList<>()).add(sample);
+            }
+        }
+
+        // Create SegmentInfo for each segment
+        List<SegmentInfo> result = new ArrayList<>(segmentSamples.size());
+        for (Map.Entry<String, List<ProfileProto.Sample>> entry : 
segmentSamples.entrySet()) {
+            String segmentId = entry.getKey();
+            List<ProfileProto.Sample> samples = entry.getValue();
+
+            SegmentInfo segmentInfo = new SegmentInfo();
+            segmentInfo.setSegmentId(segmentId);
+
+            // Extract basic information from first sample
+            ProfileProto.Sample firstSample = samples.get(0);
+            
segmentInfo.setTraceId(extractTraceIdFromLabels(firstSample.getLabelList(), 
stringTable));
+            
segmentInfo.setSpanId(extractSpanIdFromLabels(firstSample.getLabelList(), 
stringTable));
+            
segmentInfo.setServiceInstanceId(extractServiceInstanceIdFromLabels(firstSample.getLabelList(),
 stringTable));
+
+            // Merge call stacks from all samples
+            List<String> combinedStack = 
extractCombinedStackFromSamples(samples, profile);
+            segmentInfo.setStack(combinedStack);
+
+            // Calculate total sample count
+            long totalCount = samples.stream()
+                .mapToLong(sample -> sample.getValueCount() > 0 ? 
sample.getValue(0) : 1)
+                .sum();
+            segmentInfo.setCount(totalCount);
+
+            result.add(segmentInfo);
+        }
+
+        return result;
+    }
+
+    /**
+     * Extract segmentId from labels
+     */
+    public static String extractSegmentIdFromLabels(List<ProfileProto.Label> 
labels, List<String> stringTable) {
+        for (ProfileProto.Label label : labels) {
+            String key = getStringFromTable(label.getKey(), stringTable);
+            if (key != null && (key.equals("segment_id") || 
key.equals("trace_segment_id") ||
+                               key.equals("segmentId") || 
key.equals("traceSegmentId") ||
+                               key.equals("traceSegmentID"))) {
+                return getStringFromTable(label.getStr(), stringTable);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Extract traceId from labels
+     */
+    private static String extractTraceIdFromLabels(List<ProfileProto.Label> 
labels, List<String> stringTable) {
+        for (ProfileProto.Label label : labels) {
+            String key = getStringFromTable(label.getKey(), stringTable);
+            if (key != null && (key.equals("trace_id") || 
key.equals("traceId") || key.equals("traceID"))) {
+                return getStringFromTable(label.getStr(), stringTable);
+            }
+        }
+        return "go_trace_" + UUID.randomUUID().toString().replace("-", "");
+    }
+
+    /**
+     * Extract spanId from labels
+     */
+    private static String extractSpanIdFromLabels(List<ProfileProto.Label> 
labels, List<String> stringTable) {
+        for (ProfileProto.Label label : labels) {
+            String key = getStringFromTable(label.getKey(), stringTable);
+            if (key != null && (key.equals("span_id") || key.equals("spanId") 
|| key.equals("spanID"))) {
+                return getStringFromTable(label.getStr(), stringTable);
+            }
+        }
+        return null; // spanId is optional
+    }
+
+    /**
+     * Extract serviceInstanceId from labels
+     */
+    private static String 
extractServiceInstanceIdFromLabels(List<ProfileProto.Label> labels, 
List<String> stringTable) {
+        for (ProfileProto.Label label : labels) {
+            String key = getStringFromTable(label.getKey(), stringTable);
+            if (key != null && (key.equals("service_instance_id") || 
key.equals("serviceInstanceId") ||
+                               key.equals("instance_id") || 
key.equals("instanceId"))) {
+                return getStringFromTable(label.getStr(), stringTable);
+            }
+        }
+        return "go_instance_1";
+    }
+
+    /**
+     * Extract merged call stack from samples
+     */
+    private static List<String> 
extractCombinedStackFromSamples(List<ProfileProto.Sample> samples, 
ProfileProto.Profile profile) {
+        Set<String> uniqueStack = new LinkedHashSet<>();
+
+        for (ProfileProto.Sample sample : samples) {
+            List<String> stack = extractStackFromSample(sample, profile);
+            uniqueStack.addAll(stack);
+        }
+
+        return new ArrayList<>(uniqueStack);
+    }
+
+    /**
+     * Extract call stack from a single sample
+     */
+    public static List<String> extractStackFromSample(ProfileProto.Sample 
sample, ProfileProto.Profile profile) {
+        List<String> stack = new ArrayList<>();
+
+        // Traverse location_id from leaf to root
+        for (int i = sample.getLocationIdCount() - 1; i >= 0; i--) {
+            long locationId = sample.getLocationId(i);
+
+            // Delegate signature resolution to PprofParser to avoid 
duplication
+            String signature = PprofParser.resolveSignature(locationId, 
profile);
+            if (signature != null && !signature.isEmpty()) {
+                stack.add(signature);
+            }
+        }
+
+        return stack;
+    }
+
+    /**
+     * Get string from string table
+     */
+    public static String getStringFromTable(long index, List<String> 
stringTable) {
+        if (index >= 0 && index < stringTable.size()) {
+            return stringTable.get((int) index);
+        }
+        return null;
+    }
+
+    /**
+     * Extract label value from sample labels
+     */
+    public static String extractLabel(ProfileProto.Sample sample, List<String> 
stringTable, String... keys) {
+        for (ProfileProto.Label l : sample.getLabelList()) {
+            String k = getStringFromTable(l.getKey(), stringTable);
+            if (k == null) {
+                continue;
+            }
+            for (String expect : keys) {
+                if (k.equals(expect)) {
+                    return getStringFromTable(l.getStr(), stringTable);
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Extract timestamp from sample labels
+     */
+    public static long extractTimestamp(ProfileProto.Sample sample, 
List<String> stringTable, boolean isStart) {
+        String target = isStart ? "startTime" : "endTime";
+        for (ProfileProto.Label l : sample.getLabelList()) {
+            String k = getStringFromTable(l.getKey(), stringTable);
+            if (k == null) {
+                continue;
+            }
+            if (!target.equalsIgnoreCase(k)) {
+                continue;
+            }
+            long v = l.getNum();
+            if (v <= 0) {
+                try {
+                    String sv = getStringFromTable(l.getStr(), stringTable);
+                    if (sv != null) {
+                        v = Long.parseLong(sv.trim());
+                    }
+                } catch (Exception ignored) {
+                    // ignore
+                }
+            }
+            if (v > 0 && v < 1_000_000_000_000L) {
+                // looks like seconds -> millis
+                return v * 1000L;
+            }
+            return v;
+        }
+        return 0L;
+    }
+
+    /**
+     * Resolve sampling period in milliseconds from pprof profile
+     */
+    public static long resolvePeriodMillis(ProfileProto.Profile profile) {
+        try {
+            long period = profile.getPeriod();
+            String unit = null;
+            if (profile.hasPeriodType()) {
+                unit = getStringFromTable(profile.getPeriodType().getUnit(), 
profile.getStringTableList());
+            }
+            if (period > 0) {
+                if (unit == null || unit.isEmpty() || 
"nanoseconds".equals(unit) || "nanosecond".equals(unit) || "ns".equals(unit)) {
+                    return Math.max(1L, period / 1_000_000L);
+                }
+                if ("microseconds".equals(unit) || "us".equals(unit)) {
+                    return Math.max(1L, period / 1_000L);
+                }
+                if ("milliseconds".equals(unit) || "ms".equals(unit)) {
+                    return Math.max(1L, period);
+                }
+                if ("seconds".equals(unit) || "s".equals(unit)) {
+                    return Math.max(1L, period * 1000L);
+                }
+                if ("hz".equals(unit) || "HZ".equals(unit)) {
+                    // samples per second
+                    return Math.max(1L, 1000L / Math.max(1L, period));
+                }
+            }
+        } catch (Throwable t) {
+            // keep silent in normal path; this is non-fatal and we fallback 
to default
+        }
+        return 10L; // default fallback
+    }
+}
+
diff --git 
a/oap-server/server-library/library-pprof-parser/src/main/java/org/apache/skywalking/oap/server/library/pprof/type/FrameTreeBuilder.java
 
b/oap-server/server-library/library-pprof-parser/src/main/java/org/apache/skywalking/oap/server/library/pprof/type/FrameTreeBuilder.java
index 43c7d47f64..ce893cba28 100644
--- 
a/oap-server/server-library/library-pprof-parser/src/main/java/org/apache/skywalking/oap/server/library/pprof/type/FrameTreeBuilder.java
+++ 
b/oap-server/server-library/library-pprof-parser/src/main/java/org/apache/skywalking/oap/server/library/pprof/type/FrameTreeBuilder.java
@@ -28,6 +28,7 @@ import java.util.stream.Collectors;
 import lombok.AllArgsConstructor;
 import lombok.Data;
 import lombok.NoArgsConstructor;
+import org.apache.skywalking.oap.server.library.pprof.parser.PprofParser;
 
 @Data
 @NoArgsConstructor
@@ -58,15 +59,7 @@ public class FrameTreeBuilder {
     }
 
     private String getSignature(long locationId) {
-        if (locationId == 0) {
-            return "root";
-        }
-        ProfileProto.Location location = profile.getLocation((int) locationId 
- 1);
-        return location.getLineList().stream().map((line) -> {
-            ProfileProto.Function function = profile.getFunction((int) 
line.getFunctionId() - 1);
-            String functionName = profile.getStringTable((int) 
function.getName());
-            return functionName + ":" + line.getLine();
-        }).collect(Collectors.joining(";"));
+        return PprofParser.resolveSignature(locationId, profile);
     }
 
     public FrameTree build() {
diff --git 
a/oap-server/server-receiver-plugin/skywalking-profile-receiver-plugin/pom.xml 
b/oap-server/server-receiver-plugin/skywalking-profile-receiver-plugin/pom.xml
index f5f75875b5..5eb3a966e8 100644
--- 
a/oap-server/server-receiver-plugin/skywalking-profile-receiver-plugin/pom.xml
+++ 
b/oap-server/server-receiver-plugin/skywalking-profile-receiver-plugin/pom.xml
@@ -33,5 +33,11 @@
             <artifactId>skywalking-sharing-server-plugin</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <!-- Use centralized pprof parser -->
+        <dependency>
+            <groupId>org.apache.skywalking</groupId>
+            <artifactId>library-pprof-parser</artifactId>
+            <version>${project.version}</version>
+        </dependency>
     </dependencies>
 </project>
\ No newline at end of file
diff --git 
a/oap-server/server-receiver-plugin/skywalking-profile-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/profile/provider/handler/ProfileTaskServiceHandler.java
 
b/oap-server/server-receiver-plugin/skywalking-profile-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/profile/provider/handler/ProfileTaskServiceHandler.java
index 1de09417ff..e30556b03e 100644
--- 
a/oap-server/server-receiver-plugin/skywalking-profile-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/profile/provider/handler/ProfileTaskServiceHandler.java
+++ 
b/oap-server/server-receiver-plugin/skywalking-profile-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/profile/provider/handler/ProfileTaskServiceHandler.java
@@ -20,13 +20,17 @@ package 
org.apache.skywalking.oap.server.receiver.profile.provider.handler;
 
 import io.grpc.Status;
 import io.grpc.stub.StreamObserver;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 import org.apache.skywalking.apm.network.common.v3.Commands;
+import org.apache.skywalking.apm.network.language.profile.v3.GoProfileData;
 import 
org.apache.skywalking.apm.network.language.profile.v3.ProfileTaskCommandQuery;
 import 
org.apache.skywalking.apm.network.language.profile.v3.ProfileTaskFinishReport;
 import org.apache.skywalking.apm.network.language.profile.v3.ProfileTaskGrpc;
 import org.apache.skywalking.apm.network.language.profile.v3.ThreadSnapshot;
+import com.google.perftools.profiles.ProfileProto;
 import org.apache.skywalking.oap.server.core.CoreModule;
 import org.apache.skywalking.oap.server.core.analysis.IDManager;
 import org.apache.skywalking.oap.server.core.analysis.TimeBucket;
@@ -34,12 +38,16 @@ import 
org.apache.skywalking.oap.server.core.analysis.worker.RecordStreamProcess
 import org.apache.skywalking.oap.server.core.cache.ProfileTaskCache;
 import org.apache.skywalking.oap.server.core.command.CommandService;
 import 
org.apache.skywalking.oap.server.core.profiling.trace.ProfileTaskLogRecord;
+import 
org.apache.skywalking.oap.server.core.profiling.trace.ProfileLanguageType;
 import 
org.apache.skywalking.oap.server.core.profiling.trace.ProfileThreadSnapshotRecord;
 import org.apache.skywalking.oap.server.core.query.type.ProfileTask;
 import 
org.apache.skywalking.oap.server.core.query.type.ProfileTaskLogOperationType;
 import org.apache.skywalking.oap.server.library.module.ModuleManager;
 import org.apache.skywalking.oap.server.library.server.grpc.GRPCHandler;
 import org.apache.skywalking.oap.server.library.util.CollectionUtils;
+import 
org.apache.skywalking.oap.server.library.pprof.parser.PprofSegmentParser;
+import org.apache.skywalking.oap.server.library.pprof.parser.PprofParser;
+import 
org.apache.skywalking.oap.server.library.pprof.parser.PprofSegmentParser.SegmentInfo;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -105,6 +113,7 @@ public class ProfileTaskServiceHandler extends 
ProfileTaskGrpc.ProfileTaskImplBa
                 record.setSequence(snapshot.getSequence());
                 record.setStackBinary(snapshot.getStack().toByteArray());
                 
record.setTimeBucket(TimeBucket.getRecordTimeBucket(snapshot.getTime()));
+                record.setLanguage(ProfileLanguageType.JAVA); // default 
language for thread snapshots
 
                 // async storage
                 RecordStreamProcessor.getInstance().in(record);
@@ -130,6 +139,92 @@ public class ProfileTaskServiceHandler extends 
ProfileTaskGrpc.ProfileTaskImplBa
         };
     }
 
+    @Override
+    public StreamObserver<GoProfileData> 
goProfileReport(StreamObserver<Commands> responseObserver) {
+        return new StreamObserver<GoProfileData>() {
+            private ByteArrayOutputStream profileDataBuffer = new 
ByteArrayOutputStream();
+            private String currentTaskId = null;
+            
+            @Override
+            public void onNext(GoProfileData profileData) {
+                LOGGER.debug("receive go profile data: taskId='{}', 
payloadSize={}, isLast={}", 
+                           profileData.getTaskId(), 
+                           profileData.getPayload().size(), 
+                           profileData.getIsLast());
+
+                // Check if taskId is empty - this indicates a problem with Go 
agent
+                if (profileData.getTaskId() == null || 
profileData.getTaskId().isEmpty()) {
+                    LOGGER.error("Go agent sent empty taskId! This indicates a 
problem with Go agent's profile task management. " +
+                                "Please check Go agent's profile task creation 
and task.TaskID assignment.");
+                    return;
+                }
+
+                // Reset state if this is a new task
+                if (currentTaskId == null || 
!currentTaskId.equals(profileData.getTaskId())) {
+                    currentTaskId = profileData.getTaskId();
+                    profileDataBuffer.reset();
+                    LOGGER.debug("Starting new task: {}", currentTaskId);
+                }
+
+                // Collect profile data
+                try {
+                    
profileDataBuffer.write(profileData.getPayload().toByteArray());
+                } catch (IOException e) {
+                    LOGGER.error("Failed to write Go profile data", e);
+                    return;
+                }
+
+                // If this is the last data chunk, parse and store
+                if (profileData.getIsLast()) {
+                    try {
+                        // Parse Go profile data via library-pprof-parser 
(auto-detect gzip)
+                        ProfileProto.Profile profile = 
PprofParser.parseProfile(profileDataBuffer.toByteArray());
+                        List<SegmentInfo> segments = 
PprofSegmentParser.parseSegments(profile);
+
+                        // Log parsed segments briefly for troubleshooting
+                        if (CollectionUtils.isEmpty(segments)) {
+                            LOGGER.debug("Parsed Go profile has no segments. 
taskId={}, hint=check labels segment_id/trace_id", currentTaskId);
+                        }
+
+                        // Store ProfileThreadSnapshotRecord for each segment
+                        for (SegmentInfo segmentInfo : segments) {
+                            storeGoProfileSegment(segmentInfo, currentTaskId, 
profile);
+                        }
+
+                        // Analyzer preview removed to reduce log noise after 
verification
+
+                        LOGGER.info("Processed Go profile data: taskId={}, 
segments={}", currentTaskId, segments.size());
+                        
+                    } catch (Exception e) {
+                        LOGGER.error("Failed to parse Go profile data for 
task: " + currentTaskId, e);
+                    } finally {
+                        // Reset state
+                        profileDataBuffer.reset();
+                        currentTaskId = null;
+                    }
+                }
+            }
+
+            @Override
+            public void onError(Throwable throwable) {
+                Status status = Status.fromThrowable(throwable);
+                if (Status.CANCELLED.getCode() == status.getCode()) {
+                    if (LOGGER.isDebugEnabled()) {
+                        LOGGER.debug(throwable.getMessage(), throwable);
+                    }
+                    return;
+                }
+                LOGGER.error(throwable.getMessage(), throwable);
+            }
+
+            @Override
+            public void onCompleted() {
+                responseObserver.onNext(Commands.newBuilder().build());
+                responseObserver.onCompleted();
+            }
+        };
+    }
+
     @Override
     public void reportTaskFinish(ProfileTaskFinishReport request, 
StreamObserver<Commands> responseObserver) {
         // query task from cache, set log time bucket need it
@@ -160,4 +255,55 @@ public class ProfileTaskServiceHandler extends 
ProfileTaskGrpc.ProfileTaskImplBa
         RecordStreamProcessor.getInstance().in(logRecord);
     }
 
+
+    
+    
+
+    /**
+     * Store Go profile segment - create a filtered pprof containing only 
samples for this segment
+     */
+    private void storeGoProfileSegment(SegmentInfo segmentInfo, String taskId, 
ProfileProto.Profile originalProfile) {
+        try {
+            // Create a filtered pprof profile containing only samples for 
this segment
+            ProfileProto.Profile.Builder filteredProfileBuilder = 
originalProfile.toBuilder();
+            filteredProfileBuilder.clearSample();
+            
+            // Add only samples that belong to this segment
+            for (ProfileProto.Sample sample : originalProfile.getSampleList()) 
{
+                String sampleSegmentId = 
PprofSegmentParser.extractSegmentIdFromLabels(sample.getLabelList(), 
originalProfile.getStringTableList());
+                if (segmentInfo.getSegmentId().equals(sampleSegmentId)) {
+                    filteredProfileBuilder.addSample(sample);
+                }
+            }
+            
+            ProfileProto.Profile filteredProfile = 
filteredProfileBuilder.build();
+            byte[] filteredPprofData = filteredProfile.toByteArray();
+            
+            // Create ProfileThreadSnapshotRecord for this segment
+            ProfileThreadSnapshotRecord record = new 
ProfileThreadSnapshotRecord();
+            record.setTaskId(taskId);
+            record.setSegmentId(segmentInfo.getSegmentId()); // Use real 
segmentId
+            long dumpTimeMs = originalProfile.getTimeNanos() > 0 ? 
originalProfile.getTimeNanos() / 1_000_000L : System.currentTimeMillis();
+            record.setDumpTime(dumpTimeMs);
+            record.setSequence(0); // Each segment has only one record
+            record.setLanguage(ProfileLanguageType.GO); // mark as Go profile 
data
+            
+            // Store filtered pprof data containing only this segment's samples
+            record.setStackBinary(filteredPprofData);
+            record.setTimeBucket(TimeBucket.getRecordTimeBucket(dumpTimeMs));
+            
+            LOGGER.info("About to store Go profile snapshot: taskId={}, 
segmentId={}, dumpTime={}, timeBucket={}, sequence={}, language={}, 
filteredDataSize={}, samples={}",
+                record.getTaskId(), record.getSegmentId(), 
record.getDumpTime(), record.getTimeBucket(), 
+                record.getSequence(), record.getLanguage(), 
filteredPprofData.length, filteredProfile.getSampleCount());
+            
+            // Store to database
+            RecordStreamProcessor.getInstance().in(record);
+            LOGGER.info("Stored Go profile snapshot: taskId={}, segmentId={}, 
dumpTime={}, sequence={}, language={}",
+                record.getTaskId(), record.getSegmentId(), 
record.getDumpTime(), record.getSequence(), record.getLanguage());
+                
+        } catch (Exception e) {
+            LOGGER.error("Failed to store Go profile segment: segmentId={}, 
taskId={}", segmentInfo.getSegmentId(), taskId, e);
+        }
+    }
+
 }
diff --git 
a/oap-server/server-storage-plugin/storage-banyandb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/banyandb/BanyanDBConverter.java
 
b/oap-server/server-storage-plugin/storage-banyandb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/banyandb/BanyanDBConverter.java
index c4dfd2491d..24256e0dae 100644
--- 
a/oap-server/server-storage-plugin/storage-banyandb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/banyandb/BanyanDBConverter.java
+++ 
b/oap-server/server-storage-plugin/storage-banyandb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/banyandb/BanyanDBConverter.java
@@ -31,6 +31,7 @@ import org.apache.skywalking.banyandb.v1.client.TraceWrite;
 import 
org.apache.skywalking.banyandb.v1.client.grpc.exception.BanyanDBException;
 import org.apache.skywalking.banyandb.v1.client.metadata.Serializable;
 import org.apache.skywalking.oap.server.core.analysis.Layer;
+import 
org.apache.skywalking.oap.server.core.profiling.trace.ProfileLanguageType;
 import org.apache.skywalking.oap.server.core.analysis.TimeBucket;
 import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
 import org.apache.skywalking.oap.server.core.analysis.record.Record;
@@ -283,6 +284,9 @@ public class BanyanDBConverter {
             return TagAndValue.stringTagValue(((StorageDataComplexObject<?>) 
value).toStorageData());
         } else if (Layer.class.equals(clazz)) {
             return TagAndValue.longTagValue(((Integer) value).longValue());
+        } else if (ProfileLanguageType.class.equals(clazz)) {
+            // Mirror Layer handling: value is provided as Integer (enum 
ordinal/value)
+            return TagAndValue.longTagValue(((Integer) value).longValue());
         } else if (JsonObject.class.equals(clazz)) {
             return TagAndValue.stringTagValue((String) value);
         } else if (byte[].class.equals(clazz)) {
@@ -302,6 +306,11 @@ public class BanyanDBConverter {
             return TagAndValue.binaryFieldValue(ByteUtil.double2Bytes((double) 
value));
         } else if (StorageDataComplexObject.class.isAssignableFrom(clazz)) {
             return TagAndValue.stringFieldValue(((StorageDataComplexObject<?>) 
value).toStorageData());
+        } else if (Layer.class.equals(clazz)) {
+            return TagAndValue.longFieldValue(((Integer) value).longValue());
+        } else if (ProfileLanguageType.class.equals(clazz)) {
+            // Mirror Layer handling: value is provided as Integer (enum 
ordinal/value)
+            return TagAndValue.longFieldValue(((Integer) value).longValue());
         }
         throw new IllegalStateException(clazz.getSimpleName() + " is not 
supported");
     }
diff --git 
a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/ColumnTypeEsMapping.java
 
b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/ColumnTypeEsMapping.java
index 914154ea40..02fd400181 100644
--- 
a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/ColumnTypeEsMapping.java
+++ 
b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/ColumnTypeEsMapping.java
@@ -24,12 +24,13 @@ import java.lang.reflect.Type;
 import java.util.List;
 import org.apache.skywalking.oap.server.core.analysis.Layer;
 import 
org.apache.skywalking.oap.server.core.storage.model.ElasticSearchExtension;
+import 
org.apache.skywalking.oap.server.core.profiling.trace.ProfileLanguageType;
 import 
org.apache.skywalking.oap.server.core.storage.type.StorageDataComplexObject;
 
 public class ColumnTypeEsMapping {
 
     public String transform(Class<?> type, Type genericType, int length, 
boolean storageOnly, final ElasticSearchExtension elasticSearchExtension) {
-        if (Integer.class.equals(type) || int.class.equals(type) || 
Layer.class.equals(type)) {
+        if (Integer.class.equals(type) || int.class.equals(type) || 
Layer.class.equals(type) || ProfileLanguageType.class.equals(type)) {
             return "integer";
         } else if (Long.class.equals(type) || long.class.equals(type)) {
             return "long";
diff --git 
a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/JDBCTableInstaller.java
 
b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/JDBCTableInstaller.java
index ad5f7c860d..57079de7ce 100644
--- 
a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/JDBCTableInstaller.java
+++ 
b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/JDBCTableInstaller.java
@@ -26,6 +26,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.oap.server.core.analysis.DownSampling;
 import org.apache.skywalking.oap.server.core.analysis.Layer;
 import org.apache.skywalking.oap.server.core.analysis.TimeBucket;
+import 
org.apache.skywalking.oap.server.core.profiling.trace.ProfileLanguageType;
 import org.apache.skywalking.oap.server.core.storage.StorageData;
 import org.apache.skywalking.oap.server.core.storage.model.ColumnName;
 import org.apache.skywalking.oap.server.core.storage.model.Model;
@@ -111,7 +112,7 @@ public class JDBCTableInstaller extends ModelInstaller {
 
     protected String getColumnDefinition(ModelColumn column, Class<?> type, 
Type genericType) {
         final String storageName = column.getColumnName().getStorageName();
-        if (Integer.class.equals(type) || int.class.equals(type) || 
Layer.class.equals(type)) {
+        if (Integer.class.equals(type) || int.class.equals(type) || 
Layer.class.equals(type) || ProfileLanguageType.class.equals(type)) {
             return storageName + " INT";
         } else if (Long.class.equals(type) || long.class.equals(type)) {
             return storageName + " BIGINT";
diff --git 
a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/postgresql/PostgreSQLTableInstaller.java
 
b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/postgresql/PostgreSQLTableInstaller.java
index fd76087b4b..c0a775b3c2 100644
--- 
a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/postgresql/PostgreSQLTableInstaller.java
+++ 
b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/postgresql/PostgreSQLTableInstaller.java
@@ -29,6 +29,7 @@ import 
org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCTableInst
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
 import java.util.List;
+import 
org.apache.skywalking.oap.server.core.profiling.trace.ProfileLanguageType;
 
 public class PostgreSQLTableInstaller extends JDBCTableInstaller {
     public PostgreSQLTableInstaller(Client client, ModuleManager 
moduleManager) {
@@ -48,7 +49,7 @@ public class PostgreSQLTableInstaller extends 
JDBCTableInstaller {
     @Override
     protected String getColumnDefinition(ModelColumn column, Class<?> type, 
Type genericType) {
         final String storageName = column.getColumnName().getStorageName();
-        if (Integer.class.equals(type) || int.class.equals(type) || 
Layer.class.equals(type)) {
+        if (Integer.class.equals(type) || int.class.equals(type) || 
Layer.class.equals(type) || ProfileLanguageType.class.equals(type)) {
             return storageName + " INT";
         } else if (Long.class.equals(type) || long.class.equals(type)) {
             return storageName + " BIGINT";
diff --git a/test/e2e-v2/cases/go/service/e2e.go 
b/test/e2e-v2/cases/go/service/e2e.go
index 833edab181..febb593d8c 100644
--- a/test/e2e-v2/cases/go/service/e2e.go
+++ b/test/e2e-v2/cases/go/service/e2e.go
@@ -63,5 +63,25 @@ func main() {
                context.String(200, "Nobody cares me.")
        })
 
+       engine.Handle("GET", "/profile", func(context *gin.Context) {
+               log.Printf("=== /profile endpoint called ===")
+               log.Printf("Starting profiling work...")
+               doWork()
+               log.Printf("Profiling work completed")
+               context.String(200, "Profiling completed")
+       })
+
        _ = engine.Run(":8080")
 }
+
+func doWork() {
+       log.Printf("doWork() started")
+       start := time.Now()
+       for time.Since(start) < 10*time.Second {
+               _ = 1
+               for i := 0; i < 1e6; i++ {
+                       _ = i * i
+               }
+       }
+       log.Printf("doWork() completed after %v", time.Since(start))
+}
\ No newline at end of file
diff --git a/test/e2e-v2/cases/go/service/go.mod 
b/test/e2e-v2/cases/go/service/go.mod
index 1e2b1db6e3..2197662dbd 100644
--- a/test/e2e-v2/cases/go/service/go.mod
+++ b/test/e2e-v2/cases/go/service/go.mod
@@ -61,5 +61,4 @@ require (
        google.golang.org/grpc v1.55.0 // indirect
        google.golang.org/protobuf v1.34.1 // indirect
        gopkg.in/yaml.v3 v3.0.1 // indirect
-       skywalking.apache.org/repo/goapi v0.0.0-20230314034821-0c5a44bb767a // 
indirect
 )
diff --git a/test/e2e-v2/cases/profiling/trace/go/docker-compose.yml 
b/test/e2e-v2/cases/profiling/trace/go/docker-compose.yml
new file mode 100644
index 0000000000..d1df1d9c80
--- /dev/null
+++ b/test/e2e-v2/cases/profiling/trace/go/docker-compose.yml
@@ -0,0 +1,65 @@
+# 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.
+
+version: '2.1'
+
+services:
+  oap:
+    extends:
+      file: ../../../../script/docker-compose/base-compose.yml
+      service: oap
+    ports:
+      - 12800
+    networks:
+      - e2e
+
+  banyandb:
+    extends:
+      file: ../../../../script/docker-compose/base-compose.yml
+      service: banyandb
+    ports:
+      - 17912
+    networks:
+      - e2e  
+
+  go-service:
+    build:
+      context: ../../../go/service
+      dockerfile: Dockerfile
+      args:
+        - SW_AGENT_GO_COMMIT=${SW_AGENT_GO_COMMIT}
+    networks:
+      - e2e
+    expose:
+      - 8080
+    ports:
+      - 8080
+    environment:
+      SW_AGENT_NAME: go-service
+      SW_AGENT_REPORTER_GRPC_BACKEND_SERVICE: oap:11800
+      SW_AGENT_REPORTER_GRPC_PROFILE_FETCH_INTERVAL: 1
+      SW_AGENT_COLLECTOR_GET_PROFILE_TASK_INTERVAL: 1
+      SW_AGENT_COLLECTOR_GET_AGENT_DYNAMIC_CONFIG_INTERVAL: 1
+    depends_on:
+      oap:
+        condition: service_healthy
+    healthcheck:
+      test: ["CMD", "sh", "-c", "nc -z 127.0.0.1 8080"]
+      interval: 5s
+      timeout: 60s
+      retries: 120
+
+networks:
+  e2e:
diff --git a/test/e2e-v2/cases/profiling/trace/go/e2e.yaml 
b/test/e2e-v2/cases/profiling/trace/go/e2e.yaml
new file mode 100644
index 0000000000..326893f517
--- /dev/null
+++ b/test/e2e-v2/cases/profiling/trace/go/e2e.yaml
@@ -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.
+
+
+setup:
+  env: compose
+  file: docker-compose.yml
+  timeout: 20m
+  init-system-environment: ../../../../script/env
+  steps:
+    - name: set PATH
+      command: export PATH=/tmp/skywalking-infra-e2e/bin:$PATH
+    - name: install yq
+      command: bash test/e2e-v2/script/prepare/setup-e2e-shell/install.sh yq
+    - name: install swctl
+      command: bash test/e2e-v2/script/prepare/setup-e2e-shell/install.sh swctl
+
+trigger:
+  action: http
+  interval: 3s
+  times: 60
+  url: http://${go-service_host}:${go-service_8080}/profile
+  method: GET
+  
+verify:
+  retry:
+    count: 20
+    interval: 3s
+  cases:
+    # create profiling task for Go service
+    - query: |
+        swctl --display yaml 
--base-url=http://${oap_host}:${oap_12800}/graphql \
+          profiling trace create --service-name=go-service \
+            --endpoint-name=GET:/profile \
+            --start-time=-1 \
+            --duration=1 --min-duration-threshold=1000 \
+            --dump-period=500 --max-sampling-count=3
+      expected: expected/profile-create.yml
+
+    # profiling list notified: sleep to wait agent notices and query profiling 
list
+    - query: sleep 3 && swctl --display yaml 
--base-url=http://${oap_host}:${oap_12800}/graphql profiling trace list 
-service-name=go-service --endpoint-name=GET:/profile
+      expected: expected/profile-list-notified.yml
+
+    # profiling list finished
+    - query: |
+        sleep 3;
+        go_host=$(printenv go-service_host || printenv go_service_host)
+        go_port=$(printenv go-service_8080 || printenv go_service_8080)
+        curl -s -XGET http://$go_host:$go_port/profile > /dev/null;
+        sleep 30;
+        swctl --display yaml 
--base-url=http://${oap_host}:${oap_12800}/graphql profiling trace list 
-service-name=go-service --endpoint-name=GET:/profile
+      expected: expected/profile-list-finished.yml
+
+    # profiled segment list
+    - query: |
+        sleep 30;
+        swctl --display yaml 
--base-url=http://${oap_host}:${oap_12800}/graphql profiling trace segment-list 
--task-id=$( \
+          swctl --display yaml 
--base-url=http://${oap_host}:${oap_12800}/graphql profiling trace list 
-service-name=go-service --endpoint-name=GET:/profile | yq e '.[0].id' - \
+        )
+      expected: expected/profile-segment-list.yml
+
+    # query profiled segment analyze
+    - query: |
+        segmentid=$( \
+          swctl --display yaml 
--base-url=http://${oap_host}:${oap_12800}/graphql profiling trace segment-list 
--task-id=$( \
+            swctl --display yaml 
--base-url=http://${oap_host}:${oap_12800}/graphql profiling trace list 
-service-name=go-service --endpoint-name=GET:/profile | yq e '.[0].id' - \
+          ) | yq e '.[0].spans.[] | select(.spanid == 0) | .segmentid' - \
+        );
+        start=$(
+          swctl --display yaml 
--base-url=http://${oap_host}:${oap_12800}/graphql profiling trace segment-list 
--task-id=$( \
+            swctl --display yaml 
--base-url=http://${oap_host}:${oap_12800}/graphql profiling trace list 
-service-name=go-service --endpoint-name=GET:/profile | yq e '.[0].id' - \
+          ) | yq e '.[0].spans.[] | select(.spanid == 0) | .starttime' - \
+        );
+        end=$(
+          swctl --display yaml 
--base-url=http://${oap_host}:${oap_12800}/graphql profiling trace segment-list 
--task-id=$( \
+            swctl --display yaml 
--base-url=http://${oap_host}:${oap_12800}/graphql profiling trace list 
-service-name=go-service --endpoint-name=GET:/profile | yq e '.[0].id' - \
+          ) | yq e '.[0].spans.[] | select(.spanid == 0) | .endtime' - \
+        );
+        swctl --display yaml 
--base-url=http://${oap_host}:${oap_12800}/graphql profiling trace analysis 
--segment-ids=$segmentid --time-ranges=$(echo $start"-"$end)
+      expected: expected/profile-segment-analyze.yml
\ No newline at end of file
diff --git a/test/e2e-v2/cases/profiling/trace/go/expected/profile-create.yml 
b/test/e2e-v2/cases/profiling/trace/go/expected/profile-create.yml
new file mode 100644
index 0000000000..8f89323654
--- /dev/null
+++ b/test/e2e-v2/cases/profiling/trace/go/expected/profile-create.yml
@@ -0,0 +1,17 @@
+# 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.
+
+id: {{ notEmpty .id }}
+errorreason: null
diff --git 
a/test/e2e-v2/cases/profiling/trace/go/expected/profile-list-finished.yml 
b/test/e2e-v2/cases/profiling/trace/go/expected/profile-list-finished.yml
new file mode 100644
index 0000000000..61a8437407
--- /dev/null
+++ b/test/e2e-v2/cases/profiling/trace/go/expected/profile-list-finished.yml
@@ -0,0 +1,34 @@
+# 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.
+
+  {{- contains . }}
+- id: {{ notEmpty .id }}
+  serviceid: {{ b64enc "go-service" }}.1
+  servicename: ""
+  endpointname: GET:/profile
+  starttime: {{ gt .starttime 0 }}
+  duration: 1
+  mindurationthreshold: 1000
+  dumpperiod: 500
+  maxsamplingcount: 3
+  logs:
+    {{- contains .logs }}
+    - id: {{ notEmpty .id }}
+      instanceid: {{ notEmpty .instanceid }}
+      operationtype: {{ .operationtype }}
+      instancename: ""
+      operationtime: {{ gt .operationtime 0 }}
+    {{- end }}
+  {{- end }}
diff --git 
a/test/e2e-v2/cases/profiling/trace/go/expected/profile-list-notified.yml 
b/test/e2e-v2/cases/profiling/trace/go/expected/profile-list-notified.yml
new file mode 100644
index 0000000000..61a8437407
--- /dev/null
+++ b/test/e2e-v2/cases/profiling/trace/go/expected/profile-list-notified.yml
@@ -0,0 +1,34 @@
+# 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.
+
+  {{- contains . }}
+- id: {{ notEmpty .id }}
+  serviceid: {{ b64enc "go-service" }}.1
+  servicename: ""
+  endpointname: GET:/profile
+  starttime: {{ gt .starttime 0 }}
+  duration: 1
+  mindurationthreshold: 1000
+  dumpperiod: 500
+  maxsamplingcount: 3
+  logs:
+    {{- contains .logs }}
+    - id: {{ notEmpty .id }}
+      instanceid: {{ notEmpty .instanceid }}
+      operationtype: {{ .operationtype }}
+      instancename: ""
+      operationtime: {{ gt .operationtime 0 }}
+    {{- end }}
+  {{- end }}
diff --git 
a/test/e2e-v2/cases/profiling/trace/go/expected/profile-segment-analyze.yml 
b/test/e2e-v2/cases/profiling/trace/go/expected/profile-segment-analyze.yml
new file mode 100644
index 0000000000..1e8d0167ce
--- /dev/null
+++ b/test/e2e-v2/cases/profiling/trace/go/expected/profile-segment-analyze.yml
@@ -0,0 +1,32 @@
+# 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.
+
+tip: null
+trees:
+  {{- if .trees }}
+    {{- contains .trees }}
+    - elements:
+      {{- contains .elements }}
+      - id: "{{ notEmpty .id }}"
+        parentid: "{{ notEmpty .parentid }}"
+        codesignature: "{{ notEmpty .codesignature }}"
+        duration: {{ gt .duration 0 }}
+        durationchildexcluded: 0
+        count: {{ gt .count 0 }}
+      {{- end }}
+    {{- end }}
+    {{- else }}
+    []
+    {{- end }}
diff --git 
a/test/e2e-v2/cases/profiling/trace/go/expected/profile-segment-list.yml 
b/test/e2e-v2/cases/profiling/trace/go/expected/profile-segment-list.yml
new file mode 100644
index 0000000000..14103b5b29
--- /dev/null
+++ b/test/e2e-v2/cases/profiling/trace/go/expected/profile-segment-list.yml
@@ -0,0 +1,52 @@
+# 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.
+
+{{- contains . }}
+- duration: {{ gt .duration 0 }}
+  endpointnames:
+    - GET:/profile
+  instanceid: {{ notEmpty .instanceid }}
+  instancename: {{ notEmpty .instancename }}
+  spans:
+    {{- contains .spans }}
+    - component: Gin
+      endpointname: GET:/profile
+      endtime: {{ gt .endtime 0 }}
+      iserror: false
+      layer: Http
+      logs: []
+      parentspanid: -1
+      peer: ""
+      profiled: true
+      refs: []
+      segmentid: {{ notEmpty .segmentid }}
+      servicecode: go-service
+      serviceinstancename: {{ notEmpty .serviceinstancename }}
+      spanid: 0
+      starttime: {{ gt .starttime 0 }}
+      tags:
+        {{- contains .tags }}
+        - key: http.method
+          value: GET
+        - key: url
+          value: {{ notEmpty .value }}
+        - key: status_code
+          value: "200"
+        {{- end }}
+      type: Entry
+    {{- end }}
+  start: {{ notEmpty .start }}
+  traceid: {{ notEmpty .traceid }}
+{{- end }}

Reply via email to