Skip to content

ohtuser/query-spy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

5 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ” QuerySpy

Real-time Laravel query performance monitoring. Drop it in, browse your app, and instantly see N+1 queries, slow SQL, duplicates, memory spikes, and more β€” all in a beautiful developer dashboard.

Packagist PHP Laravel License: MIT


✨ Features

Feature Description
πŸ” N+1 Detection Finds repeated SQL patterns caused by missing eager-loading
🐒 Slow Queries Flags individual queries over your ms threshold
πŸ“„ Duplicate SQL Catches identical queries run multiple times per request
🧠 Memory Tracking Peak memory, growth per request, configurable alert threshold
⭐ SELECT * Detection Warns when all columns are fetched unnecessarily
πŸ” Index Hints Detects leading-wildcard LIKE '%...' that force full table scans
πŸ“Š Severity Score Every request scored 0–100 and labelled OK / Notice / Warning / Critical
πŸ–₯ Dashboard Dark, dev-friendly UI at /queryspy
πŸ“ˆ Timeline Chart Dual-axis Chart.js bar+line showing request time and query count
πŸ“‹ Pagination 25 entries per page with smart controls
♻️ Auto-refresh 10-second polling toggle on the dashboard
πŸ“‹ Copy SQL One-click copy button on every SQL block
πŸ“€ Export Download as JSON or CSV directly from the dashboard
🌐 Response Headers X-QuerySpy-* headers visible in your browser's Network tab
πŸ” Password Protection Optional dashboard password via .env
🌍 Environment Guard Skips production, CLI commands, and ignored URL patterns
πŸ–¨ Artisan Commands summary, watch, clear, export

πŸ“¦ Installation

composer require tuser/query-spy

Laravel auto-discovers the service provider β€” no manual registration needed.

Publish the config:

php artisan vendor:publish --tag=queryspy-config

βš™οΈ Configuration

Add any of these to your .env (all are optional):

QS_ENABLED=true
QS_SLOW_QUERY_MS=100          # Flag queries slower than this (ms)
QS_MAX_QUERIES=50             # Alert when queries/request exceed this
QS_N_PLUS_ONE=5               # Same SQL pattern N times = N+1 warning
QS_SLOW_REQUEST_SECONDS=2     # Flag requests slower than this
QS_MEMORY_THRESHOLD_MB=64     # Alert when peak memory exceeds this (MB)
QS_INJECT_HEADERS=true        # Add X-QuerySpy-* headers to responses
QS_LOG_CHANNEL=stack          # Laravel log channel for alerts
QS_DASHBOARD_URL=/queryspy    # Dashboard URL
QS_PASSWORD=                  # Optional dashboard password
QS_MAX_LOG_ENTRIES=200        # Max entries kept in storage

Full reference: config/queryspy.php


πŸ–₯ Dashboard

Visit /queryspy in your browser after installing.

What you get:

  • 7 stat cards β€” Total, Critical, Warning, Notice, Clean, Avg Duration, Total N+1
  • Sidebar β€” avg queries, avg memory, avg severity score with progress bar
  • Timeline chart β€” request duration (bars) + query count (line), coloured by severity
  • Filters β€” by severity level or issue type (N+1, slow, dupes, memory)
  • Search β€” by URL, route name, or any SQL text
  • Pagination β€” 25 per page
  • Auto-refresh β€” 10-second toggle
  • Export CSV / JSON β€” one-click download
  • Per-request drill-down with tabs:
    • Summary β€” all metrics, memory, index hints, SELECT* warnings
    • All Queries β€” time badge, full SQL with Copy button, source file:line
    • N+1 β€” pattern, count, total time, eager-load suggestion, source
    • Slow β€” full SQL, caller, source
    • Duplicates β€” count, source

🌐 Response Headers

When QS_INJECT_HEADERS=true, every response includes:

X-QuerySpy-Queries:    14
X-QuerySpy-Time-Ms:    87.4
X-QuerySpy-Memory-MB:  12.5
X-QuerySpy-Severity:   warning
X-QuerySpy-Score:      45
X-QuerySpy-N1:         2
X-QuerySpy-Slow:       1
X-QuerySpy-Duplicates: 0

Visible in your browser's Network tab β†’ select request β†’ Headers.


πŸ–¨ Artisan Commands

# Pretty table of recent entries
php artisan queryspy:summary
php artisan queryspy:summary --limit=50

# Live tail β€” prints new entries as they arrive
php artisan queryspy:watch
php artisan queryspy:watch --interval=5

# Wipe all stored logs
php artisan queryspy:clear

# Export to file
php artisan queryspy:export --format=csv
php artisan queryspy:export --format=json
php artisan queryspy:export --format=csv --output=/tmp/report.csv

πŸ“‘ JSON API

All endpoints accept ?password= when QS_PASSWORD is set.

GET  /queryspy/api               β†’ paginated JSON log
GET  /queryspy/api?severity=critical
GET  /queryspy/api?page=2&per_page=20
GET  /queryspy/export/csv        β†’ CSV download
POST /queryspy/clear             β†’ clear all logs

API response shape:

{
  "data":  [ ... ],
  "stats": { "total": 42, "critical": 3, "warning": 8, ... },
  "meta":  { "total": 42, "page": 1, "per_page": 50, "last_page": 1 }
}

🌍 Environment Guard

QuerySpy only runs in:

// config/queryspy.php
'environments' => ['local', 'development', 'staging'],

It never runs in production by default, in CLI/Artisan commands, or for URLs matching ignore_urls patterns (/queryspy*, /_ignition*, /telescope*, /horizon*).


πŸ” Password Protection

QS_PASSWORD=my-secret

The dashboard shows a password form. Pass ?password=my-secret to API endpoints.


πŸ—‚ Issue Types Explained

πŸ” N+1 Queries

The same SQL pattern (with bindings normalised to ?) runs 5+ times per request. Classic sign of missing with('relation') in Eloquent.

🐒 Slow Queries

Any individual query taking longer than QS_SLOW_QUERY_MS (default 100ms). Includes full SQL with real binding values and the source file:line.

πŸ“„ Duplicate SQL

Identical SQL (including bindings) run more than once β€” usually a missing cache or a logic loop.

🧠 Memory

Peak PHP memory exceeds QS_MEMORY_THRESHOLD_MB. Also tracks memory growth across the request lifecycle.

⭐ SELECT *

SELECT * on wide tables fetches unnecessary columns, wasting memory and network bandwidth.

πŸ” Index Hints

LIKE '%value' (leading wildcard) can't use a B-tree index and results in a full table scan. Consider a full-text index or a dedicated search engine.


πŸ›  Publishing

# Config
php artisan vendor:publish --tag=queryspy-config

# Blade views (to customise the dashboard)
php artisan vendor:publish --tag=queryspy-views

πŸ“ Changelog

See CHANGELOG.md.


πŸ“„ License

MIT Β© QuerySpy

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors