Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Debug Laravel in Production Safely with Logs and Telescope

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.

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.

Production Debug LadderStep 1: Read existing logsstorage/logs + web server + PHP-FPMStep 2: Raise LOG_LEVEL brieflyAdd correlation ID + redact secretsStep 3: Enable Telescope behind authFilter entries + 24h retention maxStep 4: Fix root causeRevert LOG_LEVEL and disable Telescope
Safe Laravel production debugging ladder — logs first, Telescope only when needed, then immediate cleanup

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.

Laravel Production Log PipelineHTTP Requestweb + APIMiddlewarerequest_id contextControllerLog::warning()Monolog Stacksingle + daily channelslaravel.log14-day rotationstderr / syslogoptional ship to LokiNever log secrets — redact at source
Laravel production log pipeline — correlation IDs flow from middleware through Monolog to rotated log files

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.

ToolBest forProduction riskOverhead
Application logsErrors, warnings, audit eventsLow with redactionMinimal
Spatie Activity LogModel change historyLowLow–medium
Laravel TelescopeRequest replay, queries, jobsHigh if unguardedMedium–high
Laravel DebugbarLocal development onlyCritical — never prodHigh
External APM (Sentry, etc.)Continuous monitoringLow with samplingConfigurable

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.

  1. 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.
  2. Search existing logs. Grep by request_id, order ID, or exception class before changing any config.
  3. Reproduce in staging. Mirror production data shape without copying production secrets. Use anonymised fixtures.
  4. Enable temporary debug logging. Set LOG_LEVEL=debug, deploy, reproduce once, capture output.
  5. Enable Telescope if still stuck. Confirm auth gate, filters, pruning, and Redis queue driver.
  6. Fix and verify. Add a regression test where feasible. See Laravel feature testing patterns.
  7. Revert everything. Restore LOG_LEVEL=warning, set TELESCOPE_ENABLED=false, run telescope:clear, and config:cache.
Logs vs Telescope in ProductionLogsAlways on at warning+Flat files / syslogLow overheadNeeds grep / tailSafe defaultTelescopeTemporary + gatedMySQL / Postgres rowsRich UI + replayDB growth riskIncident onlyUse both — logs continuously, Telescope briefly
Logs versus Laravel Telescope for production debugging — complementary tools with different risk profiles

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:work logs. 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_children may 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:clear or prune ran successfully
  • Log rotation is catching up
  • config:cache reflects reverted LOG_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.

Production Incident Runbook1. Confirm symptom + collect IDs2. Grep existing logs first3. Reproduce in staging4. LOG_LEVEL=debug briefly5. Enable gated Telescope6. Fix + add regression test7. Revert LOG_LEVELDisable Telescope + config:cache + prune entriesNever skip step 7 — treat cleanup as part of the fix
Seven-step Laravel production incident runbook — always revert LOG_LEVEL and disable Telescope after debugging

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=warning as the production default and raise to debug only 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_LEVEL and 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

Yes, briefly, when gated behind authentication, filtered to exceptions and failed jobs, Redis-queued, pruned daily, and disabled immediately after the incident. Unguarded Telescope is a security and performance risk.

Set LOG_LEVEL=warning as the default. Raise to debug only during an active incident, reproduce once, then revert within hours.

No. Debugbar is for local development only. Leaving it enabled after deploy exposes env keys and query details — treat that as a production incident.

Application logs are cheap, passive, and safe at scale. Telescope watches every request, query, mail, and queue job, which 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, and enable Telescope only when you need deep request context and can accept the overhead for a short window. Most production fires on legal-tech portals and booking systems resolve at step one or two.

Laravel 12 and 13 use config/logging.php and .env values. Set LOG_CHANNEL=stack, LOG_STACK=single,daily, LOG_LEVEL=warning, and LOG_DAILY_DAYS=14 for normal production. The daily driver rotates files automatically, which matters on shared EC2 boxes where a forgotten debug level can fill disk during a traffic spike. During an incident only, temporarily set LOG_LEVEL=debug, capture output, then revert within hours. Pair application logs with PHP-FPM slow logs and web server access logs when latency is the symptom rather than a 500 response. Never log raw passwords, API keys, card data, or full JWTs — redact sensitive fields at the source before Monolog writes to disk.

A correlation ID is a unique request identifier, often generated in middleware such as AssignRequestId, that ties a web request, queue job, and payment webhook to one searchable key in storage/logs/laravel.log. When support forwards three similar tickets, you need one ID instead of guessing which log lines belong together. Register the middleware in bootstrap/app.php for Laravel 11+, set Log::withContext with the request_id, return it in the X-Request-Id response header, and push the same ID into queued jobs via SerializesModels job middleware or explicit constructor arguments so Redis queue workers log with the same key the web tier used.

Enable Telescope when logs tell you 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. Telescope is a debug dashboard, not a permanent observability platform; it stores entries in your application database by default. That is acceptable only when you control access, filter noise, and plan cleanup. Set TELESCOPE_ENABLED=true only during the incident window, confirm auth gate, filters, pruning, and Redis queue driver, fix the issue, then set TELESCOPE_ENABLED=false and run telescope:clear the same day.

Install Telescope with composer require laravel/telescope, run php artisan telescope:install and migrate, then restrict the viewTelescope gate in app/Providers/TelescopeServiceProvider.php to named admin accounts or IP allowlists — never rely on security through obscurity alone. Block /telescope at the web server layer for all IPs except yours if needed, and prefer VPN or SSH tunnel over public exposure. Set APP_DEBUG=false always in production because 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 that your pre-deploy checklist should catch.

In TelescopeServiceProvider register method, use Telescope::filter so production only records reportable exceptions, failed jobs, scheduled tasks, and entries with monitored tags — not every HTTP request. Tag critical paths explicitly when you need guaranteed capture, for example payment-callback on webhook routes. Set aggressive pruning so the telescope_entries table cannot grow without bound: schedule telescope:prune --hours=24 daily in routes/console.php or your scheduler. Queue Telescope writes via TELESCOPE_QUEUE_CONNECTION=redis to keep user-facing latency lower than synchronous inserts on every query. After symlink swap on Deployer 7 releases, run php artisan config:cache so TELESCOPE_ENABLED and filter settings take effect immediately.

Follow a written runbook every time. Confirm the symptom with URL, user ID, timestamp, and any payment reference. Search existing logs by request_id, order ID, or exception class before changing config. Reproduce in staging with anonymised fixtures, not production secrets. Enable temporary debug logging, deploy, reproduce once, capture output. If still stuck, enable Telescope with auth gate, filters, pruning, and Redis queue driver. Fix and verify, add a regression test where feasible. Revert everything the same day: restore LOG_LEVEL=warning, set TELESCOPE_ENABLED=false, run telescope:clear, and config:cache. Ad hoc debugging is how Telescope stays enabled for weeks and disks fill with debug logs.

Application logs capture errors, warnings, and audit events with minimal overhead when you keep LOG_LEVEL=warning and redact secrets. Telescope provides request replay, query traces, job timelines, and mail inspection by writing entries to your database — medium to high overhead if unguarded. Logs are always on; Telescope is a temporary escalation tool. Spatie Activity Log sits between them for model change history without recording every HTTP request. External APM tools like Sentry handle continuous exception capture with sampling. Use logs first, Telescope only when you need deep request context, then disable Telescope immediately after the incident.

SSH in and tail with filters instead of opening massive files in an editor on the server. Use tail -f on storage/logs/laravel-$(date +%Y-%m-%d).log for live output, grep by request_id across storage/logs/laravel-*.log when you have a correlation ID, and grep for SQLSTATE to find database exceptions. If you centralise logs, ship JSON lines to syslog or a collector by changing only the Monolog handler — application code stays the same. Search existing logs before changing LOG_LEVEL or enabling Telescope; payment callback mismatches, stale cache keys, and queue worker crashes often leave fingerprints in laravel.log within minutes without touching any debug UI.

Log transaction reference, status code, and a SHA-256 hash of the webhook body — never the full signing secret, raw tokens, or card data. Use Arr::except on callback payloads to strip token, password, and card fields before writing to disk. Tag payment-callback routes in Telescope when you need guaranteed capture during an incident. Local gateways like eSewa and Khalti retry with opaque payloads, so a correlation ID linking the webhook to the original checkout request saves hours of grep work. Cross-reference gateway docs and implement idempotent callback handling so retries do not create duplicate charges while you debug.

Treat every incident window like temporary privilege escalation. Lock down Telescope routes, keep APP_DEBUG=false, verify hidden fields in config/telescope.php cover password, token, api_key, authorization, card, and cvv. For legal-tech portals with document uploads, log file IDs and checksums instead of paths containing client names — do not record full national ID scans or passport images in debug dumps. After debugging, verify telescope:clear or prune ran, log rotation is catching up, config:cache reflects reverted LOG_LEVEL, and PHP-FPM was reloaded so opcache serves current code. On shared Deployer 7 infrastructure, confirm Telescope is disabled across all vhosts — one forgotten flag can leak internal API calls.

Many Nepal business sites run on 2–4 GB RAM VPS plans with MySQL 8.4 or MariaDB 12.3 and a single queue worker. Telescope on the same database as checkout traffic can contend for IOPS during sale periods, so prefer file logs plus targeted Telescope sessions at quiet hours with aggressive pruning. Consider a separate PostgreSQL 18 or MySQL schema only for Telescope if volume demands it. On booking systems and legal portals, 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 when your team lacks dedicated DevOps.

Share this article

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.

Quick Contact Options
Choose how you want to connect me: