Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Query Logger Laravel Package

overtrue/laravel-query-logger

Laravel Query Logger records every SQL query your app runs, including bindings and execution time, and writes readable logs for debugging. It highlights slow and duplicate queries, helping you spot N+1 and performance issues during local development with almost no setup.

View on GitHub
Deep Wiki
Context7

Getting Started

overtrue/laravel-query-logger is a zero-code-change query recorder: it hooks Laravel's QueryExecuted event and writes each SQL statement, its bindings, and its duration to a log channel you choose. There is no facade to call and no query builder API to learn — the value is entirely in what lands in storage/logs.

Install (v6 only on Laravel 13):

composer require --dev overtrue/laravel-query-logger:^6.0
php artisan vendor:publish --tag=query-logger   # inspect the published config name in the package README

Version gate first. v6.0.0 requires Laravel ^13.0 and PHP ^8.3. If you are still on Laravel 12, pin overtrue/laravel-query-logger:^5.1 — do not attempt to force v6 with --ignore-platform-reqs, since the service provider's middleware/event wiring targets the 13.x lifecycle.

Where to look first:

  1. The published config/query-logger.php — it is the whole control surface: enable/disable, log channel, log level, duration threshold, SQL exclusion patterns, and the trigger sources (HTTP request vs. console/queue).
  2. Your config/logging.php — the package writes into a standard Laravel channel, so create a dedicated channel (e.g. query-logger → daily with 3-day retention) rather than dumping into your app log.
  3. Default to APP_ENV=local only. The release notes confirm logging behavior is unchanged in v6, meaning it is still chatty by default when enabled.

First use case: you suspect an endpoint is doing N+1 queries. Enable the logger locally, hit the endpoint, and read the log file top-to-bottom — you get the full ordered query stream with bound values and per-query milliseconds, which is usually enough to spot the repeated select * from users where id = ? loop without reaching for Telescope or a profiler.

Implementation Patterns

Local-only dev feedback loop. Keep the package in require-dev and gate it in AppServiceProvider or via env:

// .env.local
QUERY_LOGGER_ENABLED=true
QUERY_LOGGER_LOG_CHANNEL=query-logger
QUERY_LOGGER_DURATION_THRESHOLD=0

When APP_ENV=production or in CI, set QUERY_LOGGER_ENABLED=false. Because there is no runtime API, disabling is purely config — which also means a stale cached config can silently keep it on (see Gotchas).

Duration threshold as a slow-query alert, not a logger. Set duration_threshold to something like 100 (ms) and the logger stops being a firehose and becomes a "queries that hurt" feed. This is the most useful production-adjacent pattern: keep it disabled in prod, but enable it briefly behind a feature flag on a single canary node when a latency regression is suspected, with a threshold high enough to avoid log volume issues.

SQL exclusions to kill the noise. Framework and package internals — session lookups, migrations table reads, cache/tag queries, Sanctum token lookups — dominate the log if unfiltered. Add patterns for those tables to the exclusion list so the remaining lines are your application's queries. Treat the exclusion list as an evolving file you tune per project, not a one-time config.

Pair it with a test assertion, not just eyeballs. Since v6 ships 23 behavior tests over real SQLite — covering bindings, thresholds, exclusions, triggers, and channels — the package is now a reasonable thing to integrate more deeply. A practical pattern: in a feature test for a known-hot endpoint, enable the logger against an in-memory SQLite connection and assert the recorded query count stays under a budget. This gives you N+1 regression protection in CI without a full profiler dependency.

// pseudo-shape: enable logging, call the endpoint, read the log channel, assert count
$this->get('/dashboard')->assertOk();
// then assert against the captured query log

Separate channels per environment role. Because the log channel is configurable, use daily for local browsing and a stack/single channel in staging where you're diffing before/after a refactor. Keeping the query channel distinct from laravel.log is what makes grep/tail -f workable.

Console and queue triggers. The v6 test suite explicitly covers "trigger sources," so console commands and queued jobs are instrumented too. This matters day-to-day: a slow queued job or an Artisan backfill will show up in the same log format as an HTTP request. When debugging jobs, make sure you know which trigger produced a line before assuming it came from a web request.

Gotchas and Tips

Breaking-change checklist for the upgrade. v6 is a hard floor bump: Laravel ^13.0, PHP ^8.3. Update composer.json platform constraints, your CI matrix (the package's own CI now runs 8.3/8.4/8.5), and any Docker base image before bumping the tag. Laravel 12 apps stay on ^5.1 — pin explicitly in composer.json so a composer update doesn't try to cross the gap.

The SQL interpolation fix is not in this release. Release notes call out that the separate fix in #71 is excluded from v6.0.0. If your workflow depends on reading fully interpolated SQL (bindings inlined into the statement string) rather than ? placeholders plus a bindings array, verify the output format on your own queries before relying on it. Where interpolation is imperfect, cross-reference the bindings that are logged alongside each statement — string bindings, in particular, may not render the way you expect.

Config cache will bite you. php artisan config:cache freezes enabled and log_channel. A deploy that cached config while the logger was on will keep logging after you flip the env var. Always php artisan config:clear after changing query-logger settings, and never rely on env changes alone in a cached-config environment.

Log volume is the real risk, not performance. The instrumentation cost is small; the disk cost is not. An unfiltered request on a data-heavy page can produce hundreds of lines. Set the threshold, curate the exclusion list, use a daily channel with short retention, and never enable it globally in production without a threshold.

Bindings can leak sensitive data. Password hashes, tokens, and PII appear as raw binding values — the package does not scrub them. This is the strongest argument for require-dev + local-only. If you must run it in a shared staging environment, add exclusions for auth/session/token tables and review the log before sharing.

Don't confuse it with a profiler. It gives you what ran and how long, not the call stack or the controller that issued it. For "which line of code caused this query," reach for Telescope, Debugbar, or Clockwork; use this package for the fast, greppable, dependency-light view. They coexist fine — the query logger adds no UI overhead.

Known CI notice, not an app issue. The lowest-secure dependency graph can pull Symfony Translation 6.4.0 (via Carbon) which emits an implicit-nullable deprecation on PHP 8.4 during Composer autoload. It's upstream, deliberately unsuppressed, and only surfaces in the lowest-deps job. Ignore it in your own pipeline unless you're also testing the lowest-secure graph, in which case expect one noisy line before PHPUnit installs its handler.

Extension points are thin by design. There's no documented driver/contract to swap the writer. If you need structured JSON query logs or shipping to an external sink, point log_channel at a channel whose formatter does that work (monolog formatter config in logging.php) rather than patching the package. That keeps you upgrade-safe across major versions.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin