WP Manifestindependent plugin directory
manifest / developer / query-origin-tracer

Query Origin Tracer releases

Trace slow and stuck WordPress database queries to their originating requests, visitors, plugins, themes, and PHP call stacks.

by Rocket.net · github.com/andrecmsilva/query-origin-tracer · website

0stars
31release downloads
0forks

Install

The author publishes release zips, so WP-CLI can install straight from GitHub:

wp plugin install https://github.com/andrecmsilva/query-origin-tracer/releases/download/v2.0.1/query-origin-tracer-2.0.1.zip

Readme

Query Origin Tracer

Find the WordPress request, visitor, plugin, theme, or PHP call stack behind a database query.

Query Origin Tracer is a production diagnostics plugin for investigating slow, repeated, and stuck WordPress database queries. It records structured JSONL evidence and includes WP-CLI commands for starting targeted captures, following results live, and cleaning up afterward.

[!WARNING] This is a temporary diagnostic tool, not an always-on profiler. Captured SQL, request data, and headers may contain sensitive information. Use it for focused investigations and disable it when the capture is complete.

Why use it?

A slow query log can tell you what ran. Query Origin Tracer helps answer the harder questions:

  • Which request caused it?
  • Which plugin, MU-plugin, theme, or application code initiated it?
  • What PHP stack led to the query?
  • Which visitor or upstream request was involved?
  • Is a query currently stuck inside a PHP worker?
  • Are recurring queries the same shape with different values?

What it captures

  • Raw SQL and a normalized query fingerprint
  • Execution time for completed queries
  • PHP call stack with file and line numbers
  • Detected plugin, MU-plugin, theme, or application origin
  • Request URI, method, host, referer, and user agent
  • REMOTE_ADDR, CF-Connecting-IP, True-Client-IP, X-Forwarded-For, and CF-Ray
  • REST, AJAX, cron, WP-CLI, admin, and XML-RPC context
  • Authenticated WordPress user ID when already available
  • PID, request ID, site/blog ID, current memory, and peak memory
  • Optional per-PID records for queries that have started but not returned

How v2.0 works

Query Origin Tracer installs as a normal plugin in wp-content/plugins/query-origin-tracer/. When activated, it creates a small managed bootstrap at:

wp-content/mu-plugins/query-origin-tracer-loader.php

The bootstrap loads the tracer early enough to observe queries initiated before ordinary plugins load, while the plugin itself remains manageable through the standard WordPress lifecycle.

  • Activation creates the early loader and activation marker.
  • Deactivation removes the loader and marker but preserves captured evidence.
  • Deletion removes the loader, marker, configuration, logs, in-flight records, stored options, and any legacy MU-only installation.
  • Capture is opt-in: activating the plugin alone does not begin tracing queries.

Requirements

  • WordPress 5.8 or newer
  • PHP 7.4 or newer
  • WP-CLI for capture management and the live reader

Installation

WordPress Admin

  1. Download the latest release ZIP.
  2. Open Plugins → Add New → Upload Plugin.
  3. Upload, install, and activate Query Origin Tracer.

WP-CLI

wp plugin install /path/to/query-origin-tracer.zip --activate

Manual

cp -a query-origin-tracer wp-content/plugins/
wp plugin activate query-origin-tracer

The default state directory for a typical /home/USER/public_html installation is outside the document root:

/home/USER/.query-origin-tracer

To use another location, define it in wp-config.php before WordPress loads:

define( 'QOT_STATE_DIR', '/secure/path/.query-origin-tracer' );

Quick start

Capture queries taking at least 250 ms:

wp query-origin enable --mode=slow --min-seconds=0.25

Capture starts on subsequent WordPress requests. Open the site from another terminal or browser, making sure the request reaches WordPress rather than being served entirely from a page cache or CDN.

Follow the latest records live:

wp query-origin list

list is intentionally blocking: it continues waiting for new matching queries until you press Ctrl+C. The default slow mode may remain empty on a healthy site because it only records individual database queries taking at least 250 ms.

For a first-run verification, temporarily capture every query, generate one uncached request, then print the results without following:

wp query-origin enable --mode=all --max-per-request=25
curl -sS "https://example.com/?qot-test=$(date +%s)" >/dev/null
wp query-origin list --last=25 --no-follow
wp query-origin disable

Run the curl request from another terminal if the first terminal is already following the log.

Check the current configuration:

wp query-origin status

When the investigation is complete:

wp query-origin disable

Disabling capture preserves the evidence. Remove it explicitly with:

wp query-origin clear

Capture recipes

Find actively stuck queries

In-flight mode maintains one current-query file per PHP PID. If a query never returns, its record remains available for inspection.

wp query-origin enable --mode=slow --min-seconds=0.25 --inflight=1
wp query-origin inflight

Or inspect recent records directly:

find ~/.query-origin-tracer/inflight -type f -name '*.json' -mmin -10 -print -exec jq . {} \;

Capture every completed query

Use this only for short, targeted windows:

wp query-origin enable --mode=all --max-per-request=100

Filter by SQL

Regular expressions must include delimiters:

wp query-origin enable \
  --mode=all \
  --sql-include='~wp_actionscheduler_|SQL_CALC_FOUND_ROWS|wp_postmeta~i' \
  --inflight=1

Filter by request

wp query-origin enable \
  --mode=all \
  --request-include='~wp-json|admin-ajax\.php|wp-cron\.php~i'

Filter by visitor IP

IP matching uses exact values:

wp query-origin enable --mode=all --ip='203.0.113.10,2001:db8::10'

Reading results

Live WP-CLI reader

wp query-origin list prints the latest 10 records and continues following new queries until Ctrl+C. Each result includes the host, request URI and query string, remote address, user agent, UTC start time, SQL, detected origin, duration, and current/peak PHP memory.

# Start with the latest 25 records and continue following.
wp query-origin list --last=25

# Follow only records written after the command starts.
wp query-origin list --last=0

# Print the latest 50 records and exit.
wp query-origin list --last=50 --no-follow

# Poll the log every 100 milliseconds.
wp query-origin list --poll=0.10

The reader handles ordinary appends, log truncation after clear, and log-file recreation.

Raw JSONL

tail -F ~/.query-origin-tracer/events.jsonl | jq .

Group recurring query shapes:

jq -r '.fingerprint' ~/.query-origin-tracer/events.jsonl \
  | sort | uniq -c | sort -nr | head -30

Group queries by detected component:

jq -r '[.origin.type, .origin.component] | @tsv' ~/.query-origin-tracer/events.jsonl \
  | sort | uniq -c | sort -nr | head -30

Show stack traces for queries over one second:

jq -r '
  select(.duration_seconds >= 1)
  | "\n=== \(.duration_ms) ms | \(.request_uri) ===\n"
    + (.stack[] | "\(.file):\(.line) \(.call)")
' ~/.query-origin-tracer/events.jsonl

Command reference

Command Purpose
wp query-origin enable Start or update a capture
wp query-origin status Show configuration, log location, and in-flight count
wp query-origin list Read and optionally follow completed-query records
wp query-origin inflight Display queries currently associated with PHP PIDs
wp query-origin disable Stop tracing while retaining evidence
wp query-origin clear Delete completed-query and in-flight records

Operational and privacy notes

  • SAVEQUERIES times every $wpdb query and collects caller information. Expect additional CPU and memory overhead.
  • In-flight mode writes and removes a small file for each eligible query. Enable it only while investigating active hangs.
  • SQL, URIs, headers, and user metadata can contain personal data, credentials, or tokens. Protect the state directory and sanitize evidence before sharing it.
  • State directories and files are created with restrictive permissions and should remain outside the document root.
  • CF-Connecting-IP is trustworthy only when the origin accepts traffic exclusively from Cloudflare or otherwise prevents clients from spoofing it.

Limitations

  • With the managed MU loader, tracing begins after MU-plugins load. If the server prevents the loader from being created, the tracer still runs as an ordinary plugin but begins later in bootstrap.
  • It cannot observe bootstrap queries that ran before the tracer loaded.
  • It cannot observe direct mysqli or PDO connections created outside the active WordPress $wpdb implementation.
  • It cannot observe queries avoided entirely by object caching.
  • A custom db.php drop-in must implement WordPress's SAVEQUERIES and log_query_custom_data behavior for completed-query timing. In-flight capture may still help when the standard query filter is implemented.

Upgrade from v1.x

Version 2.0 replaces the legacy MU-only package with a standard WordPress plugin. Activation and uninstall routines detect and clean up the earlier package automatically. Install and activate v2.0 through the normal plugin workflow; it will manage the early bootstrap from there.

Changelog

2.0.1

  • Clarified that capture begins on subsequent WordPress requests.
  • Added actionable first-run guidance when no completed query has matched.
  • Explained the live reader's blocking behavior and all-query verification workflow.

2.0.0

  • Converted the legacy MU-only package into a standard WordPress plugin.
  • Added an activation-managed early MU bootstrap.
  • Added complete deactivation, uninstall, and v1 migration cleanup.

Verify or remove the installation

wp plugin status query-origin-tracer
wp query-origin status
ls -l wp-content/mu-plugins/query-origin-tracer-loader.php

To remove the tracer and all plugin-created diagnostic data:

wp plugin deactivate query-origin-tracer
wp plugin delete query-origin-tracer

License

Query Origin Tracer is licensed under the GNU General Public License v2.0 or later.

Read the full README on GitHub →

Releases

TagPublishedAssetDownloads
v2.0.1 Jul 18, 2026 query-origin-tracer-2.0.1.zip 23
v2.0.0 Jul 18, 2026 query-origin-tracer-2.0.0.zip 8
v1.1.0 Jul 18, 2026