You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2023/02/28 13:49:56 UTC

[skywalking] branch master updated: Add PromQL Service doc and how to use in Grafana. (#10459)

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

wusheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking.git


The following commit(s) were added to refs/heads/master by this push:
     new f866338cf9 Add PromQL Service doc and how to use in Grafana. (#10459)
f866338cf9 is described below

commit f866338cf934b35908a0155d8d447571859c8571
Author: Wan Kai <wa...@foxmail.com>
AuthorDate: Tue Feb 28 21:49:39 2023 +0800

    Add PromQL Service doc and how to use in Grafana. (#10459)
---
 docs/en/api/promql-service.md                      | 632 +++++++++++++++++++++
 docs/en/setup/backend/ui-grafana.md                |  56 ++
 docs/menu.yml                                      |  14 +-
 .../oap/query/promql/handler/PromQLApiHandler.java |   4 +-
 .../oap/query/promql/rt/PromOpUtils.java           |   4 +-
 .../query/promql/rt/PromQLExprQueryVisitor.java    |  10 +-
 6 files changed, 707 insertions(+), 13 deletions(-)

diff --git a/docs/en/api/promql-service.md b/docs/en/api/promql-service.md
new file mode 100644
index 0000000000..c4f69ae3e6
--- /dev/null
+++ b/docs/en/api/promql-service.md
@@ -0,0 +1,632 @@
+# PromQL Service
+PromQL([Prometheus Query Language](https://prometheus.io/docs/prometheus/latest/querying/basics/)) Service
+exposes Prometheus Querying HTTP APIs including the bundled PromQL expression system.
+Third-party systems or visualization platforms that already support PromQL (such as Grafana), 
+could obtain metrics through PromeQL Service.
+
+As SkyWalking and Prometheus have fundamental differences in metrics classification, format, storage, etc. 
+The PromQL Service supported will be a subset of the complete PromQL
+
+## Details Of Supported Protocol
+The following doc describes the details of the supported protocol and compared it to the PromQL official documentation.
+If not mentioned, it will not be supported by default.
+
+### Time series Selectors
+#### [Instant Vector Selectors](https://prometheus.io/docs/prometheus/latest/querying/basics/#instant-vector-selectors)
+For example: select metric `service_cpm` which the service is `$service` and the layer is `$layer`.
+```text
+service_cpm{service='$service', layer='$layer'}
+```
+**Note: The label matching operators only support `=` instead of regular expressions.**
+
+#### [Range Vector Selectors](https://prometheus.io/docs/prometheus/latest/querying/basics/#range-vector-selectors)
+For example: select metric `service_cpm` which the service is `$service` and the layer is `$layer` within the last 5 minutes.
+```text
+service_cpm{service='$service', layer='$layer'}[5m]
+```
+
+#### [Time Durations](https://prometheus.io/docs/prometheus/latest/querying/basics/#time-durations)
+| Unit | Definition   | Support |
+|------|--------------|---------|
+| ms   | milliseconds | yes     |
+| s    | seconds      | yes     |
+| m    | minutes      | yes     |
+| h    | hours        | yes     |
+| d    | days         | yes     |
+| w    | weeks        | yes     |
+| y    | years        | **no**  |
+
+### Binary operators
+#### [Arithmetic binary operators](https://prometheus.io/docs/prometheus/latest/querying/operators/#arithmetic-binary-operators)
+| Operator | Definition           | Support |
+|----------|----------------------|---------|
+| +        | addition             | yes     |
+| -        | subtraction          | yes     |
+| *        | multiplication       | yes     |
+| /        | division             | yes     |
+| %        | modulo               | yes     |
+| ^        | power/exponentiation | **no**  |
+
+##### Between two scalars
+For example:
+```text
+1 + 2
+```
+
+##### Between an instant vector and a scalar
+For example:
+```text
+service_cpm{service='$service', layer='$layer'} / 100
+```
+
+##### Between two instant vectors
+For example:
+```text
+service_cpm{service='$service', layer='$layer'} + service_cpm{service='$service', layer='$layer'}
+```
+
+**Note: The operations between vectors require the same metric and labels, and don't support [Vector matching](https://prometheus.io/docs/prometheus/latest/querying/operators/#vector-matching).**
+
+#### [Comparison binary operators](https://prometheus.io/docs/prometheus/latest/querying/operators/#comparison-binary-operators)
+| Operator | Definition       | Support |
+|----------|------------------|---------|
+| ==       | equal            | yes     |
+| !=       | not-equal        | yes     |
+| \>       | greater-than     | yes     |
+| <        | less-than        | yes     |
+| \>=      | greater-or-equal | yes     |
+| <=       | less-or-equal)   | yes     |
+##### Between two scalars
+For example:
+```text
+1 > bool 2
+```
+
+##### Between an instant vector and a scalar
+For example:
+```text
+service_cpm{service='$service', layer='$layer'} > 1
+```
+
+##### Between two instant vectors
+For example:
+```text
+service_cpm{service='service_A', layer='$layer'} > service_cpm{service='service_B', layer='$layer'}
+```
+
+### HTTP API
+
+#### Expression queries
+
+##### [Instant queries](https://prometheus.io/docs/prometheus/latest/querying/api/#instant-queries)
+```text
+GET|POST /api/v1/query
+```
+
+| Parameter | Definition                                                                                                                          | Support | Optional   |
+|-----------|-------------------------------------------------------------------------------------------------------------------------------------|---------|------------|
+| query     | prometheus expression                                                                                                               | yes     | no         |
+| time      | **The latest metrics value from current time to this time is returned. If time is empty, the default look-back time is 2 minutes.** | yes     | yes        |
+| timeout   | evaluation timeout                                                                                                                  | **no**  | **ignore** |
+
+For example:
+```text
+/api/v1/query?query=service_cpm{service='agent::songs', layer='GENERAL'}
+```
+
+Result:
+```json
+{
+    "status": "success",
+    "data": {
+        "resultType": "vector",
+        "result": [
+            {
+                "metric": {
+                    "__name__": "service_cpm",
+                    "layer": "GENERAL",
+                    "scope": "Service",
+                    "service": "agent::songs"
+                },
+                "value": [
+                    1677548400,
+                    "6"
+                ]
+            }
+        ]
+    }
+}
+```
+
+##### [Range queries](https://prometheus.io/docs/prometheus/latest/querying/api/#range-queries)
+```text
+GET|POST /api/v1/query_range
+```
+
+| Parameter | Definition                                                                           | Support | Optional   |
+|-----------|--------------------------------------------------------------------------------------|---------|------------|
+| query     | prometheus expression                                                                | yes     | no         |
+| start     | start timestamp, **seconds**                                                         | yes     | no         |
+| end       | end timestamp, **seconds**                                                           | yes     | no         |
+| step      | **SkyWalking will automatically fit Step(DAY, HOUR, MINUTE) through start and end.** | **no**  | **ignore** |
+| timeout   | evaluation timeout                                                                   | **no**  | **ignore** |
+
+For example:
+```text
+/api/v1/query_range?query=service_cpm{service='agent::songs', layer='GENERAL'}&start=1677479336&end=1677479636
+```
+
+Result:
+```json
+{
+    "status": "success",
+    "data": {
+        "resultType": "matrix",
+        "result": [
+            {
+                "metric": {
+                    "__name__": "service_cpm",
+                    "layer": "GENERAL",
+                    "scope": "Service",
+                    "service": "agent::songs"
+                },
+                "values": [
+                    [
+                        1677479280,
+                        "18"
+                    ],
+                    [
+                        1677479340,
+                        "18"
+                    ],
+                    [
+                        1677479400,
+                        "18"
+                    ],
+                    [
+                        1677479460,
+                        "18"
+                    ],
+                    [
+                        1677479520,
+                        "18"
+                    ],
+                    [
+                        1677479580,
+                        "18"
+                    ]
+                ]
+            }
+        ]
+    }
+}
+```
+
+#### Querying metadata
+
+##### [Finding series by label matchers](https://prometheus.io/docs/prometheus/latest/querying/api/#finding-series-by-label-matchers)
+```text
+GET|POST /api/v1/series
+```
+
+| Parameter | Definition                   | Support | Optional |
+|-----------|------------------------------|---------|----------|
+| match[]   | series selector              | yes     | no       |
+| start     | start timestamp, **seconds** | yes     | no       |
+| end       | end timestamp, **seconds**   | yes     | no       |
+
+For example:
+```text
+/api/v1/series?match[]=service_traffic{layer='GENERAL'}&start=1677479336&end=1677479636
+```
+
+Result:
+```json
+{
+    "status": "success",
+    "data": [
+        {
+            "__name__": "service_traffic",
+            "service": "agent::songs",
+            "scope": "Service",
+            "layer": "GENERAL"
+        },
+        {
+            "__name__": "service_traffic",
+            "service": "agent::recommendation",
+            "scope": "Service",
+            "layer": "GENERAL"
+        },
+        {
+            "__name__": "service_traffic",
+            "service": "agent::app",
+            "scope": "Service",
+            "layer": "GENERAL"
+        },
+        {
+            "__name__": "service_traffic",
+            "service": "agent::gateway",
+            "scope": "Service",
+            "layer": "GENERAL"
+        },
+        {
+            "__name__": "service_traffic",
+            "service": "agent::frontend",
+            "scope": "Service",
+            "layer": "GENERAL"
+        }
+    ]
+}
+```
+
+**Note: SkyWalking's metadata exists in the following metrics(traffics):**
+- service_traffic
+- instance_traffic
+- endpoint_traffic
+
+#### [Getting label names](https://prometheus.io/docs/prometheus/latest/querying/api/#getting-label-names)
+```text
+GET|POST /api/v1/labels
+```
+
+| Parameter | Definition      | Support | Optional |
+|-----------|-----------------|---------|----------|
+| match[]   | series selector | yes     | yes      |
+| start     | start timestamp | **no**  | yes      |
+| end       | end timestamp   | **no**  | yes      |
+
+For example:
+```text
+/api/v1/labels?match[]=instance_jvm_cpu'
+```
+
+Result:
+```json
+{
+    "status": "success",
+    "data": [
+        "layer",
+        "scope",
+        "top_n",
+        "order",
+        "service_instance",
+        "parent_service"
+    ]
+}
+```
+
+#### [Querying label values](https://prometheus.io/docs/prometheus/latest/querying/api/#querying-label-values)
+```text
+GET /api/v1/label/<label_name>/values
+```
+
+| Parameter | Definition      | Support | Optional |
+|-----------|-----------------|---------|----------|
+| match[]   | series selector | yes     | no       |
+| start     | start timestamp | **no**  | yes      |
+| end       | end timestamp   | **no**  | yes      |
+
+For example:
+```text
+/api/v1/label/__name__/values
+```
+
+Result:
+```json
+{
+  "status": "success",
+  "data": [
+    "meter_mysql_instance_qps",
+    "service_cpm",
+    "envoy_cluster_up_rq_active",
+    "instance_jvm_class_loaded_class_count",
+    "k8s_cluster_memory_requests",
+    "meter_vm_memory_used",
+    "meter_apisix_sv_bandwidth_unmatched",
+    "meter_vm_memory_total",
+    "instance_jvm_thread_live_count",
+    "instance_jvm_thread_timed_waiting_state_thread_count",
+    "browser_app_page_first_pack_percentile",
+    "instance_clr_max_worker_threads",
+    ...
+  ]
+}
+```
+
+#### [Querying metric metadata](https://prometheus.io/docs/prometheus/latest/querying/api/#querying-metric-metadata)
+```text
+GET /api/v1/metadata
+```
+
+| Parameter | Definition                                  | Support | Optional |
+|-----------|---------------------------------------------|---------|----------|
+| limit     | maximum number of metrics to return         | yes     | **yes**  |
+| metric    | **metric name, support regular expression** | yes     | **yes**  |
+
+For example:
+```text
+/api/v1/metadata?limit=10
+```
+
+Result:
+```json
+{
+  "status": "success",
+  "data": {
+    "meter_mysql_instance_qps": [
+      {
+        "type": "gauge",
+        "help": "",
+        "unit": ""
+      }
+    ],
+    "meter_apisix_sv_bandwidth_unmatched": [
+      {
+        "type": "gauge",
+        "help": "",
+        "unit": ""
+      }
+    ],
+    "service_cpm": [
+      {
+        "type": "gauge",
+        "help": "",
+        "unit": ""
+      }
+    ],
+    ...
+  }
+}
+```
+
+## Metrics Type For Query
+
+### Supported Metrics [Scope](../../../oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/enumeration/Scope.java)(Catalog)
+All scopes are not supported completely, please check the following table:
+
+| Scope                   | Support |
+|-------------------------|---------|
+| Service                 | yes     |
+| ServiceInstance         | yes     |
+| Endpoint                | yes     |
+| ServiceRelation         | no      |
+| ServiceInstanceRelation | no      |
+| Process                 | no      |
+| ProcessRelation         | no      |
+
+### General labels
+Each metric contains general labels: [layer](../../../oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/Layer.java).
+Different metrics will have different labels depending on their Scope and metric value type.
+
+| Query Labels                     | Scope           | Expression Example                                                                             |
+|----------------------------------|-----------------|------------------------------------------------------------------------------------------------|
+| layer, service                   | Service         | service_cpm{service='$service', layer='$layer'}                                                |
+| layer, service, service_instance | ServiceInstance | service_instance_cpm{service='$service', service_instance='$service_instance', layer='$layer'} |
+| layer, service, endpoint         | Endpoint        | endpoint_cpm{service='$service', endpoint='$endpoint', layer='$layer'}                         |
+
+
+
+### Common Value Metrics
+- Query Labels: 
+```text
+{General labels}
+```
+
+- Expression Example: 
+```text
+service_cpm{service='agent::songs', layer='GENERAL'}
+```
+
+- Result (Instant Query):
+```json
+{
+    "status": "success",
+    "data": {
+        "resultType": "vector",
+        "result": [
+            {
+                "metric": {
+                    "__name__": "service_cpm",
+                    "layer": "GENERAL",
+                    "scope": "Service",
+                    "service": "agent::songs"
+                },
+                "value": [
+                    1677490740,
+                    "3"
+                ]
+            }
+        ]
+    }
+}
+```
+
+
+### Labeled Value Metrics
+- Query Labels:
+```text
+--{General labels}
+--labels: Used to filter the value labels to be returned
+--relabels: Used to rename the returned value labels
+note: The number and order of labels must match the number and order of relabels.
+```
+
+- Expression Example:
+```text
+service_percentile{service='agent::songs', layer='GENERAL', labels='0,1,2', relabels='P50,P75,P90'}
+```
+
+- Result (Instant Query):
+```json
+{
+  "status": "success",
+  "data": {
+    "resultType": "vector",
+    "result": [
+      {
+        "metric": {
+          "__name__": "service_percentile",
+          "label": "P50",
+          "layer": "GENERAL",
+          "scope": "Service",
+          "service": "agent::songs"
+        },
+        "value": [
+          1677493380,
+          "0"
+        ]
+      },
+      {
+        "metric": {
+          "__name__": "service_percentile",
+          "label": "P75",
+          "layer": "GENERAL",
+          "scope": "Service",
+          "service": "agent::songs"
+        },
+        "value": [
+          1677493380,
+          "0"
+        ]
+      },
+      {
+        "metric": {
+          "__name__": "service_percentile",
+          "label": "P90",
+          "layer": "GENERAL",
+          "scope": "Service",
+          "service": "agent::songs"
+        },
+        "value": [
+          1677493380,
+          "0"
+        ]
+      }
+    ]
+  }
+}
+```
+
+### Sort Metrics
+- Query Labels:
+```text
+--parent_service: <optional> Name of the parent service.
+--top_n: The max number of the selected metric value
+--order: ASC/DES
+```
+
+- Expression Example:
+```text
+service_instance_cpm{parent_service='agent::songs', layer='GENERAL',  top_n='10', order='DES'}
+```
+
+- Result (Instant Query):
+```json
+{
+  "status": "success",
+  "data": {
+    "resultType": "vector",
+    "result": [
+      {
+        "metric": {
+          "__name__": "service_instance_cpm",
+          "layer": "GENERAL",
+          "scope": "ServiceInstance",
+          "service_instance": "651db53c0e3843d8b9c4c53a90b4992a@10.4.0.28"
+        },
+        "value": [
+          1677494280,
+          "14"
+        ]
+      },
+      {
+        "metric": {
+          "__name__": "service_instance_cpm",
+          "layer": "GENERAL",
+          "scope": "ServiceInstance",
+          "service_instance": "4c04cf44d6bd408880556aa3c2cfb620@10.4.0.232"
+        },
+        "value": [
+          1677494280,
+          "6"
+        ]
+      },
+      {
+        "metric": {
+          "__name__": "service_instance_cpm",
+          "layer": "GENERAL",
+          "scope": "ServiceInstance",
+          "service_instance": "f5ac8ead31af4e6795cae761729a2742@10.4.0.236"
+        },
+        "value": [
+          1677494280,
+          "5"
+        ]
+      }
+    ]
+  }
+}
+```
+
+### Sampled Records
+
+- Query Labels:
+```text
+--parent_service: Name of the parent service
+--top_n: The max number of the selected records value
+--order: ASC/DES
+```
+
+- Expression Example:
+```text
+top_n_database_statement{parent_service='localhost:-1', layer='VIRTUAL_DATABASE',  top_n='10', order='DES'}
+```
+
+- Result (Instant Query):
+```json
+{
+  "status": "success",
+  "data": {
+    "resultType": "vector",
+    "result": [
+      {
+        "metric": {
+          "__name__": "top_n_database_statement",
+          "layer": "VIRTUAL_DATABASE",
+          "scope": "Service",
+          "record": "select song0_.id as id1_0_, song0_.artist as artist2_0_, song0_.genre as genre3_0_, song0_.liked as liked4_0_, song0_.name as name5_0_ from song song0_ where song0_.liked>?"
+        },
+        "value": [
+          1677501360,
+          "1"
+        ]
+      },
+      {
+        "metric": {
+          "__name__": "top_n_database_statement",
+          "layer": "VIRTUAL_DATABASE",
+          "scope": "Service",
+          "record": "select song0_.id as id1_0_, song0_.artist as artist2_0_, song0_.genre as genre3_0_, song0_.liked as liked4_0_, song0_.name as name5_0_ from song song0_ where song0_.liked>?"
+        },
+        "value": [
+          1677501360,
+          "1"
+        ]
+      },
+      {
+        "metric": {
+          "__name__": "top_n_database_statement",
+          "layer": "VIRTUAL_DATABASE",
+          "scope": "Service",
+          "record": "select song0_.id as id1_0_, song0_.artist as artist2_0_, song0_.genre as genre3_0_, song0_.liked as liked4_0_, song0_.name as name5_0_ from song song0_ where song0_.liked>?"
+        },
+        "value": [
+          1677501360,
+          "1"
+        ]
+      }
+    ]
+  }
+}
+```
+
diff --git a/docs/en/setup/backend/ui-grafana.md b/docs/en/setup/backend/ui-grafana.md
new file mode 100644
index 0000000000..b329775da5
--- /dev/null
+++ b/docs/en/setup/backend/ui-grafana.md
@@ -0,0 +1,56 @@
+# Use Grafana As The UI
+Since 9.4.0, SkyWalking provide [PromQL Service](../../api/promql-service.md). You can choose [Grafana](https://grafana.com/) 
+as the SkyWalking UI. About the installation and how to use please refer to the [official document](https://grafana.com/docs/grafana/v9.3/).
+
+Notice <1>, Gafana is [AGPL-3.0 license](https://github.com/grafana/grafana/blob/main/LICENSE), which is very different from Apache 2.0.
+Please follow AGPL 3.0 license requirements.
+
+Notice <2>, SkyWalking always uses its native UI as first class. All visualization features are only available on native UI.
+Grafana UI is an extension on our support of PromQL APIs. We don't maintain or promise the complete Grafana UI dashboard setup.
+
+## Configure Data Source
+In the data source config panel, chose the `Prometheus` and set the url to the OAP server address, the default port is `9090`.
+<img src="https://skywalking.apache.org/doc-graph/promql/grafana-datasource.jpg"/>
+
+## Configure Dashboards
+
+### Dashboards Settings
+The following steps are the example of config a `General Service` dashboard:
+1. Create a dashboard named `General Service`. A [layer](../../../../oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/Layer.java) is recommended as a dashboard.
+2. Configure variables for the dashboard:
+<img src="https://skywalking.apache.org/doc-graph/promql/grafana-variables.jpg"/>
+After configure, you can select the service/instance/endpoint on the top of the dashboard:
+<img src="https://skywalking.apache.org/doc-graph/promql/grafana-variables2.jpg"/>
+
+### Add Panels
+The following contents show how to add several typical metrics panels.
+General settings:
+1. Chose the metrics and chart. 
+2. Set `Query options --> Min interval = 1m`, because the metrics min time bucket in SkyWalking is 1m.
+3. Add PromQL expressions, use the variables configured above for the labels then you can select the labels value from top.
+   **Note: Some metrics values may be required calculations to match units.**
+4. Select the returned labels you want to show on panel.
+5. Test query and save the panel.
+
+#### Common Value Metrics
+1. For example `service_apdex` and `Time series chart`.
+2. Add PromQL expression, the metric scope is `Service`, so add labels `service` and `layer` for match.
+3. Set `Connect null values --> Always` and `Show points --> Always` because when the query interval > 1hour or 1day SkyWalking return 
+   the hour/day step metrics values.
+<img src="https://skywalking.apache.org/doc-graph/promql/grafana-panels.jpg"/>
+#### Labeled Value Metrics
+1. For example `service_percentile` and `Time series chart`.
+2. Add PromQL expressions, the metric scope is `Service`, add labels `service` and `layer` for match.
+   And it's a labeled value metric, add `labels='0,1,2,3,4'` filter the result label, and add`relabels='P50,P75,P90,P95,P99'` rename the result label.
+3. Set `Connect null values --> Always` and `Show points --> Always` because when the query interval > 1hour or 1day SkyWalking return
+   the hour/day step metrics values.
+<img src="https://skywalking.apache.org/doc-graph/promql/grafana-panels2.jpg"/>
+
+#### Sort Metrics
+1. For example `service_instance_cpm` and `Bar gauge chart`.
+2. Add PromQL expressions, add labels `parent_service` and `layer` for match, add `top_n='10'` and `order='DES'` filter the result.
+3. Set the `Calculation --> Latest*`.
+<img src="https://skywalking.apache.org/doc-graph/promql/grafana-panels3.jpg"/>
+
+#### Sampled Records
+Same as the Sort Metrics.
diff --git a/docs/menu.yml b/docs/menu.yml
index c51779b095..262c125cdf 100644
--- a/docs/menu.yml
+++ b/docs/menu.yml
@@ -144,11 +144,17 @@ catalog:
           - name: "Dynamic Configuration"
             path: "/en/setup/backend/dynamic-config"
       - name: "UI Setup"
-        path: "/en/setup/backend/ui-setup"
+        catalog:
+          - name: "Native UI"
+            catalog:
+            - name: "Setup"
+              path: "/en/setup/backend/ui-setup"
+            - name: "Customization"
+              path: "/en/ui/readme"
+          - name: "Grafana UI"
+            path: "/en/setup/backend/ui-grafana"
       - name: "Official Dashboards"
         catalog:
-          - name: "Overview"
-            path: "/en/ui/readme"
           - name: "General Service"
             catalog:
               - name: "Server Agents"
@@ -257,6 +263,8 @@ catalog:
             path: "/en/api/event"
           - name: "Profiling"
             path: "/en/api/profiling-protocol"
+          - name: "PromQL Service"
+            path: "/en/api/promql-service"
       - name: "Query APIs"
         catalog:
           - name:  "GraphQL APIs"
diff --git a/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/handler/PromQLApiHandler.java b/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/handler/PromQLApiHandler.java
index 77ba7f0194..ae2063c9e7 100644
--- a/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/handler/PromQLApiHandler.java
+++ b/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/handler/PromQLApiHandler.java
@@ -288,7 +288,7 @@ public class PromQLApiHandler {
         if (time.isPresent()) {
             endTS = formatTimestamp2Millis(time.get());
         }
-        long startTS = endTS - 900000; //look back 15m by default
+        long startTS = endTS - 120000; //look back 2m by default
         Duration duration = timestamp2Duration(startTS, endTS);
         ExprQueryRsp response = new ExprQueryRsp();
 
@@ -347,7 +347,7 @@ public class PromQLApiHandler {
         @Param("query") String query,
         @Param("start") String start,
         @Param("end") String end,
-        @Param("step") String step,
+        @Param("step") Optional<String> step,
         @Param("timeout") Optional<String> timeout) throws IOException {
         long startTS = formatTimestamp2Millis(start);
         long endTS = formatTimestamp2Millis(end);
diff --git a/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/rt/PromOpUtils.java b/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/rt/PromOpUtils.java
index 44f6bbd92f..524f8e1666 100644
--- a/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/rt/PromOpUtils.java
+++ b/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/rt/PromOpUtils.java
@@ -50,11 +50,11 @@ public class PromOpUtils {
 
         long durationValue = endTS - startTS;
 
-        if (durationValue < 3600000) {
+        if (durationValue <= 3600000) {
             duration.setStep(Step.MINUTE);
             duration.setStart(startDT.toString(DurationUtils.YYYY_MM_DD_HHMM));
             duration.setEnd(endDT.toString(DurationUtils.YYYY_MM_DD_HHMM));
-        } else if (durationValue < 86400000) {
+        } else if (durationValue <= 86400000) {
             duration.setStep(Step.HOUR);
             duration.setStart(startDT.toString(DurationUtils.YYYY_MM_DD_HH));
             duration.setEnd(endDT.toString(DurationUtils.YYYY_MM_DD_HH));
diff --git a/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/rt/PromQLExprQueryVisitor.java b/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/rt/PromQLExprQueryVisitor.java
index 05ac6940b0..47d2f8633f 100644
--- a/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/rt/PromQLExprQueryVisitor.java
+++ b/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/rt/PromQLExprQueryVisitor.java
@@ -260,14 +260,11 @@ public class PromQLExprQueryVisitor extends PromQLParserBaseVisitor<ParseResult>
     private void checkLabels(Map<LabelName, String> labelMap,
                              LabelName... labelNames) throws IllegalExpressionException {
         StringBuilder missLabels = new StringBuilder();
+        int j = 0;
         for (int i = 0; i < labelNames.length; i++) {
             String labelName = labelNames[i].toString();
             if (labelMap.get(labelNames[i]) == null) {
-                if (i == 0) {
-                    missLabels.append(labelName);
-                } else {
-                    missLabels.append(",").append(labelName);
-                }
+                missLabels.append(j++ > 0 ? "," : "").append(labelName);
             }
         }
         String result = missLabels.toString();
@@ -426,7 +423,8 @@ public class PromQLExprQueryVisitor extends PromQLParserBaseVisitor<ParseResult>
                                              Layer layer,
                                              Scope scope,
                                              Map<LabelName, String> labelMap) throws IllegalExpressionException {
-        checkLabels(labelMap, LabelName.TOP_N, LabelName.PARENT_SERVICE, LabelName.ORDER);
+        //sortMetrics query ParentService could be null.
+        checkLabels(labelMap, LabelName.TOP_N, LabelName.ORDER);
         TopNCondition topNCondition = new TopNCondition();
         topNCondition.setName(metricName);
         topNCondition.setParentService(labelMap.get(LabelName.PARENT_SERVICE));