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 0b2d53617b8b2edd623d4d3e692701e5067f8298
Author: wankai123 <[email protected]>
AuthorDate: Mon Mar 30 13:57:18 2026 +0800

    add time range and instance tag
---
 .../handler/SkyWalkingTraceQLApiHandler.java       | 47 ++++++++++++++++++++-
 .../query/traceql/handler/TraceQLApiHandler.java   |  6 ++-
 .../traceql/handler/ZipkinTraceQLApiHandler.java   |  2 +
 .../oap/query/traceql/rt/TraceQLQueryParams.java   |  5 +++
 .../oap/query/traceql/rt/TraceQLQueryVisitor.java  | 48 ++++++++++++++--------
 5 files changed, 88 insertions(+), 20 deletions(-)

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 47a0216e63..f244662421 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
@@ -57,11 +57,14 @@ import 
org.apache.skywalking.oap.server.core.query.input.TraceQueryCondition;
 import org.apache.skywalking.oap.server.core.query.type.Endpoint;
 import org.apache.skywalking.oap.server.core.query.type.Pagination;
 import org.apache.skywalking.oap.server.core.query.type.QueryOrder;
+import org.apache.skywalking.oap.server.core.query.type.ServiceInstance;
 import org.apache.skywalking.oap.server.core.query.type.Trace;
 import org.apache.skywalking.oap.server.core.query.type.TraceState;
 import org.apache.skywalking.oap.server.core.query.type.trace.v2.TraceList;
 import org.apache.skywalking.oap.server.library.module.ModuleManager;
 import org.apache.skywalking.oap.server.library.util.StringUtil;
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
 
 /**
  * SkyWalking-native implementation of TraceQL API Handler.
@@ -95,9 +98,19 @@ public class SkyWalkingTraceQLApiHandler extends 
TraceQLApiHandler {
 
     @Override
     protected HttpResponse queryTraceImpl(String traceId,
+                                          Optional<Long> start,
+                                          Optional<Long> end,
                                           Optional<String> accept) throws 
IOException, DecoderException {
+        // If start/end are provided use them; otherwise cover the full 
historical range from 2020-01-01 00:00:00 UTC
+        final long startOf2020Sec = new DateTime(2020, 1, 1, 0, 0, 0, 
DateTimeZone.UTC).getMillis() / 1000;
+        Duration duration = buildDuration(
+            start.isPresent() ? start : Optional.of(startOf2020Sec),
+            end,
+            0L
+        );
+
         // Query SkyWalking trace by ID
-        Trace swTrace = 
traceQueryService.queryTrace(SkyWalkingOTLPConverter.decodeTraceId(traceId), 
null);
+        Trace swTrace = 
traceQueryService.queryTrace(SkyWalkingOTLPConverter.decodeTraceId(traceId), 
duration);
 
         if (swTrace == null || swTrace.getSpans().isEmpty()) {
             return HttpResponse.of(HttpStatus.NOT_FOUND);
@@ -144,6 +157,11 @@ public class SkyWalkingTraceQLApiHandler extends 
TraceQLApiHandler {
             condition.setServiceId(serviceId);
         }
 
+        if (StringUtil.isNotBlank(queryParams.getServiceInstance()) && 
StringUtil.isNotBlank(condition.getServiceId())) {
+            String instanceId = 
IDManager.ServiceInstanceID.buildId(condition.getServiceId(), 
queryParams.getServiceInstance());
+            condition.setServiceInstanceId(instanceId);
+        }
+
         // Set endpoint ID if span name is provided
         if (StringUtil.isNotBlank(queryParams.getSpanName()) && 
StringUtil.isNotBlank(condition.getServiceId())) {
             // Use IDManager to build endpoint ID
@@ -247,6 +265,7 @@ public class SkyWalkingTraceQLApiHandler extends 
TraceQLApiHandler {
         //for Grafana variables, tempo only supports label query in variables 
setting.
         TagNamesV2Response.Scope resourceScope = new 
TagNamesV2Response.Scope(SCOPE_RESOURCE);
         resourceScope.getTags().add(SERVICE);
+        resourceScope.getTags().add(INSTANCE);
         List<TagNamesV2Response.Scope> scopes = new ArrayList<>();
         scopes.add(spanScope);
         response.setScopes(scopes);
@@ -329,6 +348,32 @@ public class SkyWalkingTraceQLApiHandler extends 
TraceQLApiHandler {
                 return successResponse(new TagValuesResponse());
             }
         }
+        if (tagName.equals(RESOURCE_INSTANCE)) {
+            if (query.isPresent() && !query.get().isEmpty()) {
+                TraceQLParseResult parseResult = 
TraceQLQueryParser.extractParams(query.get());
+                if (parseResult.hasError()) {
+                    return badRequestResponse(parseResult.getErrorInfo());
+                }
+                TraceQLQueryParams traceQLParams = parseResult.getParams();
+                TagValuesResponse response = new TagValuesResponse();
+                if (StringUtil.isNotBlank(traceQLParams.getServiceName())) {
+                    String serviceId = 
IDManager.ServiceID.buildId(traceQLParams.getServiceName(), true);
+                    List<ServiceInstance> instances = 
metadataQueryService.listInstances(
+                        duration,
+                        serviceId
+
+                    );
+
+                    for (ServiceInstance instance : instances) {
+                        response.getTagValues().add(new 
TagValuesResponse.TagValue(TYPE_STRING, instance.getName()));
+                    }
+                }
+                return successResponse(response);
+            } else {
+                // Return empty list if no query provided, to avoid error as 
Grafana queries this every time when user enters the query page.
+                return successResponse(new TagValuesResponse());
+            }
+        }
         return badRequestResponse("Unsupported tag value query.");
     }
 
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 9ae6100293..09e10b1ec3 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
@@ -61,8 +61,10 @@ public abstract class TraceQLApiHandler {
     // Resource-scoped tag names
     public static final String RESOURCE_SERVICE_NAME = "resource.service.name";
     public static final String RESOURCE_SERVICE = "resource.service";
+    public static final String RESOURCE_INSTANCE = "resource.instance";
     public static final String SERVICE_NAME = "service.name";
     public static final String SERVICE = "service";
+    public static final String INSTANCE = "instance";
 
     // Span-scoped tag prefix and names
     public static final String SPAN_PREFIX = "span.";
@@ -139,13 +141,13 @@ public abstract class TraceQLApiHandler {
                                    @Param("start") Optional<Long> start,
                                    @Param("end") Optional<Long> end,
                                    @Header("Accept") Optional<String> accept) 
throws IOException, DecoderException {
-        return queryTraceImpl(traceId, accept);
+        return queryTraceImpl(traceId, start, end, accept);
     }
 
     /**
      * Abstract method to be implemented by subclasses for trace query logic.
      */
-    protected abstract HttpResponse queryTraceImpl(String traceId, 
Optional<String> accept) throws IOException, DecoderException;
+    protected abstract HttpResponse queryTraceImpl(String traceId, 
Optional<Long> start, Optional<Long> end, Optional<String> accept) throws 
IOException, DecoderException;
 
     /**
      * Search for traces matching the given criteria.
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 487bddae03..d35278e8e5 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
@@ -81,6 +81,8 @@ public class ZipkinTraceQLApiHandler extends 
TraceQLApiHandler {
 
     @Override
     protected HttpResponse queryTraceImpl(String traceId,
+                                          Optional<Long> start,
+                                          Optional<Long> end,
                                           Optional<String> accept) throws 
IOException, DecoderException {
         List<Span> zipkinTrace = zipkinQueryService.getTraceById(traceId);
 
diff --git 
a/oap-server/server-query-plugin/traceql-plugin/src/main/java/org/apache/skywalking/oap/query/traceql/rt/TraceQLQueryParams.java
 
b/oap-server/server-query-plugin/traceql-plugin/src/main/java/org/apache/skywalking/oap/query/traceql/rt/TraceQLQueryParams.java
index bab92d9319..325724105e 100644
--- 
a/oap-server/server-query-plugin/traceql-plugin/src/main/java/org/apache/skywalking/oap/query/traceql/rt/TraceQLQueryParams.java
+++ 
b/oap-server/server-query-plugin/traceql-plugin/src/main/java/org/apache/skywalking/oap/query/traceql/rt/TraceQLQueryParams.java
@@ -32,6 +32,11 @@ public class TraceQLQueryParams {
      */
     private String serviceName;
 
+    /**
+     * Service instance name filter
+     */
+    private String serviceInstance;
+
     /**
      * Span name filter
      */
diff --git 
a/oap-server/server-query-plugin/traceql-plugin/src/main/java/org/apache/skywalking/oap/query/traceql/rt/TraceQLQueryVisitor.java
 
b/oap-server/server-query-plugin/traceql-plugin/src/main/java/org/apache/skywalking/oap/query/traceql/rt/TraceQLQueryVisitor.java
index 81416258e1..1882e9ec15 100644
--- 
a/oap-server/server-query-plugin/traceql-plugin/src/main/java/org/apache/skywalking/oap/query/traceql/rt/TraceQLQueryVisitor.java
+++ 
b/oap-server/server-query-plugin/traceql-plugin/src/main/java/org/apache/skywalking/oap/query/traceql/rt/TraceQLQueryVisitor.java
@@ -44,23 +44,37 @@ public class TraceQLQueryVisitor extends 
TraceQLParserBaseVisitor<TraceQLParseRe
 
         // Handle specific attributes
         // Note: unscoped .service.name becomes "service.name", scoped becomes 
"resource.service.name"
-        if ("service.name".equals(attribute) || 
"resource.service.name".equals(attribute)) {
-            if ("=".equals(operator)) {
-                params.setServiceName(value);
-            }
-        } else if ("span.name".equals(attribute) || "name".equals(attribute)) {
-            if ("=".equals(operator)) {
-                params.setSpanName(value);
-            }
-        } else if ("http.status_code".equals(attribute) || 
"span.http.status_code".equals(attribute)) {
-            if ("=".equals(operator)) {
-                params.setHttpStatusCode(value);
-            }
-        } else {
-            // Store other attributes
-            // Remove scope prefix if present (e.g., span.http.method -> 
http.method)
-            String tagKey = removeScopePrefix(attribute);
-            params.getTags().put(tagKey, value);
+        switch (attribute) {
+            case "service.name":
+            case "resource.service.name":
+            case "resource.service":
+                if ("=".equals(operator)) {
+                    params.setServiceName(value);
+                }
+                break;
+            case "resource.instance":
+                if ("=".equals(operator)) {
+                    params.setServiceInstance(value);
+                }
+                break;
+            case "span.name":
+            case "name":
+                if ("=".equals(operator)) {
+                    params.setSpanName(value);
+                }
+                break;
+            case "http.status_code":
+            case "span.http.status_code":
+                if ("=".equals(operator)) {
+                    params.setHttpStatusCode(value);
+                }
+                break;
+            default:
+                // Store other attributes
+                // Remove scope prefix if present (e.g., span.http.method -> 
http.method)
+                String tagKey = removeScopePrefix(attribute);
+                params.getTags().put(tagKey, value);
+                break;
         }
 
         return visitChildren(ctx);

Reply via email to