Skip to content
RouteSpear
Documentation
Documentation menu

Query basics

Choose a query form, use IntelliSense, and filter, aggregate, and group metrics.

MetricQL is shared by Metrics Explorer, dashboard query series, saved queries, and health-rule conditions. Choose one of two forms:

  • Metric selectors select a metric, filter its dimensions, and aggregate samples. Use these for a single measurement, counter rates, learned baselines, or arithmetic between metrics.
  • Source pipelines start with from, select several named measurements, correlate sources with explicit joins, and calculate outputs. Use these when you need CPU and memory together, or want to relate a process to its host.
metric_name{key="value", key2=~"regex"} | avg by (dim1, dim2)

Every part shown above is optional on its own, but a query needs at least a metric name, a label matcher, or both; there is no query that matches literally everything by accident. Two such queries can be combined with + - * /, covered in Arithmetic between queries in that guide.

The source form makes the source and output name explicit:

from tests
| where target = "api.example.com"
| summarize p95(http_check_total_ms) as latency by agent_id

from tests accepts the same full metric names as metric selectors, across check types and storage sources. latency is a result alias, not a new stored metric. Source-local field names such as cpu_percent belong inside their source’s summarize calls; a bare metric selector uses the global name, such as host_process_cpu_percent.

Source pipelines use this stage order:

from SOURCE
[ | where DIM OP VALUE [and DIM OP VALUE ...] ]
| summarize AGG(FIELD) as ALIAS [, AGG(FIELD) as ALIAS ...]
  [by DIM [, DIM ...]]
[ | join left|inner (SOURCE_QUERY) as NAME on (DIM [, DIM ...]) ... ]
[ | extend ALIAS = EXPRESSION [, ALIAS = EXPRESSION ...] ... ]
[ | order by ALIAS_OR_GROUP_DIMENSION [asc|desc] [ | limit INTEGER ] ]

Square brackets indicate optional syntax. Sources are tests, host_resources, containers, kubernetes, and custom. Combine where predicates with and; operators are =, !=, =~, !~, in, and not in. Values are quoted strings (set operators take a parenthesized list of strings) or bare true and false. Each measurement requires an as alias. For alert conditions, finish with | pick ALIAS instead of ordering or limiting.

See Source pipelines for field selection, grouping and limits, and Joins and calculations for correlation and calculated outputs. AI and MCP clients can retrieve these with get_query_language_spec(topic="sources") and get_query_language_spec(topic="joins"); use get_metrics_catalog(view="sources") to discover source fields and units, then validate_query before execution.

Writing queries with IntelliSense

The Explorer, dashboard Query language series, and individual alert conditions share the same completion engine. Press Ctrl+Space to open suggestions, use the arrow keys to select, Enter to accept, and Escape to dismiss. Suggestions also open as you type and continue into the arguments after you accept a stage or operator. In Explorer, Ctrl+Enter runs the query (Cmd+Enter on macOS).

Start typing a metric name, or choose from and then a source. Source fields show their measurement kind and unit, with descriptions where the catalog provides them. After a filter key, choose an equality, regex, or set operator; value suggestions include recent dimension values and your tenant’s current agent and test names, shown alongside their IDs. Choose a name in an agent_id or test_id filter to insert its stable ID, or in agent.name or test.name to insert its name. At the start of a filter, an entity suggestion inserts a complete ID filter. These names identify agents and test definitions (individual checks); use test.group_id to filter the containing test group. Source queries also offer the fixed resource_kind and monitored values. Quoted values are escaped when inserted.

After summarize, suggestions guide aggregation functions, their source’s fields, as, and grouping dimensions. Choose your own output alias after as. Later stages offer those aliases, including qualified joined outputs such as host.used, in calculations, ordering, and pick. Ordering also offers retained grouping dimensions, such as agent.name or test_type; pick always selects a numeric output. Join-key suggestions come from the left grouping; the right query must group by exactly those keys.

Metric selectors offer counter conversions, valid second stages, baseline profiles and statistics, and arithmetic operands. Second-stage grouping offers only dimensions retained by the first aggregation. Dashboard variables appear after ${ when the dashboard defines them.

Completion is an editing aid. Custom metric names and dimension values may be valid even when they have not been discovered yet; type them directly. An empty value menu does not mean the dimension is invalid or the metric is zero. Likewise, a configured test or agent appearing in suggestions does not prove that it has measurements in the selected time range. The server validates syntax, units, grouping, permissions, and query limits when the query runs.

Selector

The selector is the part before any |: an optional bare metric name, followed by an optional {...} block of matchers.

http_check_total_ms

selects one metric name and every dimension it carries. Leave the name off and filter by matchers instead to compare several metrics at once, typically combined with by (metric_name) so they render as separate series rather than one blended line:

{test_type="http_check"}

Both can be combined: a metric name narrows to that metric, and the matchers narrow further.

http_check_total_ms{target=~"api-.*"}

Matchers

A matcher is key, an operator, and a double-quoted string. Several matchers inside one {...} block are joined with AND; there is no OR inside a selector; run two queries instead.

Operator Meaning
key="value" Exactly equal
key!="value" Not equal
key=~"regex" Matches a regular expression
key!~"regex" Does not match a regular expression
key in ("a", "b") Exactly equal to any value in the list
key not in ("a", "b") Exactly equal to none of the values in the list

key is any queryable dimension, see Dimensions for the full list, which spans the record’s own identity, context the platform stamps on every row, entity facts resolved after the fact, and your own labels, promoted or not.

Regular expressions use RE2 (no backreferences or lookaround). Matching is unanchored: use ^api-.*$ for a full-value match beginning with api-, or api- to find that text anywhere in the value.

Values may contain a literal quote or backslash by escaping it:

{target="a\"b"}

Prefer in (...) over a regex alternation when you mean a fixed set of exact values. target=~"a.example|b.example" treats each . as a wildcard and matches axexample too, while target in ("a.example", "b.example") matches exactly those two, and compiles to a plain set lookup rather than a regex scan over every row. The list needs at least one value; in () is a syntax error, on the assumption that it is a half-typed query rather than a deliberate empty set.

Aggregation and grouping

An optional | stage follows the selector. Leaving it off is not the same as skipping aggregation; it defaults to avg across everything the selector matched, collapsed to one series.

http_check_total_ms{target=~"api-.*"}

is exactly

http_check_total_ms{target=~"api-.*"} | avg

The sample aggregations are:

Aggregation Answers
avg The typical value across matching samples
min The best case in the window
max The worst case in the window, the one that matters for anything you’d page on
sum The total across matching samples, for things meant to be added (bytes, counts)
count How many samples landed in the window, independent of their value
p50 The median sample, what a typical request saw, unmoved by a few outliers
p90, p95, p99 The tail: the value 90/95/99% of samples stayed under. For latency this is the number that matters; a steady avg over a doubling p95 is the outage a mean hides, and max alone is too jumpy to read

Each aggregation is computed per chart bucket over the raw samples that landed in it, so a percentile here is a percentile of individual measurements, not of some pre-averaged intermediate. Percentiles are approximate (ClickHouse’s sampling quantile); the error is far smaller than a chart pixel.

by (...) splits the aggregation into one series per distinct combination of the named dimensions, instead of collapsing everything into one line. Any queryable dimension can appear here, including metric_name itself, useful when the selector has no bare metric name and matches several:

{test_type="http_check"} | avg by (metric_name)

Group by more than one dimension to keep series distinct along more than one axis at once:

{region="us-east"} | max by (metric_name, target)

Repeating a key in by (...) has no extra effect; duplicates collapse to one.

Continue reading

All metric query topics

Screenshot