Gestión de errores
Laravel proporciona un sistema robusto para el manejo de excepciones que funciona de manera automática desde el momento en que creates tu proyecto. Sin embargo, la verdadera ventaja radica en la capacidad de personalizar cómo tu aplicación reporta y renderiza las excepciones según las necesidades específicas de tu proyecto.
Configuración básica del manejo de errores
El punto central para configurar el manejo de excepciones en Laravel se encuentra en el archivo bootstrap/app.php
, donde puedes utilizar el método withExceptions()
para personalizar el comportamiento:
<?php
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
)
->withExceptions(function (Exceptions $exceptions) {
// Configuración personalizada de excepciones
})
->create();
La variable de entorno APP_DEBUG
en tu archivo .env
controla cuánta información sobre errores se muestra al usuario. Durante el desarrollo local debes mantenerla como true
, pero en producción siempre debe ser false
para evitar exponer información sensible.
Reporteo personalizado de excepciones
El reporteo de excepciones te permite registrar errores en logs o enviarlos a servicios externos como Sentry. Puedes configurar diferentes comportamientos según el tipo de excepción:
use App\Exceptions\PaymentException;
use App\Exceptions\OrderException;
->withExceptions(function (Exceptions $exceptions) {
// Reportar excepciones de pago a un servicio específico
$exceptions->report(function (PaymentException $e) {
// Enviar a servicio de monitoreo de pagos
logger()->critical('Payment error occurred', [
'user_id' => auth()->id(),
'amount' => $e->getAmount(),
'error' => $e->getMessage()
]);
});
// Reportar errores de pedidos con contexto adicional
$exceptions->report(function (OrderException $e) {
// Notificar al equipo de soporte
return true; // Continúa con el log normal
});
})
Control de contexto en logs
Laravel automáticamente añade el ID del usuario actual a los logs de excepciones. Puedes agregar contexto global adicional que aparecerá en todos los logs de errores:
->withExceptions(function (Exceptions $exceptions) {
$exceptions->context(function () {
return [
'environment' => app()->environment(),
'version' => config('app.version'),
'request_id' => request()->header('X-Request-ID'),
];
});
})
Para excepciones específicas, puedes definir contexto particular implementando el método context()
en tu clase de excepción:
<?php
namespace App\Exceptions;
use Exception;
class ApiException extends Exception
{
public function __construct(
string $message,
private string $endpoint,
private array $requestData = []
) {
parent::__construct($message);
}
public function context(): array
{
return [
'api_endpoint' => $this->endpoint,
'request_data' => $this->requestData,
'timestamp' => now()->toISOString(),
];
}
}
Niveles de log y filtrado de excepciones
Puedes configurar niveles específicos para diferentes tipos de excepciones, lo que afecta cómo se registran en los logs:
use PDOException;
use Psr\Log\LogLevel;
->withExceptions(function (Exceptions $exceptions) {
// Errores de base de datos como críticos
$exceptions->level(PDOException::class, LogLevel::CRITICAL);
// Ignorar ciertos tipos de excepciones
$exceptions->dontReport([
\App\Exceptions\ValidationException::class,
\Symfony\Component\HttpKernel\Exception\NotFoundHttpException::class,
]);
})
También puedes ignorar excepciones condicionalmente usando el método dontReportWhen()
:
use App\Exceptions\ThirdPartyException;
->withExceptions(function (Exceptions $exceptions) {
$exceptions->dontReportWhen(function (Throwable $e) {
return $e instanceof ThirdPartyException &&
$e->getCode() === 503 &&
app()->environment('testing');
});
})
Renderizado personalizado de excepciones
El renderizado controla cómo se presentan las excepciones al usuario final. Puedes personalizar las respuestas según el tipo de excepción y el contexto de la petición:
use App\Exceptions\ApiException;
use Illuminate\Http\Request;
->withExceptions(function (Exceptions $exceptions) {
$exceptions->render(function (ApiException $e, Request $request) {
if ($request->is('api/*')) {
return response()->json([
'error' => [
'message' => $e->getMessage(),
'code' => $e->getCode(),
'timestamp' => now()->toISOString()
]
], 400);
}
return response()->view('errors.api-error', [
'exception' => $e
], 400);
});
})
Función auxiliar report()
La función report()
te permite reportar excepciones sin interrumpir el flujo normal de la aplicación. Es especialmente útil para registrar errores recuperables:
public function processPayment($paymentData)
{
try {
$result = $this->paymentGateway->charge($paymentData);
return $result;
} catch (GatewayTimeoutException $e) {
// Reportar el error pero intentar método alternativo
report($e);
return $this->fallbackPaymentMethod($paymentData);
} catch (PaymentDeclinedException $e) {
// Reportar y relanzar para manejo específico
report($e);
throw $e;
}
}
Deduplicación de excepciones
Para evitar duplicados en los logs cuando la misma instancia de excepción se reporta múltiples veces, puedes activar la deduplicación:
->withExceptions(function (Exceptions $exceptions) {
$exceptions->dontReportDuplicates();
})
Throttling de excepciones
En aplicaciones con alto volumen, puedes limitar el número de excepciones reportadas para evitar spam en los logs:
use Illuminate\Support\Lottery;
use Illuminate\Cache\RateLimiting\Limit;
->withExceptions(function (Exceptions $exceptions) {
$exceptions->throttle(function (Throwable $e) {
// Solo reportar 1 de cada 100 excepciones de monitoreo
if ($e instanceof \App\Exceptions\MonitoringException) {
return Lottery::odds(1, 100);
}
// Limitar errores de terceros a 50 por minuto
if ($e instanceof \App\Exceptions\ThirdPartyException) {
return Limit::perMinute(50)->by($e->getMessage());
}
return null; // Sin limitación para otros errores
});
})
Excepciones reportables y renderizables
Puedes crear excepciones inteligentes que manejen su propio reporteo y renderizado implementando los métodos correspondientes directamente en la clase:
<?php
namespace App\Exceptions;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class BusinessLogicException extends Exception
{
public function report(): void
{
// Solo reportar en producción
if (app()->environment('production')) {
logger()->warning($this->getMessage(), [
'user_id' => auth()->id(),
'trace' => $this->getTraceAsString()
]);
}
}
public function render(Request $request): Response
{
if ($request->expectsJson()) {
return response()->json([
'message' => 'Business rule violation',
'details' => $this->getMessage()
], 422);
}
return response()->view('errors.business-error', [
'message' => $this->getMessage()
], 422);
}
}
Manejo de excepciones HTTP
Laravel facilita la generación de respuestas HTTP de error usando la función abort()
:
public function show($id)
{
$user = User::find($id);
if (!$user) {
abort(404, 'Usuario no encontrado');
}
if (!$user->isActive()) {
abort(403, 'Usuario inactivo');
}
return view('users.show', compact('user'));
}
Páginas de error personalizadas
Para crear páginas de error personalizadas, simplemente crea vistas en el directorio resources/views/errors/
con el nombre del código de estado HTTP:
resources/views/errors/404.blade.php:
@extends('layouts.app')
@section('title', 'Página no encontrada')
@section('content')
<div class="error-page">
<h1>¡Ups! Página no encontrada</h1>
<p>La página que buscas no existe o ha sido movida.</p>
@if(isset($exception))
<p class="error-message">{{ $exception->getMessage() }}</p>
@endif
<a href="{{ route('home') }}" class="btn btn-primary">
Volver al inicio
</a>
</div>
@endsection
También puedes definir páginas de respaldo para rangos de errores creando archivos como 4xx.blade.php
o 5xx.blade.php
que se utilizarán cuando no exista una página específica para el código de estado.
Fuentes y referencias
Documentación oficial y recursos externos para profundizar en Laravel
Documentación oficial de Laravel
Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Laravel es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.
Más tutoriales de Laravel
Explora más contenido relacionado con Laravel y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
- Comprender la configuración básica del manejo de excepciones en Laravel.
- Aprender a personalizar el reporteo y renderizado de excepciones.
- Configurar niveles de log, contexto y filtrado de errores.
- Implementar deduplicación y throttling para el control de excepciones.
- Crear excepciones inteligentes con métodos propios de reporte y renderizado.