Skip to main content
Version: 1.3

Prometheus Query Language

GreptimeDB implements PromQL in Rust and exposes it through the Prometheus HTTP API, the GreptimeDB HTTP API, and SQL. Grafana can connect through its Prometheus data source. See Limitations for supported features and known differences.

Prometheus' HTTP API​

GreptimeDB has implemented a set of Prometheus compatible APIs under HTTP context /v1/prometheus/:

  • Instant queries /api/v1/query
  • Range queries /api/v1/query_range
  • Series /api/v1/series
  • Label names /api/v1/labels
  • Label values /api/v1/label/<label_name>/values

These endpoints use Prometheus HTTP API request and response formats. In Grafana, set the Prometheus data source URL to http://localhost:4000/v1/prometheus/.

Consult Prometheus documents for usage of these API.

You can use additional query parameter db to specify GreptimeDB database name.

For example, the following query will return the CPU usage of the process_cpu_seconds_total metric in the public database:

curl -X POST \
-H 'Authorization: Basic <base64-encoded-credentials>' \
--data-urlencode 'query=irate(process_cpu_seconds_total[1h])' \
--data-urlencode 'start=2024-11-24T00:00:00Z' \
--data-urlencode 'end=2024-11-25T00:00:00Z' \
--data-urlencode 'step=1h' \
'http://localhost:4000/v1/prometheus/api/v1/query_range?db=public'

If authentication is enabled in GreptimeDB, the authentication header is required. Refer to the authentication documentation for more details. You need to either set it in the HTTP URL query param db like the example above, or set it using --header 'x-greptime-db-name: <database name>' as HTTP header.

The query string parameters for the API are identical to those of the original Prometheus API, with the exception of the additional db parameter, which specifies the GreptimeDB database name.

The output format is compatible with the Prometheus API:

{
"status": "success",
"data": {
"resultType": "matrix",
"result": [
{
"metric": {
"job": "node",
"instance": "node_exporter:9100",
"__name__": "process_cpu_seconds_total"
},
"values": [
[
1732618800,
"0.0022222222222222734"
],
[
1732622400,
"0.0009999999999999788"
],
[
1732626000,
"0.0029999999999997585"
],
[
1732629600,
"0.002222222222222175"
]
]
}
]
}
}

SQL​

GreptimeDB also extends SQL grammar to support PromQL. You can start with the TQL (Time-series Query Language) keyword to write parameters and queries. The grammar looks like this:

TQL [EVAL|EVALUATE] (<START>, <END>, <STEP>) <QUERY>

<START> specifies the query start range and <END> specifies the end time. <STEP> identifies the query resolution step width. All of them can either be an unquoted number (represent UNIX timestamp for <START> and <END>, and duration in seconds for <STEP>), or a quoted string (represent an RFC3339 timestamp for <START> and <END>, and duration in string format for <STEP>).

For example:

TQL EVAL (1676738180, 1676738780, '10s') sum(some_metric)

You can write the above command in all places that support SQL, including the GreptimeDB HTTP API, SDK, PostgreSQL and MySQL client etc.

GreptimeDB's extensions to PromQL​

Specifying value field​

Based on the table model, GreptimeDB supports multiple fields in a single table(or metric, in the context of Prometheus). Queries will run on every fields by default. Or you can use the special filter __field__ to query a specific field(s):

metric{__field__="field1"}

Exclude or regex are also supported:

metric{__field__!="field1"}

metric{__field__=~"field_1|field_2"}

metric{__field__!~"field_1|field_2"}

Cross-database query​

Greptime has its own database concept. In order to run cross-database query, you can use __database__ matcher to specify the database name.

metric{__database__="mydatabase"}

Note that only = is supported for database matcher.

Limitations​

PromQL queries support float samples and native histogram samples. Float metrics use a timestamp column, string labels, and Double values. Native histogram support and ingestion requirements are described in Native histograms.

v1.3.0 compatibility test results​

The v1.3.0 release measurements use promql-compat revision 1203cd8 with Prometheus v3.15.0 as the reference. The target is GreptimeDB v1.3.0.

Test suiteCases countedCases excludedIncluding __name__Ignoring only __name__
Prometheus test corpus852139153.52% (456/852)88.50% (754/852)
Prometheus compliance queries539054.17% (292/539)94.81% (511/539)
Generated queries (seed 1)1999163.83% (1276/1999)93.35% (1866/1999)

Percentages are test-case pass rates, with excluded cases omitted from the denominators; the last column ignores differences only in __name__. See the promql-compat methodology.

Known differences in v1.3.0​

Query behaviorExampleDifference from Prometheus
Metric-name labels in function and aggregation resultsrate(x[1m]), abs(x), sum(rate(x[1m])), sum(x > 0)Functions retain __name__, and aggregations without grouping can retain it from their inputs, affecting Grafana legends and alert/recording-rule labels. In v1.3, filtering comparisons without bool can also restore a removed metric name.
Date functions with an argumentyear(vector(1136239445))Uses the sample timestamp instead of the sample value. Affects year, month, day_of_month, day_of_week, day_of_year, days_in_month, hour, and minute.
Selectors without a metric name{job="demo"}Returns Expect a metric matcher, but not found. A metric name or an explicit __name__ matcher is required.
vector(time())vector(time())Fails with Invalid function argument for unknown in both instant and range queries, including when used alone.
absent_over_timeabsent_over_time(nonexistent_metric[5m])Some queries return different series than Prometheus: expected series can be missing, or extra series can appear. This example returns no series; Prometheus returns a series with value 1.
Dynamic scalar parameterstopk(scalar(foo), x), quantile_over_time(scalar(foo), x[5m])Some uses of scalar() as a parameter fail planning.
first_over_timefirst_over_time(x[5m])Returns Unsupported expr type; the function is not implemented.
Validation differencesscalar_metric > on() dup_metric, clamp(x, 10, 1)Duplicate label sets and duplicate matches can return results where Prometheus raises an error; reversed clamp bounds return an error where Prometheus returns an empty result; label_replace rejects UTF-8 destination labels accepted by Prometheus 3.

Literal​

Both string and float literals are supported, with the same rule as PromQL.

Selector​

Instant and range selectors require a metric name or an explicit __name__ matcher. A selector with only ordinary labels, such as {job="demo"}, returns an error. Metric-name matching has the following restrictions:

  • In TQL, only equal-matching is supported, for example {__name__="request_count"}.
  • The Prometheus HTTP API also supports regex-matching and negative matching, for example {__name__=~"request_.*"} or {__name__!="request_count", host="h1"}. These matchers only match tables created by the metric engine, such as tables written through Prometheus Remote Write.

Time duration, offset, and @ modifier (including @ start() and @ end()) are supported.

Subqueries support an explicit step; an omitted step defaults to one minute, independently of the outer query step. Use [range:step] for another interval. Instant queries can return range vectors; range queries reject a range-vector root expression.

When selecting non-existent columns, they will be treated as columns filled with empty string values (""). This behavior aligns with both Prometheus and VictoriaMetrics.

Timestamp precision​

PromQL evaluation times and steps use millisecond precision. Sample selection preserves stored microsecond or nanosecond timestamps; timestamp() converts the selected sample timestamp to milliseconds, then returns floating-point seconds.

Binary​

  • Supported:
    Operator
    +
    -
    *
    /
    %
    ==
    !=
    >
    <
    >=
    <=
    ^
    atan2
    and
    or
    unless

Vector matching supports on, ignoring, group_left, and group_right. Some duplicate matches and duplicate label sets are not rejected; see Known differences in v1.3.0 for examples.

Aggregators​

  • Supported:
    AggregatorExample
    groupgroup by (foo)(metric)
    sumsum by (foo)(metric)
    avgavg by (foo)(metric)
    minmin by (foo)(metric)
    maxmax by (foo)(metric)
    stddevstddev by (foo)(metric)
    stdvarstdvar by (foo)(metric)
    topktopk(3, rate(instance_cpu_time_ns[5m]))
    bottomkbottomk(3, rate(instance_cpu_time_ns[5m]))
    count_valuescount_values("version", build_version)
    countcount (metric)
    quantilequantile(0.9, cpu_usage)

Instant Functions​

The following functions are implemented; behavior differences and argument limits are listed under Known differences in v1.3.0. histogram_count, histogram_sum, histogram_avg, histogram_stddev, and histogram_stdvar operate on native histogram samples.

  • Supported:
    FunctionExample
    roundround(metric)
    vectorvector(1)
    timetime()
    yearyear()
    monthmonth()
    day_of_monthday_of_month()
    day_of_weekday_of_week()
    day_of_yearday_of_year()
    days_in_monthdays_in_month()
    hourhour()
    minuteminute()
    absabs(metric)
    ceilceil(metric)
    expexp(metric)
    lnln(metric)
    log2log2(metric)
    log10log10(metric)
    sqrtsqrt(metric)
    acosacos(metric)
    asinasin(metric)
    atanatan(metric)
    sinsin(metric)
    coscos(metric)
    tantan(metric)
    acoshacosh(metric)
    asinhasinh(metric)
    atanhatanh(metric)
    sinhsinh(metric)
    coshcosh(metric)
    scalarscalar(metric)
    tanhtanh(metric)
    timestamptimestamp(metric)
    sortsort(http_requests_total)
    sort_descsort_desc(http_requests_total)
    histogram_fractionhistogram_fraction(0, 1, request_duration)
    histogram_counthistogram_count(request_duration)
    histogram_sumhistogram_sum(request_duration)
    histogram_avghistogram_avg(request_duration)
    histogram_stddevhistogram_stddev(request_duration)
    histogram_stdvarhistogram_stdvar(request_duration)
    histogram_quantilehistogram_quantile(phi, metric)
    predict_linearpredict_linear(metric[5m], 120)
    absentabsent(nonexistent{job="myjob"})
    sgnsgn(metric)
    pipi()
    degdeg(metric)
    radrad(metric)
    floorfloor(metric)
    clampclamp(metric, 0, 12)
    clamp_maxclamp_max(metric, 12)
    clamp_minclamp_min(metric, 0)

Range Functions​

See Known differences in v1.3.0 for absent_over_time behavior and the unimplemented first_over_time.

  • Supported:
    FunctionExample
    ideltaidelta(metric[5m])
    avg_over_timeavg_over_time(metric[5m])
    min_over_timemin_over_time(metric[5m])
    max_over_timemax_over_time(metric[5m])
    sum_over_timesum_over_time(metric[5m])
    count_over_timecount_over_time(metric[5m])
    last_over_timelast_over_time(metric[5m])
    present_over_timepresent_over_time(metric[5m])
    quantile_over_timequantile_over_time(0.9, metric[5m])
    stddev_over_timestddev_over_time(metric[5m])
    stdvar_over_timestdvar_over_time(metric[5m])
    changeschanges(metric[5m])
    deltadelta(metric[5m])
    raterate(metric[5m])
    derivderiv(metric[5m])
    increaseincrease(metric[5m])
    irateirate(metric[5m])
    resetsresets(metric[5m])

Label & Other Functions​

  • Supported:
    FunctionExample
    label_joinlabel_join(up{job="api-server",src1="a",src2="b",src3="c"}, "foo", ",", "src1", "src2", "src3")
    label_replacelabel_replace(up{job="api-server",service="a:c"}, "foo", "$1", "service", "(.*):.*")
    sort_by_labelsort_by_label(metric, "foo", "bar")
    sort_by_label_descsort_by_label_desc(metric, "foo", "bar")