Skip to content

Prometheus and Elastic export

The native_observability_export submodule provides the Prometheus scrape endpoint and the Elastic NDJSON export. It is part of the RAW preset (drush no:preset:raw), the minimum tier for machine-only consumers.

Routes

Route Path Permission
native_observability_export.settings /admin/config/development/native-observability/settings/export administer native observability export
native_observability_export.prometheus_metrics /admin/reports/native-observability/prometheus access native observability prometheus endpoint
native_observability_export.prometheus_scrape /native-observability/prometheus none, route declares _access: 'TRUE'
native_observability_export.elastic_export /admin/reports/native-observability/elastic view native observability traces

Admin view and scrape endpoint

Both prometheus_metrics and prometheus_scrape resolve to the same controller method, PrometheusMetricsController::render. They return identical Prometheus text output; only the access model differs.

  • /admin/reports/native-observability/prometheus is gated by the access native observability prometheus endpoint permission, for manual inspection from inside the Drupal admin.
  • /native-observability/prometheus carries no Drupal permission, because external scrapers do not send a Drupal session. Access control on this route is the bearer token described below.
sequenceDiagram
    participant Prometheus
    participant Drupal as PrometheusMetricsController
    Prometheus->>Drupal: GET /native-observability/prometheus (Authorization: Bearer <token>)
    alt no token configured
        Drupal-->>Prometheus: 200 metrics body
    else Authorization header missing
        Drupal-->>Prometheus: 401
    else token mismatch
        Drupal-->>Prometheus: 403
    else token matches
        Drupal-->>Prometheus: 200 metrics body
    end

When no bearer token is configured, the endpoint is publicly readable and the settings form shows a persistent security warning.

Metrics exposed

Ten metrics are served. Names and help text below are read from the endpoint itself, so they are what a scrape actually returns.

Metric Type Meaning
drupal_http_requests_total counter Total HTTP requests recorded, all time.
drupal_http_requests_window gauge HTTP requests inside the rolling window.
drupal_http_request_duration_ms summary Request duration by quantile and route.
drupal_http_error_rate gauge Percentage of 5xx responses in the rolling window.
drupal_http_ajax_requests_total counter Total AJAX requests recorded, all time.
drupal_cache_operations_total counter Cache events by operation and bin, all time.
drupal_span_count gauge Spans by category in the rolling window.
drupal_span_duration_avg_ms gauge Average span duration by category in the rolling window.
drupal_outbound_http_requests_total gauge Outbound HTTP spans by destination host in the rolling window.
drupal_outbound_http_duration_avg_ms gauge Average outbound HTTP span duration by destination host.

Two naming details will bite you when writing queries. Metrics ending in _total are counters over all time, and the ones scoped to the rolling window say window or are gauges, so mixing them in one query compares different time bases. And drupal_outbound_http_requests_total is a gauge despite the _total suffix, because it counts spans inside the window rather than accumulating. Do not wrap it in rate().

The rolling window is prometheus_window_seconds, 300 seconds by default. See Export settings for that and for the label strategy, whose machine names do not describe what they emit.

Cache metrics carry operation and bin labels:

drupal_cache_operations_total{operation="HIT",bin="page_cache"} 828
drupal_cache_operations_total{operation="INVALIDATED",bin="cache_tags"} 1263
drupal_cache_operations_total{operation="CACHEABLE",bin="response_cacheability"} 63

When the series cap is exceeded the reader drops the lowest-count series and emits drupal_prometheus_truncated{reason="series_limit"} 1. Alert on that series: without it, truncation looks like a traffic drop.

Bearer token

Generate and store the token with Drush:

drush native_observability:token:generate prometheus
# alias:
drush no:token:generate prometheus

The command prints the generated value once and stores it in the state key native_observability_export.secret.prometheus_bearer_token. The token can also be set from the settings form field, which is write-only: an empty submission keeps the current token, and the sentinel value __clear__ removes it.

Metrics window, label strategy, and max series settings for the scrape output are documented in Configuration.

Elastic export

ElasticTelemetryExportController::export returns stored traces as application/x-ndjson, one JSON document per line, built by ElasticTelemetryBuilder. Supported query arguments:

Argument Meaning
limit Row limit, clamped between 1 and 1000, default 200
status_code Filter by HTTP status code
path Filter by request path
min_duration_ms Minimum trace duration in milliseconds
max_duration_ms Maximum trace duration in milliseconds

Example:

curl "https://your-site.example/admin/reports/native-observability/elastic?limit=500&status_code=500"

Example Prometheus scrape_config

scrape_configs:
  - job_name: drupal_native_observability
    bearer_token: <your-token>
    metrics_path: /native-observability/prometheus
    scheme: https
    static_configs:
      - targets: ['your-site.example']