Laravel Telescope

Com depurar i monitoritzar la teva aplicació amb Laravel Telescope: peticions, consultes, jobs, excepcions, correus i més.

Què és Telescope?#

Laravel Telescope és una eina d'introspecció i depuració que registra absolutament tot el que passa dins de la teva aplicació Laravel. Cada petició HTTP, cada consulta SQL, cada job encuat, cada excepció llançada, cada correu enviat, cada notificació, cada event disparat, cada entrada de log, cada comanda Artisan executada: Telescope ho captura tot i ho mostra en un dashboard web elegant on pots inspeccionar cada detall.

Quan estàs desenvolupant una aplicació i alguna cosa no funciona com esperes, el procés habitual és afegir dd() o Log::info() al codi, refrescar la pàgina, mirar el resultat, treure el debug, afegir-ne un altre a un lloc diferent i repetir. Telescope elimina aquest cicle tediós. En lloc de contaminar el codi amb sentències de depuració, Telescope registra automàticament tota la informació que podries necessitar. Si una consulta SQL és lenta, ho veuràs a la secció de queries amb el temps exacte d'execució. Si un correu no s'envia, pots veure'l renderitzat a la secció de mail. Si un job falla, tens l'excepció completa amb el stack trace a la secció de jobs.

Per què és indispensable durant el desenvolupament#

El valor de Telescope no és només que registra informació: és que la presenta de manera que la fas servir constantment. La secció de peticions HTTP mostra cada request amb les capçaleres, el payload, la resposta, la sessió, les cookies, el middleware aplicat i el temps de resposta. La secció de consultes mostra cada query SQL amb els bindings, el temps d'execució i des de quin fitxer s'ha executat. Això és especialment valuós per detectar problemes de rendiment com l'N+1 query problem: pots veure que una pàgina executa 200 consultes SQL gairebé idèntiques i saps immediatament que t'has oblidat d'un with() al model Eloquent.

La capacitat de veure correus renderitzats sense enviar-los és un altre cas d'ús que estalvia molt de temps. En lloc de configurar Mailtrap o mirar les capçaleres del correu, simplement obres la secció de mail de Telescope i veus exactament com es veurà el correu al destinatari. Pots verificar el layout, el contingut dinàmic i els enllaços sense enviar cap correu real.

Instal·lació#

La instal·lació de Telescope és directa, però hi ha una consideració important: en molts projectes, Telescope s'instal·la com a dependència de desenvolupament perquè no es vol en producció. Això evita que el paquet consumeixi recursos innecessàriament en l'entorn de producció.

Instal·lació estàndard#

composer require laravel/telescope
 
php artisan telescope:install
 
php artisan migrate

La comanda telescope:install crea el fitxer de configuració config/telescope.php, el service provider app/Providers/TelescopeServiceProvider.php i publica els assets del dashboard. La migració crea la taula telescope_entries on s'emmagatzemen tots els registres, i la taula telescope_entries_tags per als tags.

Instal·lació només per a desenvolupament#

Si vols que Telescope només estigui disponible en l'entorn local i no s'instal·li en producció, pots instal·lar-lo com a dependència de desenvolupament:

composer require laravel/telescope --dev

Quan instal·les Telescope com a dependència de dev, has de registrar el service provider manualment al AppServiceProvider en lloc de confiar en l'auto-discovery de paquets, perquè l'auto-discovery intenta carregar el paquet en tots els entorns:

// app/Providers/AppServiceProvider.php
public function register(): void
{
    if ($this->app->environment('local')) {
        $this->app->register(\Laravel\Telescope\TelescopeServiceProvider::class);
        $this->app->register(TelescopeServiceProvider::class);
    }
}

Afegeix Telescope a la llista dont-discover del composer.json per evitar que es carregui automàticament:

"extra": {
    "laravel": {
        "dont-discover": [
            "laravel/telescope"
        ]
    }
}

Amb aquesta configuració, Telescope només es carregarà quan APP_ENV=local, i en producció no existirà ni com a dependència (perquè Composer no instal·la les dependències require-dev amb --no-dev).

El dashboard i els watchers#

El dashboard de Telescope és accessible a la ruta /telescope de la teva aplicació. Cada secció del dashboard correspon a un "watcher" que monitoritza un aspecte específic de l'aplicació. Telescope ve amb 16 watchers predefinits que cobreixen pràcticament tots els aspectes de l'aplicació.

Requests#

El watcher de peticions HTTP registra cada request que arriba a l'aplicació. Per a cada petició, mostra el mètode HTTP, la URL, el codi de resposta, el temps de resposta, les capçaleres de la petició i la resposta, el payload (body) de la petició, les dades de sessió, les cookies, el middleware aplicat i l'usuari autenticat (si n'hi ha). Això permet depurar problemes d'autenticació, validació, middleware i qualsevol altra cosa relacionada amb el cicle de vida de la petició HTTP:

// Telescope registra automàticament tota aquesta informació
// No cal afegir cap codi al teu controlador
 
class OrderController extends Controller
{
    public function store(StoreOrderRequest $request)
    {
        // Telescope captura:
        // - Les dades validades del request
        // - La sessió de l'usuari
        // - El middleware aplicat (auth, verified, etc.)
        // - El temps de resposta
        // - La resposta retornada
 
        $order = Order::create($request->validated());
 
        return redirect()->route('orders.show', $order);
    }
}

Exceptions#

Cada excepció que es llança a l'aplicació es registra amb el missatge d'error complet, el stack trace, el context (request, usuari, etc.) i la línia de codi exacta on s'ha produït. Les excepcions es poden filtrar per tipus, cosa que facilita trobar totes les ocurrències d'un error específic. Pots veure si un error és recurrent o si ha aparegut per primera vegada, i el context complet ajuda a reproduir el problema.

Queries#

El watcher de consultes SQL és probablement el més valuós per a l'optimització de rendiment. Registra cada consulta SQL executada amb els bindings (els valors reals, no els ?), el temps d'execució en mil·lisegons, la connexió de base de dades utilitzada i el fitxer i la línia de codi que ha originat la consulta. Les consultes lentes es marquen automàticament, cosa que facilita identificar les que necessiten optimització:

// Si el teu controlador fa això:
$users = User::where('active', true)->get();
 
// Telescope mostra la consulta SQL real:
// SELECT * FROM `users` WHERE `active` = 1
// Temps: 2.34ms
// Fitxer: app/Http/Controllers/UserController.php:24

Telescope també detecta automàticament les consultes duplicades i les consultes N+1. Si una pàgina executa la mateixa consulta 50 vegades amb IDs diferents, ho veuràs clarament al dashboard i sabràs que necessites eager loading.

Models#

El watcher de models registra cada operació de creació, actualització i eliminació de models Eloquent. Per a cada operació, mostra el model afectat, els atributs que han canviat (amb els valors antic i nou), i qui ha fet l'operació. Això és molt útil per depurar problemes amb observers, events i mutadors que modifiquen dades de manera inesperada.

Jobs#

Cada job que es dispara es registra amb el seu estat (completat, fallit, pendent), els paràmetres, el temps d'espera a la cua, el temps d'execució, la cua i la connexió. Si el job ha fallat, es mostra l'excepció completa amb el stack trace. Pots veure exactament quins jobs s'han disparat com a resultat d'una petició HTTP, cosa que ajuda a entendre el flux complet de l'aplicació.

Mail#

El watcher de correus és especialment pràctic. Registra cada correu enviat amb el destinatari, l'assumpte, les capçaleres i, el més important, una vista prèvia del correu renderitzat. Pots veure exactament com es veurà el correu al destinatari, amb tot el HTML, el CSS inline i les imatges. Això elimina la necessitat de serveis externs com Mailtrap durant el desenvolupament:

// Quan envies un correu:
Mail::to($user)->send(new WelcomeMail($user));
 
// Telescope mostra:
// - Destinatari: user@example.com
// - Assumpte: Benvingut a la nostra aplicació
// - Vista prèvia del correu renderitzat (HTML complet)
// - Mailable class: App\Mail\WelcomeMail

Notifications#

Les notificacions enviades per qualsevol canal (mail, database, Slack, SMS) es registren amb el destinatari, el canal, el contingut i l'estat. Pots verificar que les notificacions s'envien al canal correcte i amb el contingut esperat.

Cache#

El watcher de cache registra totes les operacions de cache: hits (quan es troba un valor), misses (quan no es troba), sets (quan s'emmagatzema un valor) i deletes (quan s'elimina). Això permet entendre el patró d'ús de la cache i identificar si la cache s'està utilitzant eficientment. Un alt nombre de misses pot indicar que la cache caduca massa ràpid o que les claus no estan ben definides.

Logs#

Totes les entrades de log (Log::info(), Log::error(), etc.) es registren amb el nivell, el missatge i el context. Això és més còmode que obrir el fitxer storage/logs/laravel.log perquè pots filtrar per nivell, buscar per text i veure els logs en context amb la resta d'activitat de l'aplicació.

Commands#

Cada comanda Artisan executada es registra amb els arguments, les opcions, el codi de sortida i el temps d'execució. Útil per depurar tasques programades i comandes personalitzades.

Schedule#

El watcher de tasques programades mostra cada execució del scheduler: quina comanda s'ha executat, si ha tingut èxit o ha fallat, el temps d'execució i la sortida. Pots verificar que les tasques programades s'executen quan toca i amb els resultats esperats.

Events#

Cada event disparat es registra amb els listeners que l'han processat. Pots veure la cadena completa d'events i listeners per entendre com flueix la informació a l'aplicació. Si un listener no s'executa quan esperes, pots verificar ràpidament si l'event s'està disparant.

Gates#

Les comprovacions d'autorització (polítiques i gates) es registren amb el resultat (permès o denegat), l'usuari, l'habilitat comprovada i l'argument. Molt útil per depurar problemes de permisos: pots veure exactament per què un usuari no pot accedir a un recurs.

Views#

Cada vista Blade renderitzada es registra amb les dades que rep. Pots verificar que les vistes reben les variables esperades amb els valors correctes.

Dumps#

El watcher de dumps captura les crides a dump() des de qualsevol lloc de l'aplicació i les mostra al dashboard de Telescope en lloc de la pàgina web. Això és especialment útil quan fas debug de jobs, comandes Artisan o qualsevol codi que no s'executa dins d'una petició HTTP:

// En lloc de veure el dump a la pàgina web,
// apareix al dashboard de Telescope
dump($order->items);
dump($user->permissions);

Redis#

Si l'aplicació utilitza Redis, el watcher de Redis registra cada comanda enviada a Redis amb els arguments i el temps d'execució. Útil per depurar problemes de cache, sessions o cues basades en Redis.

Configuració#

El fitxer config/telescope.php permet controlar el comportament de Telescope en detall. Les opcions més importants són l'activació global, el path del dashboard i la configuració individual de cada watcher.

Activar i desactivar Telescope#

// config/telescope.php
 
// Activar/desactivar Telescope globalment
'enabled' => env('TELESCOPE_ENABLED', true),
 
// Ruta del dashboard
'path' => 'telescope',
 
// Dominis on Telescope està actiu (útil en multi-tenancy)
'domain' => env('TELESCOPE_DOMAIN'),

Configurar watchers individualment#

Cada watcher es pot activar, desactivar i configurar individualment. Alguns watchers accepten opcions addicionals com llindars de temps per marcar consultes lentes:

// config/telescope.php
'watchers' => [
    // Registrar consultes SQL
    Watchers\QueryWatcher::class => [
        'enabled' => env('TELESCOPE_QUERY_WATCHER', true),
        'slow' => 100, // Marcar consultes > 100ms com a lentes
    ],
 
    // Registrar peticions HTTP
    Watchers\RequestWatcher::class => [
        'enabled' => env('TELESCOPE_REQUEST_WATCHER', true),
        'size_limit' => env('TELESCOPE_RESPONSE_SIZE_LIMIT', 64),
    ],
 
    // Registrar operacions de cache
    Watchers\CacheWatcher::class => [
        'enabled' => env('TELESCOPE_CACHE_WATCHER', true),
        // No registrar accions de cache del propi Telescope
        'hidden' => [],
    ],
 
    // Registrar models
    Watchers\ModelWatcher::class => [
        'enabled' => env('TELESCOPE_MODEL_WATCHER', true),
        'events' => ['eloquent.created*', 'eloquent.updated*', 'eloquent.deleted*'],
        'hydrations' => true,
    ],
 
    // Registrar correus
    Watchers\MailWatcher::class => env('TELESCOPE_MAIL_WATCHER', true),
 
    // Registrar excepcions
    Watchers\ExceptionWatcher::class => env('TELESCOPE_EXCEPTION_WATCHER', true),
 
    // Registrar logs
    Watchers\LogWatcher::class => env('TELESCOPE_LOG_WATCHER', true),
 
    // Registrar dumps
    Watchers\DumpWatcher::class => env('TELESCOPE_DUMP_WATCHER', true),
 
    // Registrar jobs
    Watchers\JobWatcher::class => env('TELESCOPE_JOB_WATCHER', true),
 
    // Registrar events
    Watchers\EventWatcher::class => [
        'enabled' => env('TELESCOPE_EVENT_WATCHER', true),
        'ignore' => [],
    ],
 
    // Registrar notificacions
    Watchers\NotificationWatcher::class => env('TELESCOPE_NOTIFICATION_WATCHER', true),
 
    // Registrar gates/polítiques
    Watchers\GateWatcher::class => [
        'enabled' => env('TELESCOPE_GATE_WATCHER', true),
        'ignore_abilities' => [],
        'ignore_packages' => true,
    ],
 
    // Registrar comandes Artisan
    Watchers\CommandWatcher::class => [
        'enabled' => env('TELESCOPE_COMMAND_WATCHER', true),
        'ignore' => [],
    ],
 
    // Registrar tasques programades
    Watchers\ScheduleWatcher::class => env('TELESCOPE_SCHEDULE_WATCHER', true),
 
    // Registrar vistes
    Watchers\ViewWatcher::class => env('TELESCOPE_VIEW_WATCHER', true),
 
    // Registrar comandes Redis
    Watchers\RedisWatcher::class => env('TELESCOPE_REDIS_WATCHER', true),
],

Filtrar registres#

De vegades no vols registrar absolutament tot. Per exemple, pots voler ignorar les peticions a fitxers estàtics, les peticions de health check o les consultes internes de Telescope. El TelescopeServiceProvider permet definir filtres:

// app/Providers/TelescopeServiceProvider.php
use Laravel\Telescope\IncomingEntry;
use Laravel\Telescope\Telescope;
 
public function register(): void
{
    Telescope::night(); // Mode fosc per defecte
 
    $this->hideSensitiveRequestDetails();
 
    Telescope::filter(function (IncomingEntry $entry) {
        // En local, registrar-ho tot
        if ($this->app->environment('local')) {
            return true;
        }
 
        // En altres entorns, només registrar errors i anomalies
        return $entry->isReportableException() ||
               $entry->isFailedRequest() ||
               $entry->isFailedJob() ||
               $entry->isScheduledTask() ||
               $entry->hasMonitoredTag();
    });
}

La funció filter rep cada entrada que Telescope vol registrar i retorna true per guardar-la o false per descartar-la. Això és molt útil si decideixes tenir Telescope actiu en producció però només vols registrar errors i anomalies per reduir l'impacte en el rendiment i l'espai de disc.

Amagar dades sensibles#

Telescope captura per defecte totes les dades de les peticions, incloses contrasenyes, tokens i altra informació sensible. El mètode hideSensitiveRequestDetails elimina automàticament camps com password, password_confirmation i _token. Pots afegir més camps:

// app/Providers/TelescopeServiceProvider.php
protected function hideSensitiveRequestDetails(): void
{
    if ($this->app->environment('local')) {
        return;
    }
 
    Telescope::hideRequestParameters([
        '_token',
        'password',
        'password_confirmation',
        'credit_card',
        'api_key',
    ]);
 
    Telescope::hideRequestHeaders([
        'cookie',
        'x-csrf-token',
        'x-xsrf-token',
        'authorization',
    ]);
}

Tags#

Telescope assigna automàticament tags a les entrades basant-se en els models Eloquent involucrats. Per exemple, si una petició carrega un model User amb ID 5, l'entrada es tageja automàticament amb App\Models\User:5. Això permet buscar ràpidament totes les entrades relacionades amb un usuari o un model concret.

Pots afegir tags personalitzats programàticament:

// app/Providers/TelescopeServiceProvider.php
use Laravel\Telescope\IncomingEntry;
use Laravel\Telescope\Telescope;
 
public function register(): void
{
    Telescope::tag(function (IncomingEntry $entry) {
        // Afegir tags personalitzats a les peticions
        if ($entry->type === 'request') {
            return [
                'status:' . $entry->content['response_status'],
            ];
        }
 
        return [];
    });
}

Els tags personalitzats apareixen al dashboard i es poden utilitzar per filtrar les entrades. Per exemple, pots buscar status:500 per veure ràpidament totes les peticions que han retornat un error 500.

Poda d'entrades antigues#

Telescope emmagatzema totes les entrades a la base de dades, cosa que pot ocupar molt d'espai amb el temps. La comanda telescope:prune elimina les entrades antigues. Es recomana programar-la al scheduler perquè s'executi automàticament:

// routes/console.php o app/Console/Kernel.php
use Illuminate\Support\Facades\Schedule;
 
Schedule::command('telescope:prune')->daily();
 
// O amb un interval personalitzat (en hores)
Schedule::command('telescope:prune --hours=48')->daily();

Per defecte, telescope:prune elimina les entrades de més de 24 hores. L'opció --hours permet canviar aquest interval. En desenvolupament, 24 hores sol ser suficient. Si vols un historial més llarg, augmenta les hores, però tingues en compte l'espai de disc.

Seguretat del dashboard#

El dashboard de Telescope mostra informació molt sensible: consultes SQL, dades de peticions, contingut de correus, excepcions amb stack traces. En producció, l'accés ha d'estar estrictament controlat.

Per defecte, Telescope només és accessible quan APP_ENV=local. Si el tens actiu en altres entorns, has de definir una política d'autorització:

// app/Providers/TelescopeServiceProvider.php
protected function gate(): void
{
    Gate::define('viewTelescope', function ($user) {
        return in_array($user->email, [
            'admin@example.com',
            'developer@example.com',
        ]);
    });
}

Telescope està pensat principalment per a l'entorn de desenvolupament. Si el fas servir en producció, tingues en compte que cada petició, cada consulta i cada event es registren a la base de dades, cosa que pot afectar el rendiment. Utilitza filtres agressius per registrar només errors i anomalies, i programa la poda diàriament per evitar que la taula d'entrades creixi indefinidament.

Consideracions de rendiment en producció#

Si decideixes tenir Telescope actiu en producció (algunes aplicacions ho fan per poder investigar problemes en temps real), has de prendre precaucions per minimitzar l'impacte en el rendiment.

La primera mesura és desactivar els watchers que no necessites. El watcher de queries és el que més impacte té perquè intercepta cada consulta SQL. Si només necessites veure les excepcions i els jobs fallits en producció, desactiva la resta de watchers:

# .env (producció)
TELESCOPE_ENABLED=true
TELESCOPE_QUERY_WATCHER=false
TELESCOPE_REQUEST_WATCHER=false
TELESCOPE_MODEL_WATCHER=false
TELESCOPE_EVENT_WATCHER=false
TELESCOPE_VIEW_WATCHER=false
TELESCOPE_CACHE_WATCHER=false
TELESCOPE_REDIS_WATCHER=false
TELESCOPE_DUMP_WATCHER=false
 
# Mantenir actius
TELESCOPE_EXCEPTION_WATCHER=true
TELESCOPE_JOB_WATCHER=true
TELESCOPE_LOG_WATCHER=true
TELESCOPE_MAIL_WATCHER=true
TELESCOPE_COMMAND_WATCHER=true
TELESCOPE_SCHEDULE_WATCHER=true

La segona mesura és configurar el filtre per registrar només les anomalies, com s'ha vist a la secció de configuració. Amb un filtre adequat, Telescope en producció pot ser molt lleuger perquè la majoria de peticions i operacions es descarten sense ser registrades.

La tercera mesura és utilitzar una base de dades separada per a les entrades de Telescope. Això evita que les insercions de Telescope afectin la base de dades principal de l'aplicació:

// config/telescope.php
'storage' => [
    'database' => [
        'connection' => 'telescope',
        'chunk' => 1000,
    ],
],
# .env
TELESCOPE_DB_CONNECTION=telescope
DB_TELESCOPE_HOST=127.0.0.1
DB_TELESCOPE_DATABASE=telescope

Telescope vs Pulse: quan usar cadascun#

Telescope i Pulse són dos paquets que poden semblar similars a primera vista, però serveixen per a propòsits molt diferents i són complementaris.

Telescope és una eina de depuració pensada per al desenvolupament. Registra cada petició individual, cada consulta SQL individual, cada excepció. Et permet inspeccionar el detall de cada operació concreta. És com un microscopi que et mostra exactament què passa en cada moment.

Pulse és una eina de monitorització pensada per a producció. Mostra mètriques agregades: temps de resposta mitjà, consultes lentes més freqüents, ús de recursos del servidor, usuaris més actius. No et mostra cada petició individual, sinó les tendències i els patrons. És com un quadre de comandament que et dona una visió general de la salut de l'aplicació.

La combinació ideal és: Telescope en desenvolupament per depurar i entendre el codi, i Pulse en producció per monitoritzar el rendiment i detectar problemes. Alguns equips també mantenen Telescope en staging per investigar problemes que no es reprodueixen en local, però amb filtres molt estrictes per limitar l'impacte en el rendiment.