VOOZH about

URL: https://deepwiki.com/hypervel/telescope/2.3.3-query-watcher

⇱ Query Watcher | hypervel/telescope | DeepWiki


Loading...
Last indexed: 7 February 2026 (146f77)
Menu

Query Watcher

Purpose and Scope

The Query Watcher monitors all database queries executed through Hyperf's database layer, capturing SQL statements, execution time, connection details, and caller information. It provides critical performance insights by detecting slow queries and grouping related queries for analysis.

This document covers the QueryWatcher class implementation, SQL binding replacement logic, slow query detection, and integration with the event system. For general watcher patterns and registration, see Watcher Overview and Base Pattern. For storage of query entries, see Repository Pattern.

Sources: src/Watchers/QueryWatcher.php1-133


System Overview

The Query Watcher operates by listening to Hyperf's QueryExecuted events, which are dispatched after every database query completes. It transforms raw query data into structured entries that include human-readable SQL (with bindings replaced), performance metrics, and caller context.


Sources: src/Watchers/QueryWatcher.php16-52


Watcher Registration

The Query Watcher registers itself by listening to the QueryExecuted event from Hyperf's event dispatcher. This event is automatically dispatched by Hyperf's database layer after every query execution.


The registration method retrieves the event dispatcher from the container and establishes the listener:

ComponentRole
EventDispatcherInterfaceHyperf's PSR-14 event system
QueryExecutedEvent class dispatched after query execution
recordQuery()Callback method invoked for each query

Sources: src/Watchers/QueryWatcher.php23-27


Query Recording Flow

When a database query executes, the Query Watcher captures comprehensive details and transforms them into an IncomingEntry for storage.


The recorded entry contains the following data structure:

FieldTypeDescription
connectionstringDatabase connection name (e.g., "default")
bindingsarrayAlways empty array (bindings are embedded in SQL)
sqlstringSQL query with placeholders replaced by actual values
timestringQuery execution time in milliseconds, formatted to 2 decimals
slowbooleanTrue if execution time exceeds configured threshold
filestringFile path where query was called
lineintegerLine number where query was called
hashstringMD5 hash of SQL for grouping similar queries

Sources: src/Watchers/QueryWatcher.php32-52


SQL Binding Replacement

The Query Watcher replaces SQL placeholders (? for positional, :name for named) with their actual bound values, creating human-readable SQL statements. This transformation is essential for debugging as it shows exactly what was executed.

Replacement Algorithm


Binding Type Handling

The replacement logic handles three binding types:

  1. Null values: Converted to the literal string 'null'
  2. Numeric values (integers and floats): Inserted directly without quotes
  3. String values: Quoted using PDO's quote() method or a fallback escaping mechanism

Sources: src/Watchers/QueryWatcher.php81-105

String Quoting Strategy

For string bindings, the watcher attempts to use PDO's native quoting mechanism, falling back to manual escaping if unavailable:


The fallback escaping handles these special characters:

CharacterEscape SequencePurpose
chr(26)\ZEOF character
chr(8)\bBackspace
"\"Double quote
'\'Single quote
\\\Backslash

Note: Error code 'IM001' indicates "Driver does not support this function" and is expected when PDO's quote method is unavailable.

Sources: src/Watchers/QueryWatcher.php110-132

Binding Formatting

Before replacement, bindings are prepared using the database connection's prepareBindings() method, which normalizes binding values according to the connection's requirements:

Sources: src/Watchers/QueryWatcher.php73-76


Slow Query Detection

The Query Watcher identifies slow queries by comparing execution time against a configurable threshold. Slow queries are tagged for easy filtering in the Telescope UI.

Detection Logic



























ConfigurationLocationDefault
Slow thresholdconfig/telescope.phpwatchers.query.slowNot set (no slow detection)
Typefloat or integerMilliseconds
Example'slow' => 100Queries ≥100ms are tagged as slow

Slow Query Entry Data

When a query is identified as slow:

  1. The slow field in the entry is set to true src/Watchers/QueryWatcher.php46
  2. The entry receives a 'slow' tag src/Watchers/QueryWatcher.php59
  3. The tag enables filtering slow queries in the Telescope UI

Sources: src/Watchers/QueryWatcher.php46 src/Watchers/QueryWatcher.php57-60


Stack Trace Integration

The Query Watcher uses the FetchesStackTrace trait to capture the file and line number where each query originates. This provides crucial context for debugging query sources.

Stack Trace Capture


The trait filters the stack trace to exclude Telescope's own frames and identify the actual application code that triggered the query. If no caller can be determined (e.g., query executed from internal framework code), the entry is not recorded.

Stack Trace FieldPurpose
fileFull path to source file containing query call
lineLine number in source file
FilteringExcludes Telescope and framework internals

Sources: src/Watchers/QueryWatcher.php18 src/Watchers/QueryWatcher.php40-51


Query Family Hashing

The Query Watcher generates a "family hash" for each query by computing the MD5 hash of the raw SQL statement (before binding replacement). This groups structurally identical queries together, even if they have different parameter values.

Hashing Purpose


Benefits

BenefitDescription
Query groupingGroups queries that differ only in parameter values
Performance analysisIdentifies which query patterns execute most frequently
Optimization targetsHighlights query families consuming most database time
N+1 detectionReveals repeated executions of the same query structure

The hash is calculated from event->sql, which contains the raw SQL with placeholders intact, not the replaced version.

Sources: src/Watchers/QueryWatcher.php65-68


Configuration Options

The Query Watcher supports configuration via the watchers.query section in config/telescope.php:

Available Options


Configuration Example


Option Details

OptionTypeDefaultPurpose
enabledbooleantrueEnable/disable query monitoring
slowfloat/intNot setMillisecond threshold for slow query detection

Note: The ignore_tables option is referenced in the configuration but not explicitly implemented in the current watcher code. The watcher records all queries regardless of table.

Sources: src/Watchers/QueryWatcher.php46 src/Watchers/QueryWatcher.php59


Integration with Telescope Core

The Query Watcher integrates with Telescope's core recording system through the Telescope::recordQuery() static method:


The recorded entry is:

  1. Enriched with request-level context (batch ID, authenticated user)
  2. Filtered through configured entry filters
  3. Queued for batch storage at request completion

For details on the recording and storage pipeline, see Telescope Core System.

Sources: src/Watchers/QueryWatcher.php41-50