Laravel Time Machine: Perfila tu Request Lifecycle
Laravel Time Machine: Perfila tu Request Lifecycle
Cuando desarrollamos aplicaciones Laravel, a menudo nos preguntamos: “¿Por qué esta request es tan lenta?”. Las respuestas pueden venir de múltiples lugares: bootstrapping, middlewares, queries SQL, eventos, o lógica de aplicación. Laravel Time Machine es una herramienta que responde exactamente a esta pregunta, permitiéndote ver en detalle cada etapa del ciclo de vida de una request.
En este artículo, te mostraremos cómo usar Laravel Time Machine para identificar y resolver problemas de rendimiento en tus aplicaciones, con ejemplos prácticos que puedes implementar hoy mismo.
¿Qué es Laravel Time Machine?
Laravel Time Machine es un profiler especializado que captura y visualiza cada fase del ciclo de vida de una request HTTP en Laravel. Desde el bootstrap inicial hasta la terminación de la respuesta, esta herramienta te proporciona un timeline detallado con:
- Duración de cada etapa del ciclo de vida
- Queries SQL ejecutadas y su tiempo
- Eventos disparados
- Middlewares y su tiempo de ejecución
- Memoria utilizada en cada punto
A diferencia de tools genéricas como Telescope, Time Machine se enfoca específicamente en el flujo temporal de una request, lo que lo hace ideal para debugging de performance.
Instalación y Configuración
Para comenzar, instala el paquete mediante Composer:
composer require --dev laravel/time-machine
Luego, publica la configuración:
php artisan vendor:publish --provider="Laravel\TimeMachine\TimeMachineServiceProvider"
Esto creará un archivo de configuración en config/time-machine.php:
<?php
return [
'enabled' => env('TIME_MACHINE_ENABLED', true),
'storage' => env('TIME_MACHINE_STORAGE', 'file'),
'file_path' => storage_path('time-machine'),
'retention_days' => 7,
'sample_rate' => env('TIME_MACHINE_SAMPLE_RATE', 100),
'capture_queries' => true,
'capture_events' => true,
'slow_threshold' => env('TIME_MACHINE_SLOW_THRESHOLD', 1000),
];
Accediendo al Dashboard
Una vez instalado, accede al dashboard en:
http://tu-app.local/time-machine
El dashboard te mostrará un timeline interactivo de todas las requests capturadas. Puedes hacer clic en cualquier request para ver sus detalles completos.
Usando Time Machine en tu Aplicación
Captura Manual de Checkpoints
Aunque Time Machine captura automáticamente las etapas principales, puedes agregar checkpoints personalizados en tu código:
<?php
namespace App\Http\Controllers;
use TimeMachine;
class ProductController extends Controller
{
public function index()
{
TimeMachine::checkpoint('fetching_products');
$products = Product::with('category')->get();
TimeMachine::checkpoint('processing_products');
$formatted = $products->map(function ($product) {
return [
'id' => $product->id,
'name' => $product->name,
'price' => $product->price,
'category' => $product->category->name,
];
});
TimeMachine::checkpoint('formatting_complete');
return response()->json($formatted);
}
}
Los checkpoints se mostrarán en el timeline, permitiéndote ver exactamente dónde se consume más tiempo.
Etiquetando Información Contextual
Puedes agregar contexto adicional a tus checkpoints:
TimeMachine::checkpoint('cache_lookup', [
'key' => 'user_' . auth()->id(),
'hit' => true,
'time_saved_ms' => 45,
]);
TimeMachine::checkpoint('database_query', [
'query' => 'SELECT * FROM products WHERE category = ?',
'bindings' => ['electronics'],
'rows_affected' => 245,
]);
Identificando Cuellos de Botella
Caso 1: Queries N+1
Una situación común es el problema N+1, donde ejecutamos múltiples queries innecesarias:
// ❌ LENTO: N+1 queries
public function getUsersWithPosts()
{
TimeMachine::checkpoint('start_user_fetch');
$users = User::all(); // 1 query
TimeMachine::checkpoint('users_fetched', ['count' => $users->count()]);
foreach ($users as $user) {
$posts = $user->posts; // N queries más (una por usuario)
}
TimeMachine::checkpoint('posts_loaded', ['total_queries' => count($users) + 1]);
}
// ✅ RÁPIDO: Eager loading
public function getUsersWithPosts()
{
TimeMachine::checkpoint('start_user_fetch');
$users = User::with('posts')->get(); // Solo 2 queries
TimeMachine::checkpoint('data_loaded', ['queries' => 2]);
}
Al ver el timeline en el dashboard, verás inmediatamente la diferencia de tiempo entre ambos enfoques.
Caso 2: Procesamiento Lento en el Loop
// ❌ LENTO: Procesamiento síncrono pesado
public function importProducts(array $data)
{
TimeMachine::checkpoint('import_start');
foreach ($data as $item) {
$product = new Product($item);
$product->save();
// Operación pesada en cada iteración
$this->generateThumbnail($product->image);
$this->updateSearchIndex($product);
}
TimeMachine::checkpoint('import_complete');
}
// ✅ RÁPIDO: Despacho a colas
public function importProducts(array $data)
{
TimeMachine::checkpoint('import_start');
Product::insert($data); // Inserción en batch
TimeMachine::checkpoint('data_inserted');
// Despachar trabajos pesados a cola
Bus::batch($data)
->dispatch()
->then(function (Batch $batch) {
TimeMachine::checkpoint('batch_jobs_queued');
});
}
Analizando el Timeline en Detalle
El dashboard de Time Machine muestra varias capas de información:
┌─ REQUEST TIMELINE ────────────────────────────────────────┐
│ 0ms Bootstrap [████████] 45ms │
│ 45ms Routing [██] 8ms │
│ 53ms Middleware Stack [████████] 42ms │
│ 95ms Controller Execution [██████████] 87ms│
│ 182ms Response Rendering [███] 23ms │
│ 205ms TOTAL REQUEST TIME │
└───────────────────────────────────────────────────────────┘
Dentro de “Controller Execution”, verías tus checkpoints personalizados:
├─ start_user_fetch 0ms
├─ users_fetched 45ms (25 usuarios)
├─ database_query_posts 82ms (25 queries)
└─ posts_loaded 87ms (total 26 queries)
Monitoreo de Memoria
Time Machine también rastrea el uso de memoria:
public function processLargeFile($filePath)
{
TimeMachine::checkpoint('start', [
'memory_usage_mb' => memory_get_usage(true) / 1024 / 1024,
]);
$file = fopen($filePath, 'r');
while ($line = fgets($file)) {
// Procesar línea por línea para mantener memoria baja
$this->processLine($line);
}
fclose($file);
TimeMachine::checkpoint('complete', [
'memory_peak_mb' => memory_get_peak_usage(true) / 1024 / 1024,
'memory_current_mb' => memory_get_usage(true) / 1024 / 1024,
]);
}
En el dashboard, verás cómo evoluciona la memoria a lo largo del ciclo de vida.
Exportando Datos de Profiling
Para análisis más profundos, puedes exportar los datos del timeline:
// En un comando o controlador
use TimeMachine;
$timeline = TimeMachine::getLastRequest();
$csv = "Checkpoint,Time (ms),Memory (MB),Context\n";
foreach ($timeline->checkpoints() as $checkpoint) {
$csv .= sprintf(
"%s,%d,%.2f,%s\n",
$checkpoint->name,
$checkpoint->elapsedMs(),
$checkpoint->memoryMb(),
json_encode($checkpoint->context())
);
}
Storage::disk('local')->put('timeline.csv', $csv);
Mejores Prácticas
1. Habilita Solo en Desarrollo
// config/time-machine.php
'enabled' => app()->isLocal(),
2. Usa Sample Rate en Producción (si está habilitado)
// Captura solo el 5% de requests
'sample_rate' => env('TIME_MACHINE_SAMPLE_RATE', 5),
3. Establece Thresholds para Alertas
TimeMachine::setSlow(1000); // Alert si request > 1 segundo
// En tu middleware
if (TimeMachine::getLastRequest()->totalMs() > 1000) {
Log::warning('Slow request detected', [
'url' => request()->url(),
'time' => TimeMachine::getLastRequest()->totalMs() . 'ms',
]);
}
4. Integra con tu Sistema de Monitoreo
// En AppServiceProvider
use TimeMachine;
public function boot()
{
if (app()->isProduction()) {
TimeMachine::listen(function ($timeline) {
if ($timeline->totalMs() > 2000) {
// Enviar a tu sistema de monitoring
Sentry::captureMessage('Slow request', [
'level' => 'warning',
'extra' => $timeline->toArray(),
]);
}
});
}
}
Ventajas sobre Otras Herramientas
| Característica | Time Machine | Telescope | Blackfire | Xdebug |
|---|---|---|---|---|
| Timeline visual | ✅ | ✅ | ✅ | ❌ |
| Overhead bajo | ✅ | ⚠️ | ❌ | ❌ |
| Focused en timing | ✅ | ❌ | ✅ | ❌ |
| SQL capture | ✅ | ✅ | ✅ | ⚠️ |
| Fácil de usar | ✅ | ✅ | ❌ | ❌ |
Conclusión
Laravel Time Machine es una herramienta invaluable para desarrolladores que quieren entender y optimizar el rendimiento de sus aplicaciones. Proporcionando una vista clara y detallada del ciclo de vida de cada request, te permite identificar cuellos de botella con precisión quirúrgica.
Ya sea que estés depurando una aplicación lenta o simplemente quieras asegurar que tu código es eficiente, Time Machine te proporciona los datos visuales que necesitas para tomar decisiones informadas sobre optimización.
Puntos clave
- Laravel Time Machine perfila cada etapa del ciclo de vida de una request
- Usa checkpoints personalizados para medir secciones específicas de tu código
- El dashboard interactivo facilita la identificación de cuellos de botella
- Integra con tu sistema de monitoreo existente para alertas automáticas
- Sample rate permite usar en producción con overhead mínimo
- Detecta problemas N+1, procesamiento lento y fugas de memoria
- La visualización temporal es superior a herramientas genéricas para profiling
- Exporta datos para análisis más profundos y reporting
- Mejor para desarrollo; con cuidado puedes usarlo en producción
- Combínalo con eager loading y job dispatching para máximo rendimiento