Metric query dialects (MET-016)
Watchtower's metric engine runs PromQL. Queries written in other vendors' metric languages are translated to PromQL first, by our own parsers in crates/wt-promql/src/dialects/ (Datadog in crates/wt-promql/src/dd.rs). There are two ways to use them:
dialect=<name>on the Prometheus query endpoints (/v1/projects/{prj}/prometheus/api/v1/queryandquery_range): the query text is translated and run.POST /v1/translate/metric-query {"dialect", "query"}returns{"promql"}, so you can see and edit the result. The Metrics page has a "Translate from another metric language" panel.
Names are datadog (or dd), signalflow, dql, ppl, apl, uql and badgerql.
Anything outside the subsets below is refused, never dropped. The translate endpoint answers 422 application/problem+json with detail: "unsupported construct: <dialect> <construct>", for example unsupported construct: uql table operation join. The Prometheus endpoints answer their usual 422 unsupported_promql with the same name. Metric and tag names keep their spelling, except that . and - become _.
Every dialect maps to the same shape: one metric selector with label matchers, an optional per-series window function, an optional aggregation across series with by labels, and an optional top or bottom k. Time-bucketed aggregations (stats avg(..) by span(1m)) become a window function over the bucket, followed by the same aggregation across series. A per-bucket count is summed across series.
SignalFlow
data('cpu.utilization', filter=filter('host', 'a', 'b') and not filter('env', 'dev'), rollup='rate').mean(by=['host']).top(count=5).publish()
An optional stream name:
A = data(..).data(metric, filter=.., rollup=..). Filters arefilter(key, value, ..)terms (*wildcards, several values match any of them),not filter(..), andand.oris unsupported.rollup=:average/mean,sum,min,max,count,latest,rate,delta, over 60 s..mean/.sum/.min/.max/.count(by=[..]): one aggregation across series..mean(over='5m')(and the other aggregations): a moving window per series, before any aggregation..top(count=n)and.bottom(count=n), then.publish(..).
Dynatrace DQL
timeseries cpu = avg(dt.host.cpu.usage), by: {dt.entity.host}, filter: {env == "prod" and host != "h2"}, interval: 5m
Only the
timeseriescommand, with one aggregation:avg,sum,min,maxorcount, and an optional alias.rate: 1minside the aggregation: a counter's rate per minute (rate(..) * 60).by: {..},filter:with==,!=,=~,!~,in (..)andand(orandnotare unsupported), andinterval:(60 s by default).Pipe commands after
timeseriesare unsupported.
OpenSearch PPL
source = cpu.usage | where host = 'a' and env != 'dev' | stats avg(value) by span(@timestamp, 1m), host
source = <metric>, thenwhereand onestatswith one aggregation.The aggregated field is either
value(the source metric's samples) or a metric name.bytakesspan(<time field>, <duration>)and labels. Other commands are unsupported.
Axiom APL
['cpu.usage'] | where host == "a" | summarize count() by bin(_time, 5m), host
The dataset is the metric, then
whereand onesummarize.bin(_time, d)sets the bucket, andbin_auto(_time)uses 60 s. The aggregated field follows the PPL rule.
ServiceNow Cloud Observability UQL
metric cpu.usage | filter host == "a" && env != "dev" | rate 1m | group_by [host], sum | top 5
metric <name>,filter(==,!=,=~,!~,&&), the alignersrate,delta,latest,align <fn>[, window]andreduce <fn>[, window], onegroup_by [..], <agg>, thentop norbottom n. Joins and other table operations are unsupported.
Honeybadger BadgerQL
filter metric::str == "http.duration" and route::str == "/api" | stats avg(value::float) by bin(1h), route::str
::typesuffixes are ignored. Ametricornameequality infilternames the metric. An optional leadingfieldsprojection is accepted. There is onestatsstage, withbin(d)as the bucket.
Datadog
See the module docs of dd.rs: space aggregators, tag filters with wildcards, by {..}, .rollup(), .as_count(), .as_rate(), .timeshift(), .fill(), .ewma_N(), .median_N(), .cumsum(), .diff(), .per_second(), .top(), .outliers() and .anomalies().