Dashboards
A dashboard is a grid of panels, each drawing one search: pie, bar, line
and area charts, tables, gauges and single values. Base searches are
defined once at the top of the page and extended by the panels that
reference them, and inputs (text boxes and dropdowns) feed values into
the searches as $tokens$. Dashboards are saved on the server, so
everyone who signs in sees the same ones; a user may create dashboards
and change or delete their own, an admin any, and a readonly account
views them.
Using them#
Dashboards in the top bar lists them, with a filter box; New dashboard opens the editor on an empty one and Import JSON creates one from an exported file. On the search page, Add to dashboard next to a result puts that search on a dashboard of yours, or on a new one, as the visualization that fits the result. In the editor:
- The title and description are at the top, with the default time range (the range every panel uses unless it has its own) and the auto-refresh period.
- Inputs is the bar under the head. Add input gives one an id
(lower-case letters, digits and underscores), a label, a type and a
default. A text box passes what is typed; a dropdown lists fixed
choices (one per line,
valueorLabel=value) or the rows of a search of its own, such asindex=app | stats count by service, with the value and label columns named (the first column when not) and an optional All choice. The searches read an input as$id$. - Base searches is the strip under the inputs. Add base search gives it an id and a query; a base search can have its own time range. Removing one that panels extend turns its query into theirs.
- Add panel opens the panel editor: a title, the visualization, the
search (its own, or a base search extended with commands that start
with a pipe, such as
| stats count by status), a time range, and the settings of the chosen visualization, with a live preview on the right (Enterin the query runs it). Add to dashboard puts it on the grid. - On the grid, drag a panel by its head and resize it by its edges. Each panel's tools open it in the search page, download its result as CSV, edit, duplicate or remove it.
- Save stores the dashboard; Cancel drops the changes. Saving a dashboard someone else changed in the meantime is refused, so nobody's work is overwritten unseen. Export JSON downloads the dashboard as the document below, for a backup, a copy on another host, or editing by hand.
Viewing a dashboard, the inputs sit under the head; changing one reruns
the panels whose searches mention it. The time picker overrides the
dashboard's default range for that visit; a base search's or a panel's
own range still wins, as it does in the editor. The URL carries the
range and the input values (#dashboards/web?earliest=-7d&in.host=web1),
so a link shares a filled-in view. Refresh reruns every panel (the
time it last ran is shown beside it), and the auto-refresh select keeps
doing so. The base-search strip shows, per base search, how many panels
extend it, the range they ran over, the slowest one and the first
error. Clicking a slice or a bar opens the search page with that value
added to the search, or, when the panel says so, sets a dashboard input
to the value (a pie of services that fills the service input, say); the
arrow in a panel's head opens its whole search. Present shows the
dashboard alone, full screen, for a wall display; ?kiosk=1 on the URL
opens it that way. The menu button beside it exports the dashboard as
JSON or duplicates it.
The Light/Dark switch redraws every chart in the other palette.
Inputs and tokens#
An input's value replaces $id$ wherever a base search, a panel's
commands or a panel's own search mentions it, before the search runs:
with the base search index=app service=$svc$ and checkout chosen,
the panels run index=app service=checkout .... The value is put in as
it is, so a token can stand for a field value, a field name
(| stats count by $field$) or a whole clause; an input left empty, or
a dropdown's All choice, becomes *, so a blank text box matches
everything. The server checks on save that every token names an input
and that the searches parse with the defaults in place. A dropdown fed
by a search runs that search over the dashboard's range (or its own) when
the dashboard opens; its choices are the rows, so keep it to a stats
or top.
Base searches and panels#
A base search is the shared part of a query, and its result is shared
too: when two or more panels extend the same base over the same range,
the dashboard runs the base once as a search job (JOBS.md)
and each panel's own commands run over the job's result in the engine
(POST /api/v1/jobs/{id}/search), so the dashboard costs one ClickHouse
search per base rather than one per panel. The base strip says so ("ran
once in 120 ms, 125 rows, sliced for 5 panels"), a sliced panel's header
says "from the base", and the job is deleted once the panels are drawn.
A panel runs its own search instead, the base query with its commands appended, when sharing would save nothing or change what it shows:
- a panel alone on its base: one search beats a job and a slice;
- a panel whose commands do not start with a pipe, or cannot run in the
engine, such as
transaction(the slice answers 400 and the panel falls back to its own search); - every panel of a base that returns raw events when the event cap cut
them. The base is asked for the host's cap of events
(SEARCH-LIMITS.md); when more matched, the panels'
aggregations would see part of the data, so each runs its own search,
whose
statsortimechartrun in SQL over everything. A base that ends in a transforming command is complete and always shared; a base of raw events is shared while its events fit under the cap.
So keep a base to the filter and the first aggregation
(index=web | bin _time span=1m | stats count by _time, status) and let
the panels sum, pick and chart from there. Panels with the same query
and range share one request either way. A dashboard runs its searches
through a pool the size of the account's concurrent-search cap and waits
out a busy answer, so it never trips the 429 by itself; it still counts
against the host's cap while it runs, and a shared base is one job under
the account's jobs cap while its panels are drawn.
How a panel reads its result:
| Type | What it draws |
|---|---|
line, area |
one series per numeric column over _time (a timechart), or over the first text column; smooth, stacked, points, axis from zero |
bar |
one series per numeric column by the first text column (stats count by host, top, chart ... over ... by ...); vertical or horizontal, stacked, value labels |
pie |
the first text column as slices, the first numeric column as values; donut or full, rose, labels, slices kept before the rest fold into "other" |
table |
every column, sortable by clicking a header; rows shown |
gauge |
one number: the chosen field, or the first numeric column, of the first row (a stats) or of the newest complete bucket (a timechart); minimum, maximum, unit, decimals, amber and red thresholds, "lower is worse" |
single |
the same number, large, with the change against the previous bucket and a sparkline when the result is a time series; the thresholds colour it |
The category and value fields can be named instead of detected, and a
unit and decimals apply to every chart. A timechart's newest bucket is
still filling, so gauges and single values skip it by default ("Skip the
newest, still-filling bucket").
API#
| Method and path | Who | Purpose |
|---|---|---|
GET /api/dashboards |
any | list: id, title, description, owner, panel count, updated_at, can_edit |
GET /api/dashboards/{id} |
any | the dashboard and can_edit |
POST /api/dashboards |
user | create; the caller owns it; an empty id is made from the title |
PUT /api/dashboards/{id} |
user | replace own (admins: any); send the updated_at you loaded and a dashboard changed since answers 409 conflict |
DELETE /api/dashboards/{id} |
user | delete own (admins: any) |
A dashboard:
{
"id": "web", "title": "Web traffic", "description": "",
"earliest": "-24h", "latest": "now", "refresh_s": 60,
"inputs": [
{"id": "host", "label": "Host", "type": "dropdown", "default": "*", "all": true,
"search": "index=web | stats count by host", "value_field": "host", "label_field": ""},
{"id": "status", "label": "Status", "type": "text", "default": ""}
],
"searches": [{"id": "web", "query": "index=web sourcetype=nginx:access host=$host$ status=$status$", "earliest": "", "latest": ""}],
"panels": [{
"id": "status", "title": "By status", "type": "pie",
"base": "web", "query": "| stats count by status",
"earliest": "", "latest": "",
"layout": {"x": 0, "y": 0, "w": 4, "h": 4},
"options": {"donut": true, "drilldown": "token", "drilldown_token": "status"}
}]
}An input is text or dropdown; a dropdown has choices
([{"label": "Errors", "value": "error"}]) or a search with
value_field and label_field, and all adds the All choice. A panel's
options.drilldown is search (open the search page, the default),
token (set the input drilldown_token to the clicked value) or none.
The same document is what Export JSON writes and Import JSON
reads; id, owner and the timestamps are dropped on import and a
taken id gets a new one from the title.
type is one of pie, bar, line, area, table, gauge,
single. With base, query is the commands appended to that base
search (starting with a pipe, or empty for the base result as it is);
without, it is the whole search. layout places the panel on a
12-column grid (x + w at most 12, h and y in rows). options
are the visualization's settings as the UI writes them; the server only
bounds their size. Every query is parsed and every time range checked on
save; a refused dashboard answers 400 invalid with what is wrong.
Limits: 12 inputs with 200 choices each, 20 base searches, 60 panels,
10,000 characters per query.
Dashboards live in dashboards.json under the engine's data directory
and go into backups with the rest of it (BACKUP.md).
Creating, changing and deleting one is audited (dashboard.create,
dashboard.update, dashboard.delete).
Not yet#
- Time and multi-select inputs, inputs scoped to one panel, and drilldown that targets another dashboard.
- A base result kept between refreshes, or shared across dashboards: every run of a dashboard runs its bases again.
- Searches run in UTC like the search page's: a dashboard cannot set a
time zone for snaps such as
@d. - Private dashboards, and a home dashboard per user.
- Scheduled PDF or image reports, and embedding a panel elsewhere.
- Further visualizations: scatter, heatmap, maps, a log-event list panel.