Skip to content

Metrics

The metrics dashboard and route aggregation command are provided by the native_observability_metrics submodule. It is part of the RAW install tier; enable it with drush no:preset:raw, or directly with drush en native_observability_metrics -y.

Routes

Route Path Permission
native_observability_metrics.dashboard /admin/reports/native-observability/metrics view native observability metrics

Metrics dashboard

Open /admin/reports/native-observability/metrics. MetricsDashboardController::dashboard() renders the latest persisted aggregation snapshot (RouteMetricsAggregator::getLatestSnapshot()):

  • The aggregation window label (start and end time of the snapshot currently shown).
  • Summary cards: total requests, weighted average duration, max P95, max P99, peak throughput.
  • Two bar charts: requests by route, and average duration by route.
  • A table with, per route: request count, throughput per minute, average duration, P95 and P99 duration.

Metrics are grouped by route_name (falling back to path when the route name is empty), and the system.css_asset / system.js_asset internal routes are excluded from aggregation.

Running aggregation from the dashboard

A collapsed Manual aggregation section embeds MetricsAggregationRunForm. Its single Run aggregation now button calls RouteMetricsAggregator::aggregateLatestCompletedWindow() synchronously and redirects back to the dashboard with a status message reporting how many routes were aggregated (or a warning if the window had no data).

Completed window vs rolling window

RouteMetricsAggregator aggregates trace durations from the native_observability_trace table over a time window, computes count, throughput, average, P95 and P99 per route, and persists the result via DatabaseMetricsStorage::replaceWindowMetrics(). Two window strategies are available:

  • Latest completed window: a fixed 5-minute (300 second) bucket aligned to wall-clock time (floor(now / 300) * 300), ending at the start of the current bucket. This only aggregates requests from a window that has already fully elapsed, so in-flight traffic in the current bucket is never partially counted.
  • Rolling window: an arbitrary window of $seconds ending at the current time (now - seconds to now). This includes the most recent traffic, at the cost of the window contents shifting on every run.
flowchart LR
    A[native_observability_trace rows] --> B{Window strategy}
    B -- Latest completed --> C["floor(now/300)*300 - 300 .. floor(now/300)*300"]
    B -- Rolling --> D["now - seconds .. now"]
    C --> E[aggregateWindow]
    D --> E[aggregateWindow]
    E --> F[replaceWindowMetrics: persisted snapshot]
    F --> G[Metrics dashboard]

Drush: aggregation command

native-observability-metric:aggregate (alias nom:aggregate) runs the same aggregation logic from the command line.

# Aggregate the latest completed window (same as the dashboard button).
drush native-observability-metric:aggregate

# Aggregate a rolling window ending now.
drush native-observability-metric:aggregate --rolling=1 --seconds=300

Options:

  • --rolling: enable rolling window aggregation. Accepts 1 or 0; defaults to 0 (latest completed window).
  • --seconds: rolling window duration in seconds, used only when --rolling=1. Defaults to 300.

The command prints a table (route, requests, throughput per minute, average duration, P95, P99) and a success message with the number of aggregated route snapshots.

Scheduling with cron

native_observability_metrics implements hook_cron(), which already calls aggregateLatestCompletedWindow() on every Drupal cron run. No extra crontab entry is required to keep the "latest completed window" snapshot fresh as long as Drupal cron runs regularly.

The nom:aggregate --rolling=1 variant is not wired into Drupal cron. If you need a rolling-window snapshot, or you need aggregation to run more often than your Drupal cron interval, schedule the drush command directly, for example with a system crontab entry:

*/5 * * * * drush --root=/path/to/drupal nom:aggregate --rolling=1 --seconds=300