Logs y depuración
Dónde se escriben los errores, con qué frecuencia se reportan, cómo recibirlos en Slack, y las herramientas que encuentran páginas lentas y consultas N+1.
El kit escribe un log diario, limita los reportes de una excepción repetida para que una página rota no lo llene, y puede publicar cada error nuevo en Slack. En desarrollo suma la debugbar, un detector de consultas N+1 y un seguimiento en vivo del log. Esta guía cubre las variables detrás de cada uno y las dos cosas que hacer antes de desplegar: proteger el visor de logs y poner el token de Slack.
El visor de logs en /logs
routes/web.php registra GET /logs con el LogViewerController del paquete rap2hpoutre/laravel-log-viewer. Lista los archivos de storage/logs/, te deja leerlos, descargarlos y borrarlos, y el kit no le agrega ningún middleware: la ruta es pública. Protégela antes de desplegar, ya sea envolviéndola:
Route::get('logs', LogViewerController::class . '@index')->middleware(['auth', 'role:admin']);
o moviendo la línea a routes/admin.php, donde se convierte en /admin/logs detrás del rol de administrador.
Canales y variables
config/logging.php conserva los canales de Laravel más uno del kit, slack_api.
| Variable | Valor por omisión | Qué hace |
|---|---|---|
LOG_CHANNEL |
daily |
El canal al que se escribe todo. daily rota storage/logs/laravel-YYYY-MM-DD.log |
LOG_STACK |
daily |
Canales separados por coma que se usan cuando LOG_CHANNEL=stack |
LOG_LEVEL |
debug |
Nivel mínimo para single, daily, papertrail, stderr, syslog y errorlog; critical para slack |
LOG_DAILY_DAYS |
14 |
Días de archivos diarios que se conservan antes de que la rotación los borre |
LOG_DEPRECATIONS_CHANNEL |
null |
A dónde van los avisos de funciones obsoletas de PHP y librerías; null los descarta |
LOG_DEPRECATIONS_TRACE |
false |
Incluir la traza con cada aviso de obsolescencia |
LOG_STDERR_FORMATTER |
ninguno | Clase de formateador de Monolog para el canal stderr, para contenedores que recogen la salida de error |
LOG_SYSLOG_FACILITY |
LOG_USER |
Facility del canal syslog |
LOG_PAPERTRAIL_HANDLER |
SyslogUdpHandler |
Clase del handler del canal papertrail |
PAPERTRAIL_URL, PAPERTRAIL_PORT |
ninguno | Host y puerto del canal papertrail |
LOG_SLACK_WEBHOOK_URL |
ninguno | Webhook entrante del canal slack estándar de Laravel |
LOG_SLACK_USERNAME |
Laravel Log |
Nombre con el que publica el canal slack estándar |
LOG_SLACK_EMOJI |
:boom: |
Icono del canal slack estándar |
SLACK_BOT_TOKEN |
ninguno | Token de bot del canal slack_api del kit; definirlo activa las alertas de error de abajo |
SLACK_LOG_CHANNEL |
#errores |
Canal de Slack al que publica slack_api |
El canal slack estándar es un canal normal de Laravel: nada en el kit escribe en él salvo que lo agregues a LOG_STACK. Las alertas de error del kit pasan por slack_api.
Alertas de error en Slack
slack_api es un SlackHandler de Monolog que habla con la API de Slack con un token de bot. Publica como Laravel Logs con el icono :boom:, en nivel error y superiores, como un adjunto que incluye el contexto de la excepción salvo el objeto de la excepción, la URL y el id de usuario.
Para activarlo:
- Crea una app de Slack con un token de bot que tenga
chat:write, e invita al bot al canal. - Define las variables:
SLACK_BOT_TOKEN=xoxb-tu-token
SLACK_LOG_CHANNEL=#errores
Nada más cambia: el manejador de excepciones en bootstrap/app.php revisa si slack_api tiene token y, cuando lo tiene, publica cada excepción que pasa el límite de abajo. Dos mensajes nunca llegan a Slack ni así, porque son ruido que la siguiente petición arregla: una conexión a la base de datos rechazada, SQLSTATE[HY000] [2002], y el Cannot update locked property de Livewire.
Con qué frecuencia se reporta una excepción
bootstrap/app.php decide, en withExceptions, si una excepción se escribe siquiera. En el entorno local cada excepción se reporta, todas las veces. En los demás:
- El mensaje se normaliza, reemplazando números y fechas por marcadores, y se convierte en un hash junto con el nombre de la clase. El conteo de esa firma se guarda en caché 30 días.
- La excepción se reporta cuando el conteo llega a 1, 10, 25, 50, 100, 300, 500 o 1000, y después cada 1000.
- Incluso en esos conteos, la misma firma se reporta a lo más una vez cada 5 minutos.
- Una excepción lanzada dentro del componente anfitrión de modales,
wire-elements-modal, nunca se reporta. - Los mensajes listados en
ignoredExceptionMessages(), hoy sólo elactiveComponent must not be accessed before initializationdel paquete de modales, no se reportan en ningún entorno.
Cada reporte lleva contexto extra: la última URL no Livewire que la persona abrió, la ruta de la petición, el user agent, el entorno, el componente Livewire que corría y cuántas veces se ha visto esta excepción. Ese es el conteo que el botón Limpiar caché de logs de La devzone reinicia, cuando el almacén de caché es database, para que un error corregido se reporte de nuevo desde 1.
El detector de consultas N+1
beyondcode/laravel-query-detector observa cada petición y reporta una relación cargada dentro de un ciclo. config/querydetector.php:
| Variable | Valor por omisión | Qué hace |
|---|---|---|
QUERY_DETECTOR_ENABLED |
null |
null sigue a APP_DEBUG; true o false lo fuerza |
QUERY_DETECTOR_THRESHOLD |
1 |
Cuántas veces puede correr una relación antes de reportarse; 1 reporta cada repetición |
QUERY_DETECTOR_LOG_CHANNEL |
daily |
Canal usado cuando se agrega la salida Log |
Su salida es la debugbar: los hallazgos aparecen en una pestaña Messages de la barra. Pon en la lista blanca una relación que se carga a propósito en el arreglo except de la configuración, con la clase del modelo y el nombre de la relación:
'except' => [
App\Models\Order::class => [
App\Models\OrderLine::class,
'lines',
],
],
La debugbar
barryvdh/laravel-debugbar es una dependencia de desarrollo; muestra consultas, vistas, la sesión y la línea de tiempo de la petición al pie de cada página. config/debugbar.php:
| Variable | Valor por omisión | Qué hace |
|---|---|---|
DEBUGBAR_ENABLED |
null |
null sigue a APP_DEBUG; pon false para ocultarla con debug activo |
DEBUGBAR_EDITOR |
phpstorm |
Editor que abren los enlaces a archivos: phpstorm, vscode, vscode-insiders, vscode-remote, vscode-insiders-remote, vscodium, textmate, emacs, sublime, atom, nova, macvim, idea, netbeans, xdebug o espresso |
DEBUGBAR_THEME |
auto |
auto, light o dark |
DEBUGBAR_OPEN_STORAGE |
false |
Permite a cualquiera abrir desde la barra los datos guardados de peticiones anteriores; nunca lo actives donde el sitio es público |
DEBUGBAR_LOCAL_SITES_PATH, DEBUGBAR_REMOTE_SITES_PATH |
vacío | Mapean una ruta dentro de un contenedor o VM a la ruta en tu máquina para que los enlaces al editor resuelvan |
Nunca la actives en producción: expone consultas y datos de sesión a cualquiera que cargue una página.
Sigue el log mientras desarrollas
composer dev arranca el servidor, el worker de la cola, Vite y php artisan pail, que imprime cada entrada del log en la terminal conforme ocurre. Corre php artisan pail solo para seguir el log de un sitio en marcha, y php artisan pail --filter="QueryException" para ver un solo tipo de entrada. En un servidor, sigue el archivo diario:
tail -f storage/logs/laravel-$(date +%F).log
Las variables que definir en un servidor, estas entre ellas, están listadas en Despliega tu proyecto.