A sink (see Sinks and perfdata)
writes perfdata somewhere. A datasource reads it back. The two are
declared separately because writing and reading are separate concerns: a
deployment can run sinks with no datasources declared, in which case the
dashboard serves no graphs at all, or declare a datasource pointed at a
backend nothing in sinks: writes to.
jaque never hands the browser a datasource's URL or credentials. The
dashboard asks jaque's query service for a panel or a metric by name, and
jaque runs the query against the configured backend itself. Whatever a
datasource's url carries stays server-side.
1. The datasources: block
Each datasource is a named entry under datasources:, discriminated by
type the same way sinks: is.
datasources: {
ch: {
type: "clickhouse"
url: "clickhouse://ch:9000/jaque"
table: "perfdata"
}
prom: {
type: "prometheus"
url: "http://prometheus:9090"
}
}
| Type | Fields | Notes |
|---|---|---|
clickhouse |
url, table |
table defaults to perfdata; queried for both the semantic and raw SQL panel forms below |
prometheus |
url |
queried through /api/v1/query_range; only the raw PromQL panel form runs against it |
A panel or the object detail view can only ask a clickhouse datasource
for a semantic or raw SQL query, and only a prometheus datasource for a
PromQL query. Naming the wrong type is a config error caught when jaque
loads the config, not when the panel is first viewed.
2. The ui: block
ui: {
datasource: "ch"
panels: {
load_avg: {
ds: "ch"
query: {selector: "env=prod", metric: "load", agg: "avg"}
}
}
}
ui.datasource names the datasource the object detail view's automatic
per-object graphs use. It is optional: leaving it unset falls back to the
single declared datasource, or, with more than one declared, the
lexicographically first by name. Either way that datasource must be
clickhouse -- the object detail graphs use the semantic query form,
which needs an object ID to filter by, and PromQL has no such axis
(ADR-018).
ui.panels declares the named panels the panels view renders. Each panel
has:
| Field | Default | Meaning |
|---|---|---|
ds |
(required) | the datasource name this panel queries |
query |
(required) | one of the three forms below |
range |
6h |
how far back the panel plots by default |
type |
line |
line or area |
3. The three query forms
A panel's query is exactly one of semantic, raw SQL, or raw PromQL.
Semantic -- no query language
query: {selector: "env=prod, team=redes", metric: "load", agg: "avg"}
A label selector, a metric name (the
perfdata point's label, e.g. load or rta), and an aggregation --
avg, max or min. jaque resolves the selector to a set of object
IDs and groups by object, one series per matching object. Requires a
clickhouse datasource. This is the form to reach for by default: it
needs no SQL and no PromQL, and it is the only form the object detail
view's automatic graphs use.
Raw SQL
query: {sql: "SELECT service AS series, bucket, avg(value) AS value FROM (SELECT service, toStartOfInterval(ts, INTERVAL $__interval SECOND) AS bucket, value FROM perfdata WHERE ts >= toDateTime($__from) AND ts <= toDateTime($__to)) GROUP BY series, bucket ORDER BY series, bucket"}
Runs verbatim against the panel's ClickHouse datasource. See section 4 for the column contract and macros.
Raw PromQL
query: {promql: "rate(jaque_perfdata_bytes{host=\"gw\"}[5m])"}
Runs verbatim against the panel's Prometheus datasource through
query_range. Requires a prometheus datasource. jaque does not parse
or evaluate PromQL itself -- it forwards the query text and reshapes
whatever Prometheus returns into the same series format every panel uses.
4. The raw SQL column contract and macros
A raw SQL query must return exactly three columns, in this order:
| Column | Type | Meaning |
|---|---|---|
series |
String |
the series name this row belongs to |
bucket |
DateTime or DateTime64 |
the sample's timestamp |
value |
Float64 |
the sample's value |
A query returning different columns, a different order, or different types is rejected when it runs, with an error naming what was expected.
Three macros are substituted into the query text before it runs:
| Macro | Value |
|---|---|
$__from |
the range's start, unix seconds |
$__to |
the range's end, unix seconds |
$__interval |
the query's step, in whole seconds |
The step is the queried range divided into 200 buckets, rounded up to a whole number of seconds, with a floor of 10 seconds -- a 6h panel (the default range) steps at 108s; nothing ever queries at a step finer than 10s regardless of how short the range is.
5. Counter rate
A metric point's kind -- gauge or counter -- comes from how it was
recorded (see Sinks and perfdata
section 3); a semantic query knows this per series and handles each
according to its kind. A gauge series is aggregated by the requested
agg and plotted as-is. A counter series is always aggregated by max
within each bucket regardless of the requested agg, then converted to a
per-second rate in jaque before it reaches the dashboard: each plotted
point is (value[i] - value[i-1]) / step. The first point of a counter
series has no predecessor and is dropped, and any point whose delta would
be negative -- the counter reset -- is dropped too, rather than plotted
as a spike or a trough.
Raw SQL and raw PromQL queries get no such handling: a raw query returns
whatever it computes, so a raw SQL query plotting a counter needs its own
rate expression, and a raw PromQL query reaches for rate() or
increase() the way any PromQL query would.
6. Where graphs appear
Two places. The panels view (#/panels) renders every declared
ui.panels entry as an SVG chart, line or area per its type, over
its default range. The object detail view
(#/object/<host>, #/object/<host>/<service>) renders one graph per
metric the object has reported perfdata for, using the semantic form
against ui.datasource -- no panel needs to be declared for these, they
follow from the perfdata jaque has already recorded for that object.
Neither place needs the datasources:/ui: blocks to exist for the rest
of the dashboard to work; a deployment with no datasource declared simply
shows neither.