Simple Log Service offers a suite of API operations for querying and writing metrics to Metricstores, all of which are compatible with the Prometheus protocol. This topic describes the usage of these API operations.
Overview
All interfaces provided by Prometheus are located under the /api/v1 directory. Metricstore-related API operations adhere to this convention. The complete URL format is https://{project}.{sls-endpoint}/prometheus/{project}/{metricstore}/api/v1/.
Variable | Required | Description |
{sls-endpoint} | Yes | The Simple Log Service endpoint is the domain name used to access the service. The endpoint is associated with the region in which the project resides. For more information, see Service endpoint. |
{project} | Yes | Project Name: A project is a resource management unit of Simple Log Service. It is the primary boundary for multi-user isolation and access control. For more information, see Manage projects. |
{metricstore} | Yes | The Metricstore that is created. For more information, see Create a Metricstore. |
To use the related API operations, BasicAuth authentication is required. Set Username to your AccessKey ID and Password to your AccessKey secret. It is recommended to use the AccessKey pair of a RAM user with the necessary permissions for the specified project. For more information, see Configure permission assistant.
Additionally, the API operations support Security Token Service (STS) authentication. In this scenario, the Password in BasicAuth must follow the format {AccessKey secret}${STS token}
. For more information, see What is STS.
API operations for metric queries
The Instant Queries API and Range Queries API are designed for metric retrieval.
Instant Queries API
The Instant Queries API allows you to retrieve metrics at a specific timestamp.
GET https://{project}.{sls-endpoint}/prometheus/{project}/{metricstore}/api/v1/query
POST https://{project}.{sls-endpoint}/prometheus/{project}/{metricstore}/api/v1/query
The table below details the parameters used in the statement above.
Variable | Required | Description |
query | Yes | The specific PromQL statement. For more information, see PromQL syntax. |
time | No | The point in time to query. The value is a UNIX timestamp that is accurate to the second. The default value is the current time. |
timeout | No | The timeout period for a query. Unit: seconds. 1s, 2m, 3h, and 4d are supported. For example, timeout=10s. For more information, see Time durations. |
lookback_delta | No | You can use this parameter to customize the value of the query.lookback-delta flag in Prometheus. The value is valid only for the current query. The value of this parameter must follow the usage of time durations. For example, lookback_delta=1m. For more information, see Time durations. This parameter specifies the maximum backtrack range when PromQL identifies specific points in time during calculation. The default value of 3m is used for the variable in Simple Log Service Metricstores. |
-
Sample code
curl -X GET 'https://haoqi-sls-metric-test.pub-cn-hangzhou.log.aliyuncs.com/prometheus/haoqi-sls-metric-test/prometheus-metrics/api/v1/query?query=up&time=1676700699' \ -u username:password \ -H 'Content-Type: application/x-www-form-urlencoded' # Set username and password to the Alibaba Cloud AccessKey.
-
Query results
{ "status": "success", "data": { "resultType": "vector", "result": [ { "metric": { "__name__": "up", "instance": "demo.promlabs.com:10001", "job": "demo" }, "value": [ 1676700550.696, "1" ] }, { "metric": { "__name__": "up", "instance": "demo.promlabs.com:10000", "job": "demo" }, "value": [ 1676700550.696, "1" ] } ] } }
Range Queries API
The Range Queries API enables you to retrieve metrics over a specified time range at multiple intervals.
GET https://{project}.{sls-endpoint}/prometheus/{project}/{metricstore}/api/v1/query_range
POST https://{project}.{sls-endpoint}/prometheus/{project}/{metricstore}/api/v1/query_range
The table below describes the parameters in the statement above.
Variable | Required | Description |
query | Yes | The specific PromQL statement. For more information, see PromQL syntax. |
start | No | The beginning of the time range to query. The value is a UNIX timestamp that is accurate to the second. |
end | No | The end of the time range to query. The value is a UNIX timestamp that is accurate to the second. |
step | No | The interval at which queries are performed. Unit: seconds. 1s, 2m, 3h, and 4d are supported. For example, step=2m. For more information, see Time durations. |
timeout | No | The timeout period for a query. Unit: seconds. 1s, 2m, 3h, and 4d are supported. For example, timeout=10s. For more information, see Time durations. |
lookback_delta | No | You can use this parameter to customize the value of the query.lookback-delta flag in Prometheus. The value is valid only for the current query. The value of this parameter must follow the usage of time durations. For example, lookback_delta=1m. For more information, see Time durations. This parameter specifies the maximum backtrack range when PromQL identifies specific points in time during calculation. The default value of 3m is used for the variable in Simple Log Service Metricstores. |
-
Sample code
The sample code below demonstrates how to query metrics from 2023-02-18 14:09:59 to 2023-02-18 14:16:39 at 60-second intervals.
curl -X GET 'https://haoqi-sls-metric-test.pub-cn-hangzhou.log.aliyuncs.com/prometheus/haoqi-sls-metric-test/prometheus-metrics/api/v1/query_range?query=up&start=1676700599&end=1676700999&step=60s' \ -u username:password \ -H 'Content-Type: application/x-www-form-urlencoded' # Set username and password to the Alibaba Cloud AccessKey.
-
Query results
{ "status": "success", "data": { "resultType": "matrix", "result": [ { "metric": { "__name__": "up", "instance": "demo.promlabs.com:10000", "job": "demo" }, "values": [ [ 1676700599, "1" ], [ 1676700659, "1" ], [ 1676700719, "0" ], [ 1676700779, "0" ], [ 1676700839, "1" ], [ 1676700899, "0" ], [ 1676700959, "1" ] ] }, { "metric": { "__name__": "up", "instance": "demo.promlabs.com:10001", "job": "demo" }, "values": [ [ 1676700599, "1" ], [ 1676700659, "1" ], [ 1676700719, "0" ], [ 1676700779, "0" ], [ 1676700839, "1" ], [ 1676700899, "1" ], [ 1676700959, "1" ] ] } ] } }
API operations for metadata queries
Simple Log Service also facilitates metadata queries, such as retrieving label names and values, in line with Prometheus's Querying metadata API operations. These queries can fetch all metrics and label names, but not timestamps or numeric values.
Query Series API
The Query Series API retrieves all metric names and label-value pairs that match specified criteria within a given timeframe.
GET https://{project}.{sls-endpoint}/prometheus/{project}/{metricstore}/api/v1/series
POST https://{project}.{sls-endpoint}/prometheus/{project}/{metricstore}/api/v1/series
The table below describes the parameters used in the statement above.
Variable | Required | Description |
match[] | Yes | Filter conditions. For example, match[]=up{instance="demo.*"}. You can specify one or more conditions. |
start | No | The beginning of the time range to query. The value is a UNIX timestamp that is accurate to the second. The default value is 5 minutes before the current time. |
end | No | The end of the time range to query. The value is a UNIX timestamp that is accurate to the second. The default value is the current time. Important If both the start and end parameters are customized, the API operation can query only the data that is generated within 5 minutes before the end time. That is, the API operation queries the data that is generated within the (end - 5 minute, end) time range. |
-
Configuration example
curl -g -X GET 'https://haoqi-sls-metric-test.pub-cn-hangzhou.log.aliyuncs.com/prometheus/haoqi-sls-metric-test/prometheus-metrics/api/v1/series?match[]=up{instance="demo.promlabs.com:10000"}&match[]=go_sched_latencies_seconds_bucket&start=1676700599&end=1676700999' \ -u username:password \ -H 'Content-Type: application/x-www-form-urlencoded' # Set username and password to the Alibaba Cloud AccessKey.
-
Query results
{ "status": "success", "data": [ { "__name__": "go_gc_duration_seconds_count", "instance": "demo.promlabs.com:10000", "job": "demo" }, { "__name__": "go_gc_duration_seconds_count", "instance": "demo.promlabs.com:10001", "job": "demo" }, { "__name__": "up", "instance": "demo.promlabs.com:10000", "job": "demo" } ] }
Query Label Names API
The Query Label Names API retrieves all label names that satisfy specific conditions within a given timeframe.
GET https://{project}.{sls-endpoint}/prometheus/{project}/{metricstore}/api/v1/labels
POST https://{project}.{sls-endpoint}/prometheus/{project}/{metricstore}/api/v1/labels
The table below details the parameters in the statement above.
Variable | Required | Description |
match[] | Yes | Filter conditions. For example, match[]=up{instance="demo.*"}. You can specify zero or more conditions. |
start | No | The beginning of the time range to query. The value is a UNIX timestamp that is accurate to the second. The default value is 5 minutes before the current time. |
end | No | The end of the time range to query. The value is a UNIX timestamp that is accurate to the second. The default value is the current time. Important If both the start and end parameters are customized, the API operation can query only the data that is generated within 5 minutes before the end time. That is, the API operation queries the data that is generated within the (end - 5 minute, end) time range. |
-
Configuration example
The sample code below shows how to query label names for all metrics within a specified period:
curl -X GET 'https://haoqi-sls-metric-test.pub-cn-hangzhou.log.aliyuncs.com/prometheus/haoqi-sls-metric-test/prometheus-metrics/api/v1/labels?start=1676700599&end=1676700999' \ -u username:password \ -H 'Content-Type: application/x-www-form-urlencoded' # Set username and password to the Alibaba Cloud AccessKey.
-
Query results
{ "status": "success", "data": [ "code", "instance", "job", "le", "method", "mode", "path", "quantile", "status", "type", "version", "__name__" ] }
Query Label Values API
The Query Label Values API retrieves all values for a specific label name that meet certain criteria within a given timeframe.
You must replace <label_name> with the actual label name in the API operation's URL.
GET https://{project}.{sls-endpoint}/prometheus/{project}/{metricstore}/api/v1/label/<label_name>/values
The table below describes the parameters used in the statement above.
Variable | Required | Description |
match[] | Yes | Filter conditions. For example, match[]=up{instance="demo.*"}. You can specify one or more conditions. |
start | No | The beginning of the time range to query. The value is a UNIX timestamp that is accurate to the second. The default value is 5 minutes before the current time. |
end | No | The end of the time range to query. The value is a UNIX timestamp that is accurate to the second. The default value is the current time. Important If both the start and end parameters are customized, the API operation can query only the data that is generated within 5 minutes before the end time. That is, the API operation queries the data that is generated within the (end - 5 minute, end) time range. |
-
Configuration example
The sample code below illustrates how to query all values for the instance label of the up metric within a specified period:
curl -X GET 'https://haoqi-sls-metric-test.pub-cn-hangzhou.log.aliyuncs.com/prometheus/haoqi-sls-metric-test/prometheus-metrics/api/v1/label/instance/values?match[]=up&start=1676700599&end=1676700999' \ -u username:password \ -H 'Content-Type: application/x-www-form-urlencoded' # Set username and password to the Alibaba Cloud AccessKey.
-
Query results
{ "status": "success", "data": [ "demo.promlabs.com:10000", "demo.promlabs.com:10001", "demo.promlabs.com:10002" ] }
Data write API
By configuring the remote_write parameter in a Prometheus process's configuration file, you can direct metrics to Metricstores. For more details, see Collect Prometheus monitoring data using the remote write protocol. Metricstores are also compatible with Prometheus's remote write protocol, allowing you to use the remote_write API operation over HTTP to write data directly to Metricstores without a Prometheus process.
The remote_write API operation parses metrics and writes the parsed data to backend storage.
POST https://{project}.{sls-endpoint}/prometheus/{project}/{metricstore}/api/v1/write
The following code provides an example:
import (
"bytes"
"flag"
"fmt"
"github.com/gogo/protobuf/proto"
"github.com/golang/snappy"
"github.com/prometheus/prometheus/prompb"
"io/ioutil"
"net/http"
"time"
)
func MockRemoteWrite() {
project := flag.String("project", "xxxx", "")
metricStore := flag.String("metricstore", "xxxx", "")
endpoint := flag.String("endpoint", "xxxx", "")
akId := flag.String("akid", "xxxx", "") // The AccessKey ID.
akKey := flag.String("aksecret", "xxxx", "")
flag.Parse()
Url := fmt.Sprintf("https://%s.%s/prometheus/%s/%s/api/v1/write", *project, *endpoint, *project, *metricStore)
timestamp := time.Now().UnixNano()
timeSeries := []prompb.TimeSeries{
{
Labels: []prompb.Label{
{Name: "__name__", Value: "test_metric"},
{Name: "app", Value: "HOST"},
{Name: "device", Value: "vda"},
},
Samples: []prompb.Sample{
{Timestamp: timestamp / 1000000, Value: 100},
{Timestamp: timestamp/1000000 + 10000, Value: 200},
{Timestamp: timestamp/1000000 + 20000, Value: 400},
{Timestamp: timestamp/1000000 + 30000, Value: 300},
},
},
{
Labels: []prompb.Label{
{Name: "__name__", Value: "test_metric"},
{Name: "app", Value: "HOST"},
{Name: "device", Value: "vda"},
{Name: "uid", Value: "123456"},
},
Samples: []prompb.Sample{
{Timestamp: timestamp / 1000000, Value: 100},
{Timestamp: timestamp/1000000 + 10000, Value: 200},
{Timestamp: timestamp/1000000 + 20000, Value: 400},
{Timestamp: timestamp/1000000 + 30000, Value: 600},
},
},
}
data, _ := proto.Marshal(&prompb.WriteRequest{Timeseries: timeSeries})
bufBody := snappy.Encode(nil, data)
rwR, err := http.NewRequest("POST", Url, ioutil.NopCloser(bytes.NewReader(bufBody)))
rwR.Header.Add("Content-Encoding", "snappy")
rwR.Header.Set("Content-Type", "application/x-protobuf")
rwR.SetBasicAuth(*akId, *akKey) // The information that is used for basic authentication.
if err != nil {
fmt.Println(err.Error())
return
}
start := time.Now().UnixNano() / 1000000 //ms
do, err := client.Do(rwR)
end := time.Now().UnixNano() / 1000000 // ms
if err != nil {
panic(err)
}
status, result := parseResp(do)
fmt.Println("status:", status, "result:", result, "duration:", end-start)
}
func parseResp(resp *http.Response) (status, data string) {
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body) // Specifies that all content in the request body must be read.
if err != nil {
panic(err)
}
return resp.Status, string(body)
}
SDK examples
Call a query API operation over HTTP
import (
"flag"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strconv"
"strings"
"time"
)
const separator = "#"
func http_main() {
project := flag.String("project", "xxxx", "")
metricStore := flag.String("metricstore", "xxxx", "")
endpoint := flag.String("endpoint", "xxxx", "")
akId := flag.String("akid", "xxxx", "")
akKey := flag.String("aksecret", "xxxx", "")
query := flag.String("query", "avg(up)", "")
queryType := flag.String("type", "values", "range or query or labels or values or series")
matches := flag.String("match", "up", "") // Concatenate multiple parameters of the match[] method by using number signs (#).
labelName := flag.String("label", "instance", "")
step := flag.String("step", "1m", "")
fromtime := flag.String("from", "2023-02-15T00:00:00Z", "time 2006-01-02T15:04:05Z07:00")
totime := flag.String("to", "2023-02-15T00:15:00Z", "time 2006-01-02T15:04:05Z07:00")
flag.Parse()
timeFrom, err := time.Parse(time.RFC3339, *fromtime)
if err != nil {
panic(err)
}
timeTo, err := time.Parse(time.RFC3339, *totime)
if err != nil {
panic(err)
}
// URL:https://{project}.{sls-enpoint}/prometheus/{project}/{metricstore}
prometheusEndpoint := fmt.Sprintf("https://%s/prometheus/%s/%s", *project+"."+*endpoint, *project, *metricStore)
var uri string
urlVal := url.Values{}
urlVal.Add("start", strconv.FormatInt(timeFrom.Unix(), 10))
urlVal.Add("end", strconv.FormatInt(timeTo.Unix(), 10))
switch *queryType {
case "range":
urlVal.Add("query", *query)
urlVal.Add("step", *step)
uri = fmt.Sprintf("%s/api/v1/query_range?%v", prometheusEndpoint, urlVal.Encode())
case "query":
urlVal.Add("query", *query)
urlVal.Add("time", strconv.FormatInt(timeTo.Unix(), 10))
uri = fmt.Sprintf("%s/api/v1/query?%v", prometheusEndpoint, urlVal.Encode())
case "labels":
extractAddMatches(*matches, urlVal)
uri = fmt.Sprintf("%s/api/v1/labels?%v", prometheusEndpoint, urlVal.Encode())
case "values":
extractAddMatches(*matches, urlVal)
uri = fmt.Sprintf("%s/api/v1/label/%s/values?%v", prometheusEndpoint, *labelName, urlVal.Encode())
case "series":
extractAddMatches(*matches, urlVal)
uri = fmt.Sprintf("%s/api/v1/series?%v", prometheusEndpoint, urlVal.Encode())
}
req, _ := http.NewRequest(http.MethodGet, uri, nil)
req.SetBasicAuth(*akId, *akKey)
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
buf, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
panic(err)
}
fmt.Println(string(buf))
}
func extractAddMatches(matches string, uVal url.Values) {
splits := strings.Split(matches, separator)
for _, match := range splits {
uVal.Add("match[]", match)
}
}
Call a query API operation by using an SDK for Prometheus
This example is based on the Prometheus client_golang v1.14.0.
import (
"context"
"flag"
"fmt"
"github.com/prometheus/client_golang/api"
v1 "github.com/prometheus/client_golang/api/prometheus/v1"
"net"
"net/http"
"net/url"
"time"
)
func main() {
project := flag.String("project", "xxxx", "")
metricStore := flag.String("metricstore", "xxxx", "")
endpoint := flag.String("endpoint", "xxxx", "")
akId := flag.String("akid", "xxxx", "")
akKey := flag.String("aksecret", "xxxx", "")
flag.Parse()
// URL:https://{project}.{sls-enpoint}/prometheus/{project}/{metricstore}
prometheusEndpoint := fmt.Sprintf("https://%s.%s/prometheus/%s/%s", *project, *endpoint, *project, *metricStore)
client, err := api.NewClient(api.Config{
Address: prometheusEndpoint,
RoundTripper: &http.Transport{
// set basic auth
Proxy: func(req *http.Request) (*url.URL, error) {
req.SetBasicAuth(*akId, *akKey)
return nil, nil
},
DialContext: (&net.Dialer{
Timeout: 60 * time.Second,
KeepAlive: 60 * time.Second,
}).DialContext,
TLSHandshakeTimeout: 10 * time.Second,
},
})
if err != nil {
panic(err)
}
v1api := v1.NewAPI(client)
ctx, _ := context.WithTimeout(context.Background(), 60*time.Second)
r := v1.Range{
Start: time.Now().Add(-15 * time.Minute),
End: time.Now(),
Step: time.Minute,
}
// query range
result, warnings, err := v1api.QueryRange(ctx, "avg(up)", r)
if err != nil {
panic(err)
}
if len(warnings) > 0 {
fmt.Printf("Warnings: %v %v\n", warnings, result)
}
fmt.Println(result)
// query
result, warnings, err = v1api.Query(ctx, "avg(up)", time.Now())
if err != nil {
panic(err)
}
if len(warnings) > 0 {
fmt.Printf("Warnings: %v %v\n", warnings, result)
}
fmt.Println(result)
// series
series, warnings, err := v1api.Series(ctx, []string{"up"}, time.Now().Add(-15*time.Minute), time.Now())
if err != nil {
panic(err)
}
if len(warnings) > 0 {
fmt.Printf("Warnings: %v %v\n", warnings, result)
}
fmt.Println(series)
// labels
names, warnings, err := v1api.LabelNames(ctx, []string{"up"}, time.Now().Add(-15*time.Minute), time.Now())
if err != nil {
panic(err)
}
if len(warnings) > 0 {
fmt.Printf("Warnings: %v %v\n", warnings, result)
}
fmt.Println(names)
// labelValues
values, warnings, err := v1api.LabelValues(ctx, "instance", []string{"up"}, time.Now().Add(-15*time.Minute), time.Now())
if err != nil {
panic(err)
}
if len(warnings) > 0 {
fmt.Printf("Warnings: %v %v\n", warnings, result)
}
fmt.Println(values)
}
Response structure
The code snippet below shows the structure of responses for query API operations and the data write API operation:
{
"status": "success" | "error",
"data": <data>,
// The following code is returned if an error occurs in a query:
"errorType": "<string>",
"error": "<string>",
// The following warning information is returned if the query results are incomplete:
"warnings": ["<string>"]
}
Error handling
Common errors can be managed according to the descriptions below:
Authentication failure
-
If you receive the information below, authentication has failed. Ensure you provide a valid AccessKey pair.
{ "status": "error", "code": "401", "errorType": "unauthorized", "error": "get query instance error: {\n \"httpCode\": 401,\n \"errorCode\": \"Unauthorized\",\n \"errorMessage\": \"AccessKeyId not found: xxxx\",\n \"requestID\": \"xxxx\"\n}" }
-
If you receive the information below, the IP address is not whitelisted in the VPC CIDR block. Add the IP address to the whitelist.
{ "status": "error", "code": "401", "errorType": "unauthorized", "error": "get query instance error: {\n \"httpCode\": 401,\n \"errorCode\": \"Unauthorized\",\n \"errorMessage\": \"AccessKeyId not found: xxxx\",\n \"requestID\": \"xxxx\"\n}" }
Invalid PromQL statement
If you receive the information below, the PromQL statement is invalid. Modify the query statement in the query parameter accordingly.
--> /api/v1/query_range?query=up[2m]&start=1676700599&end=1676700999&step=60s
{
"status": "error",
"errorType": "bad_data",
"error": "invalid expression type \"range vector\" for range query, must be Scalar or instant Vector"
}
Timeout error
If you receive the information below, a timeout has occurred. Increase the timeout parameter value.
{
"status": "error",
"errorType": "timeout",
"error": "query timed out in expression evaluation"
}
Incomplete query results
If you receive the message below, the query results are incomplete. Try narrowing the query time range and querying again.
{
"status": "success",
"data": {
"resultType": "matrix",
"result": [
{
"metric": {},
"values": [
[
1673798460,
"11111111"
],
[
1673799060,
"22222222"
],
[
1673799660,
"33333333"
]
]
}
]
},
"warnings": [
"Request to Sls partial incompleted, incomplete task count : 11, total : 108"
]
}