@Get
    @Path("/api/v1/label/{label_name}/values")
    public HttpResponse labelValues(
        @Param("label_name") String labelName,
        @Param("match[]") Optional<String> match,
        @Param("start") Optional<String> start,
        @Param("end") Optional<String> end,
        @Param("limit") Optional<Integer> limit) throws IOException {
        LabelValuesQueryRsp response = new LabelValuesQueryRsp();
        response.setStatus(ResultStatus.SUCCESS);
        long endTS = System.currentTimeMillis();
        if (end.isPresent()) {
            endTS = formatTimestamp2Millis(end.get());
        }
        Duration duration = getDayDurationFromTimestamp(endTS);
        int limitNum = limit.orElse(100);

        //general labels
        if (LabelName.NAME.getLabel().equals(labelName)) {
            getMetricsMetadataQueryService().listMetrics("").stream().limit(limitNum).forEach(definition -> {
                response.getData().add(definition.getName());
            });
            return jsonResponse(response);
        } else if (LabelName.LAYER.getLabel().equals(labelName)) {
            for (Layer layer : Arrays.stream(Layer.values()).limit(limitNum).collect(Collectors.toList())) {
                response.getData().add(layer.name());
            }
            return jsonResponse(response);
        } else if (LabelName.SCOPE.getLabel().equals(labelName)) {
            for (Scope scope : Arrays.stream(Scope.values()).limit(limitNum).collect(Collectors.toList())) {
                response.getData().add(scope.name());
            }
            return jsonResponse(response);
        }

        if (match.isPresent()) {
            MatcherSetResult parseResult;
            try {
                parseResult = getMatcherSetResult(match.get());
            } catch (ParseCancellationException e) {
                response.setStatus(ResultStatus.ERROR);
                response.setErrorType(ErrorType.BAD_DATA);
                response.setError(e.getMessage());
                return jsonResponse(response);
            }
            String metricName = parseResult.getMetricName();
            Optional<ValueColumnMetadata.ValueColumn> valueColumn = ValueColumnMetadata.INSTANCE.readValueColumnDefinition(
                metricName);
            if (valueColumn.isPresent() && Column.ValueDataType.LABELED_VALUE == valueColumn.get().getDataType()) {
                List<MetricsValues> matchedMetrics = getMatcherMetricsValues(parseResult, duration);
                response.getData().addAll(buildLabelValuesFromQuery(matchedMetrics, labelName).stream().limit(limitNum).collect(Collectors.toList()));
            } else {
                try {
                    // Make compatible with Grafana 11 when use old config variables
                    // e.g. query service list config: `label_values(service_traffic{layer='$layer'}, service)`
                    // Grafana 11 will query this API by default rather than `/api/v1/series`(< 11)
                    limitNum = getLimitNum(limit, parseResult);
                    String layer = parseResult.getLabelMap().get(LabelName.LAYER.getLabel());
                    if (Objects.equals(metricName, ServiceTraffic.INDEX_NAME)) {
                        queryServiceTraffic(parseResult, layer, limitNum).forEach(service -> {
                            response.getData().add(service.getName());
                        });
                    } else if (Objects.equals(metricName, InstanceTraffic.INDEX_NAME)) {
                        String serviceName = parseResult.getLabelMap().get(LabelName.SERVICE.getLabel());
                        queryInstanceTraffic(parseResult, duration, layer, serviceName, limitNum).forEach(instance -> {
                            response.getData().add(instance.getName());
                        });
                    } else if (Objects.equals(metricName, EndpointTraffic.INDEX_NAME)) {
                        String serviceName = parseResult.getLabelMap().get(LabelName.SERVICE.getLabel());
                        String keyword = parseResult.getLabelMap().getOrDefault(LabelName.KEYWORD.getLabel(), "");
                        queryEndpointTraffic(parseResult, duration, layer, serviceName, keyword, limitNum).forEach(
                            endpoint -> {
                                response.getData().add(endpoint.getName());
                            });
                    }
                } catch (IllegalExpressionException e) {
                    response.setStatus(ResultStatus.ERROR);
                    response.setErrorType(ErrorType.BAD_DATA);
                    response.setError(e.getMessage());
                }
            }
        }

        return jsonResponse(response);
    }
If match[] is not present, return general labels values.
If end time is not present, use current time as default end time.
The start param will be ignored, reserve this param to keep consistent with API protocol.
Always query with day step.
oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/handler/PromQLApiHandler.java