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;