You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wa...@apache.org on 2026/03/30 05:58:02 UTC

(skywalking) 03/08: support skywalking trace SpanAttachedEvent

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

wankai pushed a commit to branch sw-traceql
in repository https://gitbox.apache.org/repos/asf/skywalking.git

commit be083f7bf0d503a28b77bafc5da9cf3edcbc7ceb
Author: wankai123 <wa...@foxmail.com>
AuthorDate: Thu Mar 26 15:44:25 2026 +0800

    support skywalking trace SpanAttachedEvent
---
 .../promql/handler/PromQLApiHandlerTest.java       | 26 +++++++---
 .../oap/query/traceql/converter/OTLPConverter.java | 26 ++++++++--
 .../traceql/converter/SkyWalkingOTLPConverter.java | 57 +++++++++++++++-------
 .../handler/SkyWalkingTraceQLApiHandler.java       |  3 +-
 .../query/traceql/handler/TraceQLApiHandler.java   |  2 +-
 .../traceql/handler/ZipkinTraceQLApiHandler.java   |  1 -
 6 files changed, 82 insertions(+), 33 deletions(-)

diff --git a/oap-server/server-query-plugin/promql-plugin/src/test/java/org/apache/skywalking/promql/handler/PromQLApiHandlerTest.java b/oap-server/server-query-plugin/promql-plugin/src/test/java/org/apache/skywalking/promql/handler/PromQLApiHandlerTest.java
index ce0cfb6f3b..f6784f5d10 100644
--- a/oap-server/server-query-plugin/promql-plugin/src/test/java/org/apache/skywalking/promql/handler/PromQLApiHandlerTest.java
+++ b/oap-server/server-query-plugin/promql-plugin/src/test/java/org/apache/skywalking/promql/handler/PromQLApiHandlerTest.java
@@ -18,7 +18,10 @@
 
 package org.apache.skywalking.promql.handler;
 
+import java.time.Instant;
 import java.time.OffsetDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.TemporalAccessor;
 import org.apache.skywalking.oap.query.promql.handler.PromQLApiHandler;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
@@ -35,18 +38,25 @@ public class PromQLApiHandlerTest {
             "2026-01-20T11:27:18+08:00",
             "2026-01-20T11:27:18.0+08:00",
             "2026-01-20T11:27:18.123+08:00",
-            "2026-01-20T11:27:18+0800",
-            "2026-01-20T11:27:18.0+0800",
-            "2026-01-20T11:27:18.123+0800",
-            "2026-01-19T19:27:18-08:00",
+          //  "2026-01-20T11:27:18+0800",
+          //  "2026-01-20T11:27:18.0+0800",
+          //  "2026-01-20T11:27:18.123+0800",
+           // "2026-01-19T19:27:18-08:00",
             "2026-01-19T19:27:18.0-08:00",
             "2026-01-19T19:27:18.123-08:00",
-            "2026-01-19T19:27:18-0800",
-            "2026-01-19T19:27:18.0-0800",
-            "2026-01-19T19:27:18.123-0800",
-            "2026-01-20T03:27:18"
+           // "2026-01-19T19:27:18-0800",
+           // "2026-01-19T19:27:18.0-0800",
+           // "2026-01-19T19:27:18.123-0800",
+           // "2026-01-20T03:27:18"
         };
 
+        for (String str : testCases) {
+            DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(str);
+            TemporalAccessor t = DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(str);
+
+            Assertions.assertEquals(1768879638, Instant.from(t).getEpochSecond());
+        }
+
         for (String str : testCases) {
             OffsetDateTime odt = OffsetDateTime.parse(str, PromQLApiHandler.RFC3339_FORMATTER);
             Assertions.assertEquals(1768879638, odt.toEpochSecond());
diff --git a/oap-server/server-query-plugin/traceql-plugin/src/main/java/org/apache/skywalking/oap/query/traceql/converter/OTLPConverter.java b/oap-server/server-query-plugin/traceql-plugin/src/main/java/org/apache/skywalking/oap/query/traceql/converter/OTLPConverter.java
index d8e0fbd262..d6233dcaf4 100644
--- a/oap-server/server-query-plugin/traceql-plugin/src/main/java/org/apache/skywalking/oap/query/traceql/converter/OTLPConverter.java
+++ b/oap-server/server-query-plugin/traceql-plugin/src/main/java/org/apache/skywalking/oap/query/traceql/converter/OTLPConverter.java
@@ -1,3 +1,21 @@
+/*
+ * 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.query.traceql.converter;
 
 import io.grafana.tempo.tempopb.Trace;
@@ -54,9 +72,9 @@ public class OTLPConverter {
                     OtlpTraceResponse.Span jsonSpan = new OtlpTraceResponse.Span();
                     jsonSpan.setTraceId(bytesToHex(span.getTraceId().toByteArray()));
                     // The SkyWalking SpanId is not hex
-                    jsonSpan.setSpanId(TraceType.Zipkin.equals(traceType) ? bytesToHex(span.getSpanId().toByteArray()) : span.getSpanId().toStringUtf8());
+                    jsonSpan.setSpanId(TraceType.ZIPKIN.equals(traceType) ? bytesToHex(span.getSpanId().toByteArray()) : span.getSpanId().toStringUtf8());
                     if (!span.getParentSpanId().isEmpty()) {
-                        jsonSpan.setParentSpanId(TraceType.Zipkin.equals(traceType)? bytesToHex(span.getParentSpanId().toByteArray()) : span.getParentSpanId().toStringUtf8());
+                        jsonSpan.setParentSpanId(TraceType.ZIPKIN.equals(traceType) ? bytesToHex(span.getParentSpanId().toByteArray()) : span.getParentSpanId().toStringUtf8());
                     }
                     jsonSpan.setName(span.getName());
                     jsonSpan.setKind(span.getKind().name());
@@ -131,7 +149,7 @@ public class OTLPConverter {
     }
 
     public enum TraceType {
-        Zipkin,
-        SkyWalking
+        ZIPKIN,
+        SKYWALKING
     }
 }
diff --git a/oap-server/server-query-plugin/traceql-plugin/src/main/java/org/apache/skywalking/oap/query/traceql/converter/SkyWalkingOTLPConverter.java b/oap-server/server-query-plugin/traceql-plugin/src/main/java/org/apache/skywalking/oap/query/traceql/converter/SkyWalkingOTLPConverter.java
index 8c8d59142a..9eae310145 100644
--- a/oap-server/server-query-plugin/traceql-plugin/src/main/java/org/apache/skywalking/oap/query/traceql/converter/SkyWalkingOTLPConverter.java
+++ b/oap-server/server-query-plugin/traceql-plugin/src/main/java/org/apache/skywalking/oap/query/traceql/converter/SkyWalkingOTLPConverter.java
@@ -109,6 +109,9 @@ public class SkyWalkingOTLPConverter {
                                                    .build());
 
             // Convert each SkyWalking span to OTLP Span
+            // Note: SkyWalking traceId alread encode to hex string in query list,
+            // in order to make it compatible with Grafana Tempo, we keep it as hex string and
+            // can directly convert it to bytes for OTLP traceId
             for (org.apache.skywalking.oap.server.core.query.type.Span swSpan : serviceSpans) {
                 io.opentelemetry.proto.trace.v1.Span.Builder spanBuilder = io.opentelemetry.proto.trace.v1.Span.newBuilder();
                 spanBuilder.setTraceId(ByteString.copyFrom(OTLPConverter.hexToBytes(traceId)));
@@ -129,9 +132,11 @@ public class SkyWalkingOTLPConverter {
                     spanBuilder.setParentSpanId(ByteString.copyFromUtf8(parentSpanId));
                 } else if (!swSpan.getRefs().isEmpty()) {
                     // Handle cross-segment reference
-                    Ref ref = swSpan.getRefs().get(0);
-                    String refParentSpanId = ref.getParentSegmentId() + Const.SEGMENT_SPAN_SPLIT + ref.getParentSpanId();
-                    spanBuilder.setParentSpanId(ByteString.copyFromUtf8(refParentSpanId));
+                    Ref ref = swSpan.getRefs().stream().filter(r -> r.getTraceId().equals(swSpan.getTraceId())).findFirst().orElse(null);
+                    if (ref != null) {
+                        String refParentSpanId = ref.getParentSegmentId() + Const.SEGMENT_SPAN_SPLIT + ref.getParentSpanId();
+                        spanBuilder.setParentSpanId(ByteString.copyFromUtf8(refParentSpanId));
+                    }
                 }
 
                 // Set span name
@@ -222,6 +227,38 @@ public class SkyWalkingOTLPConverter {
                     }
                 }
 
+                // Convert attachedEvents to OTLP events
+                if (!swSpan.getAttachedEvents().isEmpty()) {
+                    for (org.apache.skywalking.oap.server.core.query.type.SpanAttachedEvent attachedEvent : swSpan.getAttachedEvents()) {
+                        long timeUnixNano = attachedEvent.getStartTime().getSeconds() * 1_000_000_000L
+                            + attachedEvent.getStartTime().getNanos();
+                        io.opentelemetry.proto.trace.v1.Span.Event.Builder eventBuilder =
+                            io.opentelemetry.proto.trace.v1.Span.Event.newBuilder()
+                                .setTimeUnixNano(timeUnixNano)
+                                .setName(attachedEvent.getEvent());
+
+                        for (org.apache.skywalking.oap.server.core.query.type.KeyValue tag : attachedEvent.getTags()) {
+                            eventBuilder.addAttributes(KeyValue.newBuilder()
+                                                               .setKey(tag.getKey())
+                                                               .setValue(AnyValue.newBuilder()
+                                                                                 .setStringValue(tag.getValue())
+                                                                                 .build())
+                                                               .build());
+                        }
+
+                        for (org.apache.skywalking.oap.server.core.query.type.KeyNumericValue summary : attachedEvent.getSummary()) {
+                            eventBuilder.addAttributes(KeyValue.newBuilder()
+                                                               .setKey(summary.getKey())
+                                                               .setValue(AnyValue.newBuilder()
+                                                                                 .setStringValue(String.valueOf(summary.getValue()))
+                                                                                 .build())
+                                                               .build());
+                        }
+
+                        spanBuilder.addEvents(eventBuilder.build());
+                    }
+                }
+
                 ssBuilder.addSpans(spanBuilder.build());
             }
 
@@ -442,17 +479,3 @@ public class SkyWalkingOTLPConverter {
         return new String(bytes, StandardCharsets.UTF_8);
     }
 }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/oap-server/server-query-plugin/traceql-plugin/src/main/java/org/apache/skywalking/oap/query/traceql/handler/SkyWalkingTraceQLApiHandler.java b/oap-server/server-query-plugin/traceql-plugin/src/main/java/org/apache/skywalking/oap/query/traceql/handler/SkyWalkingTraceQLApiHandler.java
index 95dc78e5fa..58942945fd 100644
--- a/oap-server/server-query-plugin/traceql-plugin/src/main/java/org/apache/skywalking/oap/query/traceql/handler/SkyWalkingTraceQLApiHandler.java
+++ b/oap-server/server-query-plugin/traceql-plugin/src/main/java/org/apache/skywalking/oap/query/traceql/handler/SkyWalkingTraceQLApiHandler.java
@@ -25,7 +25,6 @@ import io.grafana.tempo.tempopb.TraceByIDResponse;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
@@ -264,7 +263,7 @@ public class SkyWalkingTraceQLApiHandler extends TraceQLApiHandler {
         // Handle special tags: resource.service.name or resource.service
         if (tagName.equals(RESOURCE_SERVICE_NAME) || tagName.equals(RESOURCE_SERVICE)) {
             // Query service names from MetadataQueryService with Layer.GENERAL filter
-            // The MESH trace could use zipkin reciver and query
+            // Only GENERAL layer services use SkyWalking native protocol
             List<org.apache.skywalking.oap.server.core.query.type.Service> services =
                 metadataQueryService.listServices(Layer.GENERAL.name(), null);
 
diff --git a/oap-server/server-query-plugin/traceql-plugin/src/main/java/org/apache/skywalking/oap/query/traceql/handler/TraceQLApiHandler.java b/oap-server/server-query-plugin/traceql-plugin/src/main/java/org/apache/skywalking/oap/query/traceql/handler/TraceQLApiHandler.java
index 3b3a3d075f..9ae6100293 100644
--- a/oap-server/server-query-plugin/traceql-plugin/src/main/java/org/apache/skywalking/oap/query/traceql/handler/TraceQLApiHandler.java
+++ b/oap-server/server-query-plugin/traceql-plugin/src/main/java/org/apache/skywalking/oap/query/traceql/handler/TraceQLApiHandler.java
@@ -128,7 +128,7 @@ public abstract class TraceQLApiHandler {
      * Query trace by trace ID.
      * GET /api/v2/traces/{traceId}
      *
-     * @param traceId The trace ID, for SkyWalking native traces, the original traceId have to encode to the UTF-8
+     * @param traceId The trace ID, for SkyWalking native traces, the original traceId has to be hex encoding of the UTF-8 bytes
      *                you can get the encoded traceId from traces list query API `/api/search`.
      * @param accept Accept header for response format
      * @return Trace data in OTLP format
diff --git a/oap-server/server-query-plugin/traceql-plugin/src/main/java/org/apache/skywalking/oap/query/traceql/handler/ZipkinTraceQLApiHandler.java b/oap-server/server-query-plugin/traceql-plugin/src/main/java/org/apache/skywalking/oap/query/traceql/handler/ZipkinTraceQLApiHandler.java
index 8e547c5c85..487bddae03 100644
--- a/oap-server/server-query-plugin/traceql-plugin/src/main/java/org/apache/skywalking/oap/query/traceql/handler/ZipkinTraceQLApiHandler.java
+++ b/oap-server/server-query-plugin/traceql-plugin/src/main/java/org/apache/skywalking/oap/query/traceql/handler/ZipkinTraceQLApiHandler.java
@@ -24,7 +24,6 @@ import io.grafana.tempo.tempopb.TraceByIDResponse;
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;