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);
