Skip to main content
drupalreleases

Use direct release data with your AI assistant.

Learn more

Real-time Performance Monitor

No security coverage Under active development

This module provides real-time monitoring of your Drupal website's performance, tracking database queries, PHP execution, and frontend rendering. It sends instant alerts via email or Slack when performance issues are detected, without requiring heavy external installations.

Real-time Performance Monitor finds out why a Drupal site is slow and tells you where to fix it. It traces requests from the browser through PHP and SQL to external APIs, records every duplicate query, slow function, uncacheable page and heavy asset, and alerts you by email, Slack or the Drupal log. It runs inside Drupal, with no external agent or SaaS account.

It works like a lightweight, self-hosted Application Performance Monitoring (APM) tool in the style of Dynatrace or New Relic, built specifically for Drupal. It understands Drupal concepts that generic tools do not: routes and bundles, Page Cache and Dynamic Page Cache headers, cache bins served by Redis, Memcache or MySQL, cache contexts that make a page uncacheable, and the PHP code that issued each SQL statement.

Why use it

  • Find N+1 and duplicate SQL, and why it happens. Every repeated statement is shown with the PHP class, method, file and line that ran it. It also says whether the data should have come from Redis, Memcache or a MySQL cache table.
  • See where a slow page spends its time. Each traced request is split into PHP code, SQL and external HTTP calls. A timeline covers routing, controller, rendering and post-response work.
  • Catch pages that silently stop caching. You are alerted when a page comes back UNCACHEABLE from Page Cache or Dynamic Page Cache. The alert names the likely culprit: max-age 0, a user or session cache context, too many cache tags, or the kill switch.
  • Measure what real visitors experience. Core Web Vitals (LCP, INP, CLS, TTFB) come from real browsers, along with the slowest CSS, JS, fonts and images, and JavaScript errors. Each page view is linked to the backend trace that produced it.
  • Get told about regressions. Baseline-based problem detection compares every request group with its own 7-day history, and gives root-cause hints such as a slower SQL statement, a new N+1 loop, a cache hit drop or a recent deployment.
  • Prove a release made things better or worse. Deployment markers from Drush or CI/CD come with a before/after comparison of each release.

Features

Alerts (email, Slack, watchdog)

Alert Triggered when What the alert contains Duplicate SQL A statement runs at least N times in one request (default 5) Each repeated statement with its count and time, whether it repeats with identical arguments or is an N+1 pattern, its calling code, and its cache source: a Redis/Memcache miss that fell through to MySQL, a read from a MySQL cache_* table (the bin is not on Redis/Memcache), a cache-tag lookup, or a query with no cache layer. Includes a summary of the site's Redis/Memcache setup and connection status. Slow SQL A statement takes longer than the limit (default 100 ms) The statement, its duration and caller, plus an automatic EXPLAIN that flags full table scans, unused or missing indexes, Using filesort and Using temporary Slow PHP / high memory The request exceeds the time limit (default 1000 ms) or the peak memory limit (default 256 MB) Controller vs core/render time, peak memory, and the top functions when XHProf is installed Uncacheable page A successful, non-admin GET response is UNCACHEABLE in Page Cache or Dynamic Page Cache Both cache headers, max-age, cache contexts, tag count and the likely culprits Frontend A real visitor's page load, LCP, INP, CLS or TTFB breaches its limit Core Web Vitals with good/poor ratings, JS and CSS payload, unused CSS, render-blocking resources, the slowest and heaviest assets (server wait vs download), image checks (lazy loading, oversized, JPEG/PNG) and CSS/JS aggregation status Problem detected Behaviour deviates from its baseline (see Problems below) The problem, its impact and root-cause analysis

Each channel (watchdog, email, Slack) has its own frequency cap per URL and alert type: always, daily, weekly, every two weeks or monthly. Paths can be excluded with wildcards.

APM dashboards

All dashboards are under Reports → Performance APM (/admin/reports/apm). Every tab has a ? link that opens a detailed help page for it.

Tab What it shows Overview Request count, p50 / p90 / p99 response time, failure rate, Drupal cache hit rate, SQL per request, open problems and real-user LCP. Includes response time and throughput charts, the code / SQL / external time split, top requests by total time contribution, key requests and SLO status. Services Traffic grouped by request naming rules (for example /{lang}/case-studies/*|Case study page), falling back to route and bundle. Each group gets percentiles, failure %, cache hit %, SQL per request and time share. Traces One trace per sampled request, similar to Dynatrace PurePath. It shows the timing breakdown and request timeline, request attributes (route, controller, bundle, language, anonymous or logged-in, X-Drupal-Cache, X-Drupal-Dynamic-Cache), and the SQL run (count, time, duplicates, cache source, caller). It also shows outgoing HTTP calls, XHProf functions, warnings and errors logged during the request, and the real-user page views of that response. You can filter by cache status, user type, language, minimum time, 5xx and key requests. Database SQL statements across all traces, ranked by total time contribution, with executions per request (N+1 flag), identical repeats, cache source and calling code. Each statement links to every trace that ran it. Code hotspots Time spent per lifecycle phase, PHP time per controller, the slowest methods (XHProf), and external services with call count, latency and errors. Frontend (RUM) Core Web Vitals at the 75th percentile by page, browser and device. The resource waterfall splits each resource into DNS, TCP/TLS, server wait and download, and flags third-party resources. JavaScript errors are grouped by message, source and line. Issue history Every duplicate SQL, slow SQL, slow PHP / slow function, uncacheable page and heavy CSS/JS or slow-asset occurrence. Records are kept even when the alert itself was throttled, for 30 days by default (configurable). It shows the top duplicate statements, slowest functions and pages, JS/CSS size per page, and the assets taking the most time to load. Problems Automatic, baseline-based problem detection (see below) Releases Deployment markers with a before/after comparison of p50, p90, failure rate, SQL per request and cache hit rate, plus the request groups that regressed the most Synthetic Scheduled HTTP monitors for key URLs, with availability, response time, server wait, cache header and run history SLOs Service level objectives such as "95% of homepage requests under 1 s" or "availability 99.9%", with error budget tracking Topology A live dependency map: real users → page cache → PHP → Drupal → MySQL / Redis / Memcache → external services, with the health of each Health report Live checks of Page Cache and Dynamic Page Cache, max-age, Twig debug and cache, and cache bins still stored in MySQL. It also shows the Redis/Memcache hit ratio and evictions, CSS/JS aggregation, OPcache hit rate and memory, PHP-FPM workers and "max children reached", the last cron run, queue backlog, dblog volume and available profilers.

Problem detection and root-cause analysis

On cron, at most every 5 minutes, the last hour of each request group is compared with its own 7-day baseline. A problem is opened when:

  • p90 response time is higher than the baseline by a configurable factor (default 1.5×) and by at least 200 ms
  • the 5xx failure rate is at least 5% and 5 points above the baseline
  • real-user LCP (p75) for a page is above 4 seconds
  • a synthetic monitor fails twice in a row

Each problem comes with root-cause hints:

  • which layer grew the most (PHP code, SQL or external calls)
  • whether SQL executions per request jumped (a new N+1 loop)
  • which SQL statement added the most time
  • whether the Drupal cache hit ratio dropped
  • whether a deployment happened shortly before

Problems resolve automatically when the condition clears.

How data is collected

  • Backend traces: Drupal's database query log, kernel events and the http_client middleware capture SQL, timing and outgoing HTTP calls. A logger records warnings and errors per request. A trace ID is added to each response as Server-Timing: rpm;desc=…, including page-cache hits.
  • Sampling: a configurable share of requests is traced (default 25%). Slow requests, 5xx responses, requests that logged errors, and synthetic checks are always kept. Traces are written after the response has been sent.
  • Real User Monitoring: a small script uses the browser's PerformanceObserver and Resource Timing APIs. For a configurable share of page views (default 25%), plus every page view with a JavaScript error, it sends a beacon when the page is hidden. The beacon endpoint is rate-limited per IP and validates and sanitizes all input.
  • Storage: data is kept in the site's own database, in 9 tables prefixed rpm_. Old rows are purged on cron: traces and RUM after 7 days by default, issue history after 30 days. Both periods are configurable.

Requirements

  • Drupal 10, 11 or 12
  • MySQL or MariaDB for the automatic EXPLAIN on slow queries. The other features work on any database Drupal supports.
  • Optional: the Redis or Memcache module, for cache-source attribution and hit-ratio statistics
  • Optional: the XHProf PHP extension, for function-level hotspots
  • Optional: PHP-FPM, for the worker statistics in the Health report

Installation

  1. Install as you would normally install a contributed Drupal module: composer require drupal/realtime_performance_monitor, then drush en realtime_performance_monitor.
  2. If you are updating from an earlier release, run drush updb to create the APM tables.
  3. Grant the View performance APM dashboards permission to the roles that need the dashboards. The permission is marked as restricted, because traces contain URLs and SQL text.
  4. Make sure cron runs regularly. Problem detection, synthetic monitors and data purging run on cron.

Configuration

Go to Configuration → Development → Real-time Performance Monitor (/admin/config/development/real-time-performance-monitor). The page starts with quick links to every dashboard.

  • Thresholds: the slow SQL limit, duplicate query limit, PHP time and memory limits, and the page load, LCP, INP, CLS and TTFB limits
  • Cache layer: uncacheable-page alerts, and an optional Server-Timing header that shows Drupal, controller and SQL time in the browser DevTools
  • APM: the trace and RUM sample rates, retention periods, request naming rules, key requests, SLOs, problem detection sensitivity, synthetic monitors and the deployment API token
  • Notifications: watchdog, email recipients and a Slack webhook, each with its own frequency cap

Example request naming rules

/admin/*|Admin
/jsonapi/*|JSON:API
/{lang}/case-studies/*|Case study page
/user/login|Login page

Example SLOs

Homepage under 1 s|/|1000|95
Availability|*|avail|99.9

Drush commands

Command Purpose drush rpm:deployment 2.14 --description="Sprint 42" Record a deployment marker, typically right after drush deploy. Alias: rpm-deploy. drush rpm:detect-problems Run problem detection now drush rpm:synthetic Run all synthetic monitors now

Deployment markers from CI/CD

curl -X POST https://example.com/api/real-time-performance-monitor/deployment \
  -H "X-RPM-Token: $RPM_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"release":"2.14","description":"Sprint 42"}'

The API is disabled until a token is set on the settings page.

Performance and privacy considerations

  • Overhead: the module enables Drupal's database query log, which records a backtrace for every query. Traced requests also write a few rows to the database after the response has been sent. On busy production sites, start with a low trace sample rate and increase it as needed. Monitoring can be switched off completely with one checkbox.
  • What is stored: URL paths, route names, SQL statements with placeholders (no argument values), the host and path of outgoing HTTP calls (query strings are dropped, because they often carry API keys), log messages, and JavaScript error messages. The module's tables store no user IDs, IP addresses, cookies or form data; only an anonymous vs logged-in flag is kept per trace. Core's flood table briefly holds visitor IPs for rate limiting.
  • Server-Timing header: the optional detailed Server-Timing header exposes internal timings to anyone. Enable it on non-production environments, or behind a CDN that strips it. The trace ID entry is always added while tracing is on.
  • Public endpoints: the RUM and telemetry endpoints are public by design, because browsers must be able to post to them. They are rate-limited, size-limited and sanitized.

Limitations

  • Only requests handled by Drupal are traced. Drush, cron and queue workers are not traced, and a CDN, load balancer or Varnish in front of Drupal is not visible.
  • Redis and Memcache calls are not timed individually. Their time is counted as PHP code, and "miss" in cache-source labels is inferred from the cache configuration.
  • INP, LCP and long tasks are only reported by Chromium-based browsers.
  • Synthetic monitors are HTTP checks. They do not execute JavaScript or follow scripted click paths.
  • Values on the dashboards are based on sampled traces.

Similar and complementary tools

  • Webprofiler is excellent for inspecting a single page in depth while developing. Real-time Performance Monitor watches all traffic continuously, keeps history and alerts you.
  • Commercial APM tools such as Dynatrace, New Relic and Blackfire offer deeper, infrastructure-wide tracing with an installed agent. This module covers the Drupal-specific parts without an agent or external account, and it works alongside those tools.

Ask your assistant about Real-time Performance Monitor

Check compatibility with your Drupal and PHP version, maintenance and security coverage, from current release data. How it works

Depends on

Dependencies of the latest stable release

No dependencies recorded for this project.

Required by

Tracked projects that depend on this one

No tracked projects depend on this one yet.

Activity

Tracked releases
8
Tracked since
Jun 2026
Latest release
3 weeks ago
Releases (12 mo)
8 ▲ from 0
Maintenance
Active

Release Timeline

Releases

Version Type Core PHP Release date
1.0.8 Stable Sep 27, 2026
1.0.7 Stable Sep 6, 2026
1.0.6 Stable 9–11 Jun 10, 2026
1.0.4 Stable 9–11 Jun 7, 2026
1.0.3 Stable 10–11 Jun 7, 2026
1.0.2 Stable 10–11 Jun 5, 2026
1.0.0 Stable 10–11 Jun 5, 2026
1.0.x-dev Dev 10–11 Jun 4, 2026