What goes in a Presto or Trino monitoring dashboard in Metabase?
A Presto or Trino monitoring dashboard tracks query volume and state, wall-time percentiles, how long work sits queued in each resource group, splits in flight across the workers, memory pool pressure, and the error codes queries fail with. Metabase connects to Presto and Trino natively, so every card is plain SQL over the engine's own system.runtime tables and the event listener's history table.
For: platform and data engineering teams who own the query engine. Grain: one row per query from the event listener, plus live snapshots of tasks and nodes.
Source:
system.runtime.queries, system.runtime.tasks, system.runtime.nodes, the JMX connector, and a QueryCompletedEvent table.
What does a Presto or Trino monitoring dashboard look like?
Here’s the layout this guide builds. Cluster-level counters sit at the top; the middle section is throughput and latency — how many queries, how long they take, how long they wait, and how much split work is in flight; the bottom section is the pressure half, where the memory pool, worker health, and error codes name the thing that is actually breaking.

An example Presto and Trino monitoring dashboard in Metabase, built from system.runtime and the event listener. Figures are illustrative.
Which cards belong on a Presto or Trino monitoring dashboard?
Eight cards. Four describe the workload, four describe the pressure it puts on the cluster — and it is the pairing that makes the dashboard diagnostic rather than decorative.
- Queries by hour and final state — finished, failed, cancelled (stacked bar)
- Query wall time, p50 and p95 by hour (line)
- Queue time vs. execution time by resource group (line)
- Splits in flight — queued and running across the workers (area)
- Cluster memory pool reserved against total distributed bytes (line)
- Failures by error code — memory limit, no nodes available, syntax (row)
- Worker nodes and CPU time per hour (combo)
- Top queries by CPU time, with splits and bytes scanned (table)
What data does the dashboard need?
system.runtime.queries— the coordinator’s live view:state,user,source,resource_group_id,queued_time_ms,analysis_time_ms,planning_time_ms, and the query text. Recent queries only.system.runtime.tasks— per node and stage:queued_splits,running_splits,completed_splits,split_cpu_time_ms,raw_input_bytes, andraw_input_rows.system.runtime.nodesfor the worker roster —node_id,coordinator,node_version, andstate(active, inactive, shutting down).- The JMX connector for memory:
jmx.current."trino.memory:name=general,type=clustermemorypool"gives free and total distributed bytes, blocked nodes, and assigned queries (com.facebook.presto.memoryon Presto). - An event-listener table of
QueryCompletedEventrows — wall, queued, and CPU time, peak user memory, completed splits, total bytes, andfailureInfo.errorCode. This is what every trend card reads.
How do you build it?
- Connect Presto or Trino to Metabase with a read-only user, and make sure the catalog list includes
systemandjmx— they are ordinary catalogs, and without them half the cards have no source. - Turn on an event listener that persists
QueryCompletedEventto a table the cluster can query, then expose that table through the same connection. Without it you have a status page, not a dashboard. - Model the event table once — milliseconds to seconds, a duration bucket, a normalized query fingerprint, and the resource group parsed out of
resource_group_id— so no two cards disagree about what “slow” means. - Build the queue-time and memory-pool cards first. Together they tell you whether the cluster is admission-bound or execution-bound, which is the only question worth answering before you tune anything.
- Add filters for cluster, resource group, and date range, and alert the platform channel when reserved memory crosses its threshold or the failure rate doubles.
Example card SQL
SELECT
date_trunc('hour', end_time) AS hour,
resource_group,
count(*) AS queries,
count_if(state = 'FAILED') AS failed,
round(approx_percentile(queued_time_ms, 0.95) / 1000.0, 2)
AS queue_p95_s,
round(approx_percentile(wall_time_ms, 0.50) / 1000.0, 2) AS wall_p50_s,
round(approx_percentile(wall_time_ms, 0.95) / 1000.0, 2) AS wall_p95_s,
round(sum(cpu_time_ms) / 3600000.0, 1) AS cpu_hours,
sum(completed_splits) AS splits,
round(sum(total_bytes) / power(1024, 4), 2) AS tb_scanned
FROM metrics.query_events
WHERE end_time >= current_timestamp - interval '14' day
GROUP BY 1, 2
ORDER BY 1, 2; Related
Metrics
Integrations
Dashboards
FAQ
What is a Presto or Trino monitoring dashboard?
system.runtime tables expose the coordinator's live view, and the event listener writes one durable row per finished query. Metabase connects to Presto and Trino natively, so the dashboard is ordinary SQL against the same cluster you are watching.Does the dashboard change between Presto and Trino?
system.runtime.queries, system.runtime.tasks, and system.runtime.nodes exist in both, with the same columns for state, queued time, splits, and input bytes. The differences are naming — the JMX beans live under trino.memory on one and com.facebook.presto.memory on the other, the session and config properties drifted apart, and each project has added error codes the other does not have. Point the cards at whichever bean and error-code list your cluster reports and the layout is unchanged. Managed distributions are the real exception: on Starburst you get the same tables plus an insights schema, while Athena is serverless and gives you CloudWatch and the query-execution API instead of system.runtime.Why is system.runtime not enough on its own?
system.runtime.queries is materialized from the coordinator's in-memory state, which keeps only the most recent queries — governed by query.max-history (100 by default) and query.min-expire-age (15 minutes) — and it empties entirely when the coordinator restarts. That is perfect for the "what is happening right now" cards and useless for trends. The fix is the event listener: implement or install one, have it write a QueryCompletedEvent row per query into a table the cluster can also read, and point every trend card at that table. The live tables then only power the running/queued counters.What does queue time tell me that wall time doesn't?
hardConcurrencyLimit or softMemoryLimit is admitting too few queries at once, and the fix is resource-group configuration or more workers. Steady queue time with rising execution means the queries themselves got heavier — more data, worse join order, a missing partition filter — and no amount of scheduling helps. Resource groups are also the only place a dashboard can see who is starving whom, since a single greedy group can hold the whole cluster's memory.What do splits tell me that query count doesn't?
system.runtime.tasks gives you queued_splits, running_splits, and completed_splits per node, so a chart of splits in flight is the cluster's true load curve, and a persistently deep split queue with idle CPU usually means small files, not too few workers.How do I read the memory pool cards?
query.max-memory-per-node, and the coordinator refuses to admit a query when the general pool cannot cover it. Chart reserved bytes against total distributed bytes, and watch two things — the percentage reserved, and the count of blocked nodes. Sustained above roughly 85% and you will see EXCEEDED_GLOBAL_MEMORY_LIMIT failures and long queue times together, which is the signature of a memory-bound cluster rather than a CPU-bound one. The three real fixes are lowering per-query limits so one query cannot eat the pool, enabling spill-to-disk for the heavy joins and aggregations, or adding workers.