Simple Log Service provides multiple APIs to query time series metrics or write metric data to a MetricStore. These APIs are compatible with the open source Prometheus protocol.
Overview
Prometheus APIs are located in the /api/v1/ directory. MetricStore APIs follow the same convention. The complete URL format is https://{project}.{sls-endpoint}/prometheus/{project}/{metricstore}/api/v1/.
|
Parameter |
Required |
Description |
|
{sls-endpoint} |
Yes |
The endpoint of Simple Log Service. The endpoint is the domain name used to access the service. The endpoint varies by the region where the project is located. For more information, see Endpoints. |
|
{project} |
Yes |
Project Name: A project is the resource management unit of Simple Log Service and serves as the primary boundary for multi-user isolation and access control. For more information, see Manage Projects. |
|
{metricstore} |
Yes |
The name of the MetricStore. For more information, see Create a MetricStore. |
These APIs require BasicAuth authentication. Set Username to your AccessKey ID and Password to your AccessKey secret. We recommend that you use the AccessKey pair of a Resource Access Management (RAM) user who has query permissions on the specified project. For more information, see Configure a permission assistant.
These APIs also support Security Token Service (STS) authentication. In this case, set the BasicAuth Password to the format {AccessKey Secret}${STS Token}. For more information, see What is STS?.
Time series metric query APIs
The time series metric query APIs include the Instant Queries API and Range Queries API.
Instant Queries API
The Instant Queries API queries metric data at a specific point in time.
GET https://{project}.{sls-endpoint}/prometheus/{project}/{metricstore}/api/v1/query
POST https://{project}.{sls-endpoint}/prometheus/{project}/{metricstore}/api/v1/query
The following table describes the parameters.
|
Parameter |
Required |
Description |
|
query |
Yes |
A Prometheus Query Language (PromQL) expression. For more information, see PromQL syntax. |
|
time |
No |
The point in time for the query. The value is a UNIX timestamp in seconds. Default value: the current time. |
|
timeout |
No |
The query timeout period in seconds. Time duration formats such as 1s, 2m, 3h, and 4d are also supported. Example: timeout=10s. For more information, see Time Durations. |
|
lookback_delta |
No |
Overrides the `query.lookback-delta` flag in Prometheus for this query only. The value must follow the Time Durations format. Example: `lookback_delta=1m`. For more information, see Time Durations. This parameter specifies the maximum lookback interval for finding data points in PromQL calculations. Default value in an SLS MetricStore: `3m`. |
-
Example
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 your Alibaba Cloud AccessKey. -
Sample response
{ "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 queries metric data at multiple points in time within a specified time range.
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 following table describes the parameters.
|
Parameter |
Required |
Description |
|
query |
Yes |
A PromQL expression. For more information, see PromQL syntax. |
|
start |
No |
The start time of the query range. The value is a UNIX timestamp in seconds. |
|
end |
No |
The end time of the query range. The value is a UNIX timestamp in seconds. |
|
step |
No |
The query step interval in seconds. Time duration formats such as 1s, 2m, 3h, and 4d are also supported. Example: `step=2m`. For more information, see Time Durations. |
|
timeout |
No |
The query timeout period in seconds. Time duration formats such as 1s, 2m, 3h, and 4d are also supported. Example: timeout=10s. For more information, see Time Durations. |
|
lookback_delta |
No |
Overrides the `query.lookback-delta` flag in Prometheus for this query only. The value must follow the Time Durations format. Example: `lookback_delta=1m`. For more information, see Time Durations. This parameter specifies the maximum lookback interval for finding data points in PromQL calculations. Default value in an SLS MetricStore: `3m`. |
-
Example
This example queries metric data from 14:09:59 to 14:16:39 on 2023-02-18 with a step of 60s.
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 your Alibaba Cloud AccessKey. -
Sample response
{ "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" ] ] } ] } }
Metadata query APIs
Simple Log Service also supports querying metadata such as labels and label values. The SLS metadata query APIs are compatible with the Querying metadata APIs in Prometheus. Use these APIs to retrieve all metrics, labels, and label values within a specific time period. The response does not include timestamps or numeric values.
Query Series API
The Query Series API retrieves all metric names and their corresponding label-value pairs that match specific conditions within a specified time period.
GET https://{project}.{sls-endpoint}/prometheus/{project}/{metricstore}/api/v1/series
POST https://{project}.{sls-endpoint}/prometheus/{project}/{metricstore}/api/v1/series
Parameters
|
Parameter |
Required |
Description |
|
match[] |
Yes |
The filter condition. Example: match[]=up{instance="demo.*"}. One or more values can be specified. |
|
start |
No |
The start time of the query range. The value is a UNIX timestamp in seconds. Default value: 5 minutes before the current time. |
|
end |
No |
The end time of the query range. The value is a UNIX timestamp in seconds. Default value: the current time. Important
Even if you specify custom values for both start and end, this API only queries data within the 5 minutes before the end time. The actual query range is `(end - 5 minutes, end)`. |
|
x-sls-disable-range-limit |
No |
Set this parameter to true to remove the 5-minute query range limit and use the specified start and end values instead. |
|
forceMaxMetaTimeRangeSeconds |
No |
The maximum query range in seconds. When (end - start) exceeds this value, the query range is aligned to (end - forceMaxMetaTimeRangeSeconds, end). For optimal query performance, we recommend that you always include this parameter. |
-
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 your Alibaba Cloud AccessKey. -
Sample response
{ "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 match specific conditions within a specified time period.
GET https://{project}.{sls-endpoint}/prometheus/{project}/{metricstore}/api/v1/labels
POST https://{project}.{sls-endpoint}/prometheus/{project}/{metricstore}/api/v1/labels
Parameters
|
Parameter |
Required |
Description |
|
match[] |
Yes |
The filter condition. Example: `match[]=up{instance="demo.*"}`. Zero, one, or more values can be specified. |
|
start |
No |
The start time of the query range. The value is a UNIX timestamp in seconds. Default value: 5 minutes before the current time. |
|
end |
No |
The end time of the query range. The value is a UNIX timestamp in seconds. Default value: the current time. Important
Even if you specify custom values for both start and end, this API only queries data within the 5 minutes before the end time. The actual query range is `(end - 5 minutes, end)`. |
|
x-sls-disable-range-limit |
No |
Set this parameter to true to remove the 5-minute query range limit and use the specified start and end values instead. |
|
forceMaxMetaTimeRangeSeconds |
No |
The maximum query range in seconds. When (end - start) exceeds this value, the query range is aligned to (end - forceMaxMetaTimeRangeSeconds, end). For optimal query performance, we recommend that you always include this parameter. |
-
Example
This example queries all label names of all metrics within a specified time 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 your Alibaba Cloud AccessKey. -
Sample response
{ "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 label values for a specific label name that match specific conditions within a specified time period.
In the API URL, replace <label_name> with the actual label name.
GET https://{project}.{sls-endpoint}/prometheus/{project}/{metricstore}/api/v1/label/<label_name>/values
Parameters
|
Parameter |
Required |
Description |
|
match[] |
Yes |
The filter condition. Example: `match[]=up{instance="demo.*"}`. One or more values can be specified. |
|
start |
No |
The start time of the query range. The value is a UNIX timestamp in seconds. Default value: 5 minutes before the current time. |
|
end |
No |
The end time of the query range. The value is a UNIX timestamp in seconds. Default value: the current time. Important
Even if you specify custom values for both start and end, this API only queries data within the 5 minutes before the end time. The actual query range is `(end - 5 minutes, end)`. |
|
x-sls-disable-range-limit |
No |
Set this parameter to true to remove the 5-minute query range limit and use the specified start and end values instead. |
|
forceMaxMetaTimeRangeSeconds |
No |
The maximum query range in seconds. When (end - start) exceeds this value, the query range is aligned to (end - forceMaxMetaTimeRangeSeconds, end). For optimal query performance, we recommend that you always include this parameter. |
-
Example
This example queries all label values for the instance label of the up metric within a specified time 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 your Alibaba Cloud AccessKey. -
Sample response
{ "status": "success", "data": [ "demo.promlabs.com:10000", "demo.promlabs.com:10001", "demo.promlabs.com:10002" ] }
Data write API
Ingest time series data into a MetricStore by configuring the `remote_write` parameter in the Prometheus configuration file. For more information, see Ingest Prometheus monitoring data using the remote write protocol. Because MetricStore is compatible with the Prometheus remote write protocol, you can also write data to a MetricStore by directly calling the `remote_write` API over HTTP without a Prometheus process.
MetricStore provides the following remote write-compatible API that parses time series data and writes it to backend storage.
When time series data is written to an SLS MetricStore using the remote write protocol, SLS uses `MetricName` and `Labels` as the hash key by default. This routes time series data from different time series to specific shards to improve data locality in storage.
POST https://{project}.{sls-endpoint}/prometheus/{project}/{metricstore}/api/v1/write
The following code shows 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", "") // AccessKey information.
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) // Set the basic auth information.
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) // The body content must be read completely.
if err != nil {
panic(err)
}
return resp.Status, string(body)
}
SDK examples
Access the query API 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", "") // Use the # symbol to concatenate multiple match[] parameters.
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-endpoint}/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)
}
}
Access the query API using the Prometheus SDK
This example uses 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-endpoint}/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 query and write APIs return responses in the following structure:
{
"status": "success" | "error",
"data": <data>,
// The following two items are returned when an error occurs during query analysis.
"errorType": "<string>",
"error": "<string>",
// A warning message is returned, usually for an incomplete query.
"warnings": ["<string>"]
}
Error handling
The following are common errors and solutions.
Authentication failed
-
If the following response is returned, authentication failed. Verify your 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 the following response is returned, the source IP address is not in the VPC CIDR block whitelist. 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}" }
PromQL expression error
If the following response is returned, the PromQL expression contains an error. Fix the expression in the query parameter.
--> /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 the following response is returned, the query timed out. Increase the timeout value.
{
"status": "error",
"errorType": "timeout",
"error": "query timed out in expression evaluation"
}
Incomplete query results
If the following response is returned, the query result is incomplete. Narrow the query time range and try 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"
]
}