Skip to main content
Version: 0.12.1

Metrics

The manager registers these series through Micrometer. They are emitted to whichever sink is active (QOD_METRICS_SINK); under the default Prometheus sink they appear at GET :20900/metrics. For how to scrape, push to a cloud monitor, or import the Grafana dashboard, see Observability.

Application metrics​

MetricTypeLabelsMeaning
statements_totalcountertenant, pool, statusStatements executed, partitioned by outcome status. Drives QPS and error-rate panels.
statement_duration_secondshistogramtenant, poolStatement execution latency; the source of the p50/p95/p99 percentiles.
flightsql_sessions_activegauge(none)Currently open FlightSQL sessions.
pool_nodesgaugetenant, pool, roleNode count per pool, broken down by node role.
node_healthygaugetenant, pool, node_id, role1 when the node is healthy, 0 otherwise.
node_draininggaugetenant, pool, node_id, role1 when the node is draining in-flight work before shutdown.
node_in_flightgaugetenant, pool, node_id, roleStatements currently executing on the node.
node_ewma_latency_secondsgaugetenant, pool, node_id, roleEWMA of completed-statement latency, the signal the router uses to pick the least-loaded node.

Routing metrics​

Emitted per routed statement by the cache-aware placement layer. The locality series (routing_tables_total, routing_placements_total) run on any routing policy and stay populated even with QOD_ROUTING_CACHE_AWARE=false; the decision and load series describe placement outcomes.

MetricTypeLabelsMeaning
routing_tables_totalcountertenant, pool, resultTable references seen, split into new (first time this table is routed) and repeat (seen before). A low repeat rate means locality has little to exploit.
routing_placements_totalcountertenant, pool, resultRepeat-table routings by whether the table stayed on its last node or switched to another. The switch rate is the locality-loss (scatter) signal: high means placement is being destroyed.
routing_decisions_totalcountertenant, pool, outcomePlacement decisions by outcome: claim, sticky-fresh, sticky-stale, overflow-new-home, overflow-evict-home, pinned-sticky, pinned-move, no-refs-fallback, not-eligible, flag-off. Frequent overflow-evict-home on a pool means three homes are not enough for its hottest tables. pinned-sticky / pinned-move mark statements a transaction pin or soft preferredNode placed rather than the scorer, so they are excluded from the overflow signal.
routing_load_ratiosummarytenant, poolChosen-node in-flight count over the pool average. Should stay under routing.loadCapFactor; a sustained excess means the load cap is not binding.

Maintenance metrics​

Emitted per finished managed-maintenance run. These series carry the qod_ prefix; the legacy series above predate the prefix convention.

MetricTypeLabelsMeaning
qod_maint_runs_totalcountertenant, tenant_db, resultMaintenance runs by outcome (succeeded, failed, partial). A rising partial count usually means the pinned-file guard is firing.
qod_maint_bytes_reclaimed_totalcountertenant, tenant_dbCatalog bytes released by runs (physical deletion lags by the cleanup grace window).
qod_maint_files_compacted_totalcountertenant, tenant_dbFiles touched by the merge and rewrite steps.
qod_maint_snapshots_expired_totalcountertenant, tenant_dbSnapshots expired (pinned snapshots are skipped, never counted here).
qod_maint_duration_secondstimertenant, tenant_dbEnd-to-end run duration, including maintenance-node spawn time.

Authorization metrics​

Every tenant statement is authorized on its node: the node asks the manager replica that minted its session handle for a verdict, caches it, and refuses what no grant (or the tenant's OPA policy) covers. See Access control model. Dry runs (qod tenant opa-test --sql) are not counted.

Decisions taken by this replica's decide endpoint (POST /api/internal/authz/decide):

MetricTypeLabelsMeaning
qod_authz_decisions_totalcountertenant, kind, outcome, modeDecisions answered to nodes. kind is plan (a statement judged on the plan DuckDB bound) or screen (the check quack's authorization callback asks for); outcome is allow, refuse or unavailable; mode is qod (grants) or opa (the tenant's OPA). A rising unavailable rate means decisions could not be had in time, which users see as QoD: authorization unavailable, retry.
qod_authz_decide_duration_mssummarykindTime to take one decision, in milliseconds, with fixed buckets from 0.5 to 5000. Prometheus exports _bucket, _count, _sum and _max. A grant decision takes well under a millisecond; an OPA tenant's runs up to its OPA timeout.

Per-node counters, read from each node's system.main.qod_authz_stats() by the health probe and exported on Prometheus scrapes by the HA leader only (a single manager always leads), so sum by (node) is not multiplied by the replica count. A node that leaves the pool loses its series.

MetricTypeLabelsMeaning
qod_node_authz_plan_cache_hits_totalcountertenant, pool, nodePlan verdicts served from the node's verdict cache.
qod_node_authz_plan_cache_misses_totalcountertenant, pool, nodePlan verdicts not in the cache, each followed by a decide call.
qod_node_authz_decide_calls_totalcountertenant, pool, nodeCalls the node made to the manager for a verdict.
qod_node_authz_decide_unavailable_totalcountertenant, pool, nodeCalls that got no verdict in time (replica down, restarted or unreachable from the node).
qod_node_authz_decide_refused_totalcountertenant, pool, nodeCalls answered with a refusal.
qod_node_authz_local_refusals_totalcountertenant, pool, nodeStatements the node refused on its own while planning them, without a verdict from the manager (for example a statement shape it cannot describe).
qod_node_authz_screen_calls_totalcountertenant, pool, nodeScreen checks the node ran for quack's authorization callback.
qod_node_authz_verdict_cache_evictions_totalcountertenant, pool, nodeVerdicts evicted from a full cache. Sustained growth means QOD_AUTHZ_CACHE_ENTRIES is too small for the working set.
qod_node_authz_verdict_cache_sizegaugetenant, pool, nodeVerdicts currently cached on the node.
qod_node_authz_credential_sets_sizegaugetenant, pool, nodeUsers' own S3 credential sets currently held by the node.

Cache metrics​

Each replica registers its own bounded caches through Micrometer's Caffeine binder, so a sum across replicas is the fleet's total. The cache label is one of qod_minted_handles (session handle contexts this replica minted), qod_issued_handles (handles whose users' S3 keys a node may fetch), qod_dry_run_results (OPA dry-run inputs), qod_effective_sets (resolved grants per principal) and qod_opa_decisions (registered only while QOD_OPA_CACHE_TTL_SEC is above zero).

MetricTypeLabelsMeaning
cache_sizegaugecacheEntries currently held.
cache_gets_totalcountercache, resultLookups, result = hit or miss.
cache_evictions_totalcountercacheEntries evicted to stay under the bound. A rising cache_evictions_total{cache="qod_minted_handles"} means the replica mints more handles than QOD_AUTHZ_HANDLE_CONTEXTS_MAX keeps: raise it.
qod_cache_capacitygaugecacheThe configured bound, to chart how full each cache is.

Micrometer's binder also exports its other standard cache_* series (puts, eviction weight) under the same cache label.

DuckDB engine metrics​

Scraped from each node's DuckDB engine (duckdb_memory(), duckdb_temporary_files()) by the background health probe, one extra round-trip per node per QOD_HEALTH_CHECK_INTERVAL_SEC tick. A node that has never been scraped successfully publishes no row (rather than a misleading zero); a failed scrape keeps the previous sample until the next tick.

MetricTypeLabelsMeaning
node_duckdb_memory_used_bytesgaugetenant, pool, node_id, roleBuffer-manager memory in use, summed across all consumers (base tables, hash tables, parquet readers, ...). Compare against the node's memory_limit to spot memory pressure before latency degrades.
node_duckdb_temp_storage_bytesgaugetenant, pool, node_id, roleBytes the buffer manager has moved to temporary storage.
node_duckdb_spill_filesgaugetenant, pool, node_id, roleLive spill-to-disk files. Non-zero means queries are exceeding the memory budget and spilling.
node_duckdb_spill_bytesgaugetenant, pool, node_id, roleTotal size of live spill files.

JVM and process metrics​

Registered by the Micrometer JVM and process binders:

MetricTypeMeaning
jvm_memory_used_bytesgaugeHeap and non-heap memory in use.
jvm_gc_pause_seconds_sumcounterCumulative GC pause time.
jvm_threads_live_threadsgaugeLive thread count.
process_uptime_secondsgaugeProcess uptime since manager start.

Common labels​

Every series can carry static deployment labels when these are set, useful for separating environments in a shared Grafana:

VariableLabelExample
QOD_METRICS_DEPLOYMENTdeploymentprod-eu
QOD_METRICS_REGIONregioneu-west-1