
September 09, 2026
13 min read
By Kokil Thapa | Last reviewed: September 2026
Production bugs rarely wait for your local machine. You need a way to debug Laravel in production safely with logs and Telescope without dumping stack traces to users or leaving a wide-open admin panel on the internet. Structured logging catches most incidents. Laravel Telescope fills the gaps when you need request replay, query traces, and job timelines. The trick is turning both on briefly, under guardrails, then shutting them down. This guide walks through that workflow on real Laravel 12 and 13 stacks running PHP 8.3+ on Ubuntu with Apache or Nginx and PHP-FPM.
LOG_LEVEL=warning by default, enable Telescope only behind auth with strict filters and short retention, capture correlation IDs in logs, reproduce the issue, then revert LOG_LEVEL and disable Telescope immediately after the incident.Why should you debug Laravel in production with logs before touching Telescope?
Logs are cheap, passive, and safe at scale. Telescope watches every request, query, mail, and queue job. That visibility costs CPU, disk, and database rows. On a busy booking portal or eCommerce checkout, leaving Telescope fully open can add measurable latency.
I treat production debugging as a ladder. Start with application logs and server error logs. Escalate to temporary debug logging with a correlation ID. Enable Telescope only when you need deep request context and can accept the overhead for a short window.
On legal-tech portals and booking systems I maintain, most production fires resolve at step one or two. Payment callback mismatches, stale cache keys, and queue worker crashes all leave fingerprints in storage/logs/laravel.log before you touch any debug UI.
What belongs in baseline production logs
Your default channel should capture warnings and errors only. Info-level chatter belongs in staging. Pair application logs with PHP-FPM slow logs and web server access logs when latency is the symptom rather than a 500 response.
How do you configure Laravel logging for safe production debugging?
Laravel 12 and 13 ship with a flexible logging stack driven by config/logging.php and .env values. The goal is signal without noise and zero secret leakage.
Set LOG_LEVEL and channels in .env
# .env — normal production baseline
LOG_CHANNEL=stack
LOG_STACK=single,daily
LOG_LEVEL=warning
LOG_DAILY_DAYS=14
# Temporary incident window only (revert within hours)
# LOG_LEVEL=debug The daily driver rotates files automatically. That matters on shared EC2 boxes where a forgotten debug level can fill disk during a traffic spike. I've seen a single verbose weekend take a 20 GB partition to 98% full.
Add structured context with a correlation ID
When support forwards three similar tickets, you need one ID tying web request, queue job, and payment webhook together. A middleware approach keeps controllers clean.
<?php
// app/Http/Middleware/AssignRequestId.php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Log;
class AssignRequestId
{
public function handle($request, Closure $next)
{
$requestId = $request->header('X-Request-Id') ?: (string) Str::uuid();
$request->attributes->set('request_id', $requestId);
Log::withContext(['request_id' => $requestId]);
$response = $next($request);
$response->headers->set('X-Request-Id', $requestId);
return $response;
}
} Register the middleware in bootstrap/app.php for Laravel 11+. Push the same request_id into queued jobs via SerializesModels job middleware or explicit constructor arguments. Your Redis queue workers then log with the same key the web tier used.
Redact secrets before they hit disk
Never log raw passwords, API keys, card data, or full JWTs. Laravel's log context passes through Monolog formatters. Wrap sensitive fields at the source.
Log::warning('Payment callback failed', [
'gateway' => 'khalti',
'order_id' => $order->id,
'payload' => Arr::except($request->all(), ['token', 'password', 'card']),
]); For deeper audit trails on business events, pair logs with Spatie Activity Log. It records who changed what without turning every HTTP request into a database write like Telescope does.
When is Laravel Telescope safe to enable in production?
Telescope is a debug dashboard, not a permanent observability platform. The official package stores entries in your application database by default. That is acceptable in production only when you control access, filter noise, and plan cleanup.
Use Telescope when logs tell you that something failed but not why. Duplicate charge attempts, mystery N+1 regressions, and silent mail failures are typical cases. Skip it for simple config typos visible in a stack trace.
Install and gate Telescope behind authentication
composer require laravel/telescope
php artisan telescope:install
php artisan migrate In app/Providers/TelescopeServiceProvider.php, restrict the gate to named admin accounts or IP allowlists. Never rely on security through obscurity alone.
protected function gate(): void
{
Gate::define('viewTelescope', function ($user) {
return in_array($user->email, [
'ops@example.com',
], true);
});
} Also set TELESCOPE_ENABLED=true only during the incident window. Better yet, drive it from an environment flag your deploy pipeline toggles. After symlink swap on Deployer 7 releases, run php artisan config:cache so the flag takes effect immediately.
Filter what Telescope records in production
use Laravel\Telescope\IncomingEntry;
use Laravel\Telescope\Telescope;
public function register(): void
{
Telescope::filter(function (IncomingEntry $entry) {
if ($this->app->environment('local')) {
return true;
}
return $entry->isReportableException()
|| $entry->isFailedJob()
|| $entry->isScheduledTask()
|| $entry->hasMonitoredTag();
});
} Tag critical paths explicitly when you need guaranteed capture:
Telescope::tag(function () {
return ['payment-callback'];
}); Set aggressive pruning so the telescope_entries table cannot grow without bound:
# .env
TELESCOPE_ENABLED=true
TELESCOPE_PATH=telescope
TELESCOPE_QUEUE_CONNECTION=redis Schedule pruning in routes/console.php or your scheduler:
Schedule::command('telescope:prune --hours=24')->daily(); Queueing Telescope writes via Redis 8.10 keeps user-facing latency lower than synchronous inserts on every query. Match that setup to your existing Redis queue configuration.
| Tool | Best for | Production risk | Overhead |
|---|---|---|---|
| Application logs | Errors, warnings, audit events | Low with redaction | Minimal |
| Spatie Activity Log | Model change history | Low | Low–medium |
| Laravel Telescope | Request replay, queries, jobs | High if unguarded | Medium–high |
| Laravel Debugbar | Local development only | Critical — never prod | High |
| External APM (Sentry, etc.) | Continuous monitoring | Low with sampling | Configurable |
Debugbar belongs in local development only. I have seen it left enabled after a rushed deploy. It exposes env keys and query details to anyone who loads a page. Treat that as a production incident, not a minor misconfiguration.
What is the step-by-step workflow to debug Laravel in production safely?
Follow a written runbook every time. Ad hoc debugging is how Telescope stays enabled for weeks and disks fill with debug logs.
- Confirm the symptom. Collect URL, user ID, timestamp in Nepal Time or UTC, and any payment reference. Check JSON formatter output if the client sent a malformed API body.
- Search existing logs. Grep by
request_id, order ID, or exception class before changing any config. - Reproduce in staging. Mirror production data shape without copying production secrets. Use anonymised fixtures.
- Enable temporary debug logging. Set
LOG_LEVEL=debug, deploy, reproduce once, capture output. - Enable Telescope if still stuck. Confirm auth gate, filters, pruning, and Redis queue driver.
- Fix and verify. Add a regression test where feasible. See Laravel feature testing patterns.
- Revert everything. Restore
LOG_LEVEL=warning, setTELESCOPE_ENABLED=false, runtelescope:clear, andconfig:cache.
Reading logs on the server without breaking production
SSH in, then tail with filters. Avoid opening massive files in an editor on the server.
tail -f storage/logs/laravel-$(date +%Y-%m-%d).log
grep "request_id\":\"abc-123" storage/logs/laravel-*.log
grep -i "SQLSTATE" storage/logs/laravel-*.log | tail -20 If you centralise logs, ship JSON lines to syslog or a collector. The application code stays the same. Only the Monolog handler changes. Refer to the Laravel 12 logging documentation for custom channel examples.
Common production failures and where to look
- 502 after deploy. Check PHP-FPM socket path, opcache stale code, and
storage/permissions. Reload PHP-FPM after symlink swap. - Queue jobs stuck. Inspect failed_jobs table and Horizon or
queue:worklogs. See scheduled task setup. - Slow checkout. Enable query logging briefly or use Telescope's query tab. Cross-check N+1 detection techniques.
- Payment webhook mismatch. Log raw payload hash, not secrets. Compare against gateway docs for eSewa, Khalti, or Stripe.
- Memory exhaustion. PHP-FPM
pm.max_childrenmay be too high for available RAM. Scale workers before blaming Laravel.
On a production Laravel application handling document uploads, I've traced failed jobs to incorrect storage:link paths after migration between servers. Logs showed the exception in under a minute. Telescope was never required.
How do you harden Laravel production debugging against security and performance risks?
Debugging tools become attack surfaces when left exposed. Treat every incident window like a temporary privilege escalation.
Lock down routes and environment flags
Block /telescope at the web server layer for all IPs except yours if needed. Use VPN or SSH tunnel when possible instead of public exposure. Set APP_DEBUG=false always in production. Debug mode leaks stack traces and environment details to end users.
Review .env on the server after every deploy. A copied staging file with APP_DEBUG=true is a recurring mistake on small teams. Your pre-deploy checklist should catch it.
Protect database and customer data inside Telescope
Telescope hides passwords by default on request bodies. Verify hidden fields in config/telescope.php:
'hidden' => [
'password', 'password_confirmation', 'token', 'api_key',
'authorization', 'card', 'cvv',
], Do not record full national ID scans or passport images in custom debug dumps. For legal-tech portals with document uploads, log file IDs and checksums instead of paths containing client names.
Watch disk, database, and opcache after debugging
After an incident, verify:
telescope:clearor prune ran successfully- Log rotation is catching up
config:cachereflects revertedLOG_LEVEL- PHP-FPM was reloaded so opcache serves current code
On shared infrastructure where several Laravel sites run Deployer 7 releases, I add a calendar reminder to confirm Telescope is disabled across all vhosts. One forgotten flag on a sister site is enough to leak internal API calls.
Integrate with external error tracking
Logs and Telescope solve active investigations. Continuous exception capture belongs in a dedicated service with sampling and release tracking. The Laravel Telescope documentation describes watchers you can disable individually to reduce noise when pairing with Sentry or similar tools.
For API-heavy platforms, also log 429 and 422 responses at info level in a separate channel. That keeps error logs clean while preserving audit evidence. See Laravel API best practices for response shape conventions.
How does this apply to real Laravel production stacks in Nepal?
Many Nepal business sites run on budget VPS plans with 2–4 GB RAM, MySQL 8.4 or MariaDB 12.3, and a single queue worker. That constraint shapes debugging choices.
Telescope on the same database as checkout traffic can contend for IOPS during sale periods. Prefer file logs plus targeted Telescope sessions at quiet hours. Schedule pruning aggressively. Consider a separate PostgreSQL 18 or MySQL schema only for Telescope if volume demands it.
Local payment gateways add webhook retries with opaque payloads. Log transaction reference, status code, and a SHA-256 hash of the body. Never the full signing secret. Cross-reference Laravel payment integration patterns for idempotent callback handling.
On booking systems like Adventure Third Pole Trek and legal portals such as Mijar Law Associates, uptime matters more than debug convenience. Document who may enable Telescope, for how long, and who reverts it. A shared runbook beats heroic midnight SSH.
If your team lacks dedicated DevOps, consider ongoing Laravel support that includes incident response playbooks. Prevention still beats debugging, but every production app eventually needs a safe way to inspect live behaviour.
Key Takeaways
- Keep
LOG_LEVEL=warningas the production default and raise todebugonly during active incidents. - Add correlation IDs in middleware so web requests, jobs, and webhooks share one searchable key.
- Enable Laravel Telescope behind auth with filters, Redis queuing, and 24-hour pruning — never leave it wide open.
- Redact passwords, tokens, and payment data in logs and Telescope hidden fields before anything hits disk.
- Follow a written runbook: investigate logs first, fix, then revert
LOG_LEVELand disable Telescope the same day. - Pair temporary debugging with regression tests and external exception tracking for continuous coverage.
People Also Ask
Is Laravel Telescope safe for production?
Telescope can run in production when authentication, entry filters, queued writes, and scheduled pruning are configured. Without those guardrails it exposes internal requests, queries, and mail content to anyone who reaches the dashboard. Treat it as a short-lived incident tool, not permanent monitoring.
What LOG_LEVEL should Laravel use in production?
Use warning or error for steady-state production. Switch to debug or info only while investigating a specific issue, then revert within hours. Long-running debug levels fill disks and may log sensitive request data you did not intend to retain.
How do I debug Laravel queue failures in production?
Check failed_jobs, worker logs, and Horizon if installed. Search application logs by job class and correlation ID. Enable Telescope's job watcher temporarily to inspect payload and exception traces. Fix the root cause, retry or flush failed jobs, and confirm workers restart after deploy.
Should APP_DEBUG ever be true in production?
No. APP_DEBUG=true in production exposes stack traces, environment variables, and database details to visitors. Keep it false always. Use logging, Telescope behind auth, or an external error tracker for investigation instead.
Ship reliable Laravel apps and debug safely when production breaks
You can debug Laravel in production safely with logs and Telescope if you treat debugging as a controlled, reversible procedure. Logs carry you through most incidents. Telescope earns its overhead only when you need full request context and can lock it down immediately afterward. Build that discipline into deploy checklists, train your team on the runbook, and revert every temporary flag the same day the bug ships.
Need help hardening a live Laravel app, setting up safe observability, or responding to a production incident? Contact us for Laravel development and support, or browse the portfolio for production systems already running this stack. For related reading, see database transaction debugging and speed optimization once the immediate fire is out.
Frequently Asked Questions
0 Comments
Leave a comment
Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

