Saltar contenido

Registro

Introducción

Para ayudarte a aprender más sobre lo que está sucediendo dentro de tu aplicación, Laravel ofrece servicios de logging robustos que te permiten registrar mensajes en archivos, en el registro de errores del sistema e incluso en Slack para notificar a todo tu equipo. El registro de Laravel se basa en "canales". Cada canal representa una forma específica de escribir información de registro. Por ejemplo, el canal single escribe archivos de registro en un solo archivo de registro, mientras que el canal slack envía mensajes de registro a Slack. Los mensajes de registro pueden escribirse en múltiples canales según su gravedad. Bajo el capó, Laravel utiliza la biblioteca Monolog, que proporciona soporte para una variedad de potentes controladores de registro. Laravel facilita la configuración de estos controladores, lo que te permite combinarlos y personalizar el manejo de registros de tu aplicación.

Configuración

Todas las opciones de configuración que controlan el comportamiento de registro de tu aplicación se encuentran en el archivo de configuración config/logging.php. Este archivo te permite configurar los canales de registro de tu aplicación, así que asegúrate de revisar cada uno de los canales disponibles y sus opciones. Revisaremos algunas opciones comunes a continuación. Por defecto, Laravel utilizará el canal stack al registrar mensajes. El canal stack se utiliza para agregar múltiples canales de registro en un solo canal. Para obtener más información sobre cómo construir pilas, consulta la documentación a continuación.

Controladores de Canal Disponibles

Cada canal de registro está impulsado por un "driver". El driver determina cómo y dónde se graba realmente el mensaje de registro. Los siguientes drivers de canal de registro están disponibles en cada aplicación Laravel. Una entrada para la mayoría de estos drivers ya está presente en el archivo de configuración config/logging.php de tu aplicación, así que asegúrate de revisar este archivo para familiarizarte con su contenido:

Nombre Descripción
custom Un driver que llama a una fábrica especificada para crear un canal.
daily Un driver de Monolog basado en RotatingFileHandler que rota diario.
errorlog Un driver de Monolog basado en ErrorLogHandler.
monolog Un driver de fábrica de Monolog que puede usar cualquier manejador de Monolog soportado.
papertrail Un driver de Monolog basado en SyslogUdpHandler.
single Un canal de registrador basado en un solo archivo o ruta (StreamHandler).
slack Un driver de Monolog basado en SlackWebhookHandler.
stack Un envoltorio para facilitar la creación de canales "multi-canal".
syslog Un driver de Monolog basado en SyslogHandler.
> [!NOTE] Consulta la documentación sobre [personalización avanzada de canales](#monolog-channel-customization) para aprender más sobre los drivers `monolog` y `custom`.

Configurando el Nombre del Canal

Por defecto, Monolog se instancia con un "nombre de canal" que coincide con el entorno actual, como production o local. Para cambiar este valor, puedes agregar una opción name a la configuración de tu canal:

'stack' => [
'driver' => 'stack',
'name' => 'channel-name',
'channels' => ['single', 'slack'],
],

Prerrequisitos del Canal

Configurando los Canales Simple y Diario

Los canales single y daily tienen tres opciones de configuración opcionales: bubble, permission y locking.

Nombre Descripción Predeterminado
bubble Indica si los mensajes deben elevarse a otros canales después de ser manejados. true
locking Intenta bloquear el archivo de registro antes de escribir en él. false
permission Los permisos del archivo de registro. 0644
Además, la política de retención para el canal `daily` se puede configurar a través de la variable de entorno `LOG_DAILY_DAYS` o configurando la opción `days`.
Nombre Descripción Predeterminado
days El número de días que se deben retener los archivos de registro diarios. 7

Configurando el Canal de Papertrail

El canal papertrail requiere opciones de configuración host y port. Estos pueden definirse a través de las variables de entorno PAPERTRAIL_URL y PAPERTRAIL_PORT. Puedes obtener estos valores de Papertrail.

Configurando el canal de Slack

El canal slack requiere una opción de configuración url. Este valor puede definirse a través de la variable de entorno LOG_SLACK_WEBHOOK_URL. Esta URL debe coincidir con una URL para un webhook entrante que hayas configurado para tu equipo de Slack. Por defecto, Slack solo recibirá registros en el nivel crítico y superior; sin embargo, puedes ajustar esto utilizando la variable de entorno LOG_LEVEL o modificando la opción de configuración level dentro del array de configuración del canal de registro de Slack.

Registro de Advertencias de Deprecación

PHP, Laravel y otras bibliotecas a menudo notifican a sus usuarios que algunas de sus características han sido desaprobadas y se eliminarán en una versión futura. Si deseas registrar estas advertencias de desaprobación, puedes especificar tu canal de registro deprecations preferido utilizando la variable de entorno LOG_DEPRECATIONS_CHANNEL, o dentro del archivo de configuración config/logging.php de tu aplicación:

'deprecations' => [
'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'),
'trace' => env('LOG_DEPRECATIONS_TRACE', false),
],
 
'channels' => [
// ...
]

O, también puedes definir un canal de registro llamado deprecations. Si existe un canal de registro con este nombre, siempre se utilizará para registrar deprecaciones:

'channels' => [
'deprecations' => [
'driver' => 'single',
'path' => storage_path('logs/php-deprecation-warnings.log'),
],
],

Construyendo Pilas de Registros

Como se mencionó anteriormente, el driver stack te permite combinar múltiples canales en un solo canal de registro para mayor comodidad. Para ilustrar cómo usar pilas de registros, echemos un vistazo a una configuración de ejemplo que podrías ver en una aplicación de producción:

'channels' => [
'stack' => [
'driver' => 'stack',
'channels' => ['syslog', 'slack'],
'ignore_exceptions' => false,
],
 
'syslog' => [
'driver' => 'syslog',
'level' => env('LOG_LEVEL', 'debug'),
'facility' => env('LOG_SYSLOG_FACILITY', LOG_USER),
'replace_placeholders' => true,
],
 
'slack' => [
'driver' => 'slack',
'url' => env('LOG_SLACK_WEBHOOK_URL'),
'username' => env('LOG_SLACK_USERNAME', 'Laravel Log'),
'emoji' => env('LOG_SLACK_EMOJI', ':boom:'),
'level' => env('LOG_LEVEL', 'critical'),
'replace_placeholders' => true,
],
],

Vamos a desglosar esta configuración. Primero, nota que nuestro canal de stack agrega dos canales adicionales a través de su opción channels: syslog y slack. Así que, al registrar mensajes, ambos canales tendrán la oportunidad de registrar el mensaje. Sin embargo, como veremos a continuación, si estos canales registran realmente el mensaje puede ser determinado por la severidad / "nivel" del mensaje.

Niveles de Registro

Toma nota de la opción de configuración level presente en las configuraciones de canal syslog y slack en el ejemplo anterior. Esta opción determina el "nivel" mínimo que debe tener un mensaje para ser registrado por el canal. Monolog, que potencia los servicios de registro de Laravel, ofrece todos los niveles de registro definidos en la Especificación RFC 5424. En orden descendente de gravedad, estos niveles de registro son: emergencia, alerta, crítico, error, advertencia, notificación, info y debug. Así que, imagina que registramos un mensaje utilizando el método debug:

Log::debug('An informational message.');

Dada nuestra configuración, el canal syslog escribirá el mensaje en el registro del sistema; sin embargo, dado que el mensaje de error no es crítico o superior, no se enviará a Slack. Sin embargo, si registramos un mensaje de emergencia, se enviará tanto al registro del sistema como a Slack, ya que el nivel emergencia está por encima de nuestro umbral de nivel mínimo para ambos canales:

Log::emergency('The system is down!');

Escribiendo Mensajes de Registro

Puedes escribir información en los registros utilizando la Log facade. Como se mencionó anteriormente, el logger proporciona los ocho niveles de registro definidos en la especificación RFC 5424: emergencia, alerta, crítico, error, advertencia, noticia, info y depuración:

use Illuminate\Support\Facades\Log;
 
Log::emergency($message);
Log::alert($message);
Log::critical($message);
Log::error($message);
Log::warning($message);
Log::notice($message);
Log::info($message);
Log::debug($message);

Puedes llamar a cualquiera de estos métodos para registrar un mensaje para el nivel correspondiente. Por defecto, el mensaje se escribirá en el canal de registro predeterminado según lo configurado en tu archivo de configuración logging:

<?php
 
namespace App\Http\Controllers;
 
use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
 
class UserController extends Controller
{
/**
* Show the profile for the given user.
*/
public function show(string $id): View
{
Log::info('Showing the user profile for user: {id}', ['id' => $id]);
 
return view('user.profile', [
'user' => User::findOrFail($id)
]);
}
}

Información Contextual

Se puede pasar un array de datos contextuales a los métodos de registro. Estos datos contextuales se formatearán y mostrarán junto con el mensaje de registro:

use Illuminate\Support\Facades\Log;
 
Log::info('User {id} failed to login.', ['id' => $user->id]);

Ocasionalmente, es posible que desees especificar alguna información contextual que deba incluirse con todas las entradas de registro posteriores en un canal particular. Por ejemplo, es posible que desees registrar un ID de solicitud que esté asociado con cada solicitud entrante a tu aplicación. Para lograr esto, puedes llamar al método withContext de la fachada Log:

<?php
 
namespace App\Http\Middleware;
 
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Symfony\Component\HttpFoundation\Response;
 
class AssignRequestId
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
$requestId = (string) Str::uuid();
 
Log::withContext([
'request-id' => $requestId
]);
 
$response = $next($request);
 
$response->headers->set('Request-Id', $requestId);
 
return $response;
}
}

Si deseas compartir información contextual a través de todos los canales de registro, puedes invocar el método Log::shareContext(). Este método proporcionará la información contextual a todos los canales creados y a cualquier canal que se cree posteriormente:

<?php
 
namespace App\Http\Middleware;
 
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Symfony\Component\HttpFoundation\Response;
 
class AssignRequestId
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
$requestId = (string) Str::uuid();
 
Log::shareContext([
'request-id' => $requestId
]);
 
// ...
}
}

[!NOTA] Si necesitas compartir el contexto de registro mientras procesas trabajos en cola, puedes utilizar middleware de trabajo.

Escribir a Canales Específicos

A veces es posible que desees registrar un mensaje en un canal diferente al canal predeterminado de tu aplicación. Puedes usar el método channel en la fachada Log para recuperar y registrar en cualquier canal definido en tu archivo de configuración:

use Illuminate\Support\Facades\Log;
 
Log::channel('slack')->info('Something happened!');

Si deseas crear un stack de registro bajo demanda que consista en múltiples canales, puedes usar el método stack:

Log::stack(['single', 'slack'])->info('Something happened!');

Canales Bajo Demanda

También es posible crear un canal bajo demanda proporcionando la configuración en tiempo de ejecución sin que esa configuración esté presente en el archivo de configuración logging de tu aplicación. Para lograr esto, puedes pasar un array de configuración al método build de la fachada Log:

use Illuminate\Support\Facades\Log;
 
Log::build([
'driver' => 'single',
'path' => storage_path('logs/custom.log'),
])->info('Something happened!');

También es posible que desees incluir un canal bajo demanda en una pila de registro bajo demanda. Esto se puede lograr incluyendo tu instancia de canal bajo demanda en el array pasado al método stack:

use Illuminate\Support\Facades\Log;
 
$channel = Log::build([
'driver' => 'single',
'path' => storage_path('logs/custom.log'),
]);
 
Log::stack(['slack', $channel])->info('Something happened!');

Personalización del Canal Monolog

Personalizando Monolog para Canales

A veces es posible que necesites tener control total sobre cómo se configura Monolog para un canal existente. Por ejemplo, es posible que desees configurar una implementación personalizada de FormatterInterface de Monolog para el canal single incorporado de Laravel. Para comenzar, define un array tap en la configuración del canal. El array tap debe contener una lista de clases que deben tener la oportunidad de personalizar (o "interactuar" con) la instancia de Monolog después de que se haya creado. No hay una ubicación convencional donde se deban colocar estas clases, así que puedes crear un directorio dentro de tu aplicación para contener estas clases:

'single' => [
'driver' => 'single',
'tap' => [App\Logging\CustomizeFormatter::class],
'path' => storage_path('logs/laravel.log'),
'level' => env('LOG_LEVEL', 'debug'),
'replace_placeholders' => true,
],

Una vez que hayas configurado la opción tap en tu canal, estás listo para definir la clase que personalizará tu instancia de Monolog. Esta clase solo necesita un método: __invoke, que recibe una instancia de Illuminate\Log\Logger. La instancia de Illuminate\Log\Logger hace proxy a todas las llamadas a métodos en la instancia subyacente de Monolog:

<?php
 
namespace App\Logging;
 
use Illuminate\Log\Logger;
use Monolog\Formatter\LineFormatter;
 
class CustomizeFormatter
{
/**
* Customize the given logger instance.
*/
public function __invoke(Logger $logger): void
{
foreach ($logger->getHandlers() as $handler) {
$handler->setFormatter(new LineFormatter(
'[%datetime%] %channel%.%level_name%: %message% %context% %extra%'
));
}
}
}

[!NOTA] Todas tus clases "tap" son resolvidas por el contenedor de servicios, así que cualquier dependencia de constructor que requieran será inyectada automáticamente.

Creando Canales de Controladores Monolog

Monolog tiene una variedad de manejadores disponibles y Laravel no incluye un canal incorporado para cada uno. En algunos casos, es posible que desees crear un canal personalizado que sea simplemente una instancia de un manejador Monolog específico que no tenga un driver de registro correspondiente en Laravel. Estos canales se pueden crear fácilmente utilizando el driver monolog. Al usar el driver monolog, la opción de configuración handler se utiliza para especificar qué controlador se instanciará. Opcionalmente, se pueden especificar los parámetros del constructor que necesita el controlador utilizando la opción de configuración with:

'logentries' => [
'driver' => 'monolog',
'handler' => Monolog\Handler\SyslogUdpHandler::class,
'with' => [
'host' => 'my.logentries.internal.datahubhost.company.com',
'port' => '10000',
],
],

Formateadores de Monolog

Al utilizar el driver monolog, se usará el LineFormatter de Monolog como el formateador predeterminado. Sin embargo, puedes personalizar el tipo de formateador que se pasa al controlador utilizando las opciones de configuración formatter y formatter_with:

'browser' => [
'driver' => 'monolog',
'handler' => Monolog\Handler\BrowserConsoleHandler::class,
'formatter' => Monolog\Formatter\HtmlFormatter::class,
'formatter_with' => [
'dateFormat' => 'Y-m-d',
],
],

Si estás utilizando un manejador de Monolog que es capaz de proporcionar su propio formateador, puedes establecer el valor de la opción de configuración formatter en default:

'newrelic' => [
'driver' => 'monolog',
'handler' => Monolog\Handler\NewRelicHandler::class,
'formatter' => 'default',
],

Procesadores de Monolog

Monolog también puede procesar mensajes antes de registrarlos. Puedes crear tus propios procesadores o usar los procesadores existentes ofrecidos por Monolog. Si deseas personalizar los procesadores para un driver monolog, añade un valor de configuración processors a la configuración de tu canal:

'memory' => [
'driver' => 'monolog',
'handler' => Monolog\Handler\StreamHandler::class,
'with' => [
'stream' => 'php://stderr',
],
'processors' => [
// Simple syntax...
Monolog\Processor\MemoryUsageProcessor::class,
 
// With options...
[
'processor' => Monolog\Processor\PsrLogMessageProcessor::class,
'with' => ['removeUsedContextFields' => true],
],
],
],

Creando Canales Personalizados a través de Factories

Si deseas definir un canal completamente personalizado en el que tengas control total sobre la instanciación y configuración de Monolog, puedes especificar un tipo de driver custom en tu archivo de configuración config/logging.php. Tu configuración debe incluir una opción via que contenga el nombre de la clase factory que se invocará para crear la instancia de Monolog:

'channels' => [
'example-custom-channel' => [
'driver' => 'custom',
'via' => App\Logging\CreateCustomLogger::class,
],
],

Una vez que hayas configurado el canal del driver custom, estás listo para definir la clase que creará tu instancia de Monolog. Esta clase solo necesita un único método __invoke que debe devolver la instancia del registrador de Monolog. El método recibirá el array de configuración de los canales como su único argumento:

<?php
 
namespace App\Logging;
 
use Monolog\Logger;
 
class CreateCustomLogger
{
/**
* Create a custom Monolog instance.
*/
public function __invoke(array $config): Logger
{
return new Logger(/* ... */);
}
}

Seguimiento de Mensajes de Registro Usando Pail

A menudo es posible que necesites seguir los registros de tu aplicación en tiempo real. Por ejemplo, al depurar un problema o al monitorear los registros de tu aplicación en busca de tipos específicos de errores. Laravel Pail es un paquete que te permite explorar fácilmente los archivos de registro de tu aplicación Laravel directamente desde la línea de comandos. A diferencia del comando tail estándar, Pail está diseñado para trabajar con cualquier driver de registro, incluyendo Sentry o Flare. Además, Pail ofrece un conjunto de filtros útiles para ayudarte a encontrar rápidamente lo que estás buscando.

Instalación

[!WARNING] Laravel Pail requiere PHP 8.2+ y la extensión PCNTL. Para comenzar, instala Pail en tu proyecto utilizando el gestor de paquetes Composer:

composer require laravel/pail

Uso

Para comenzar a seguir los registros, ejecuta el comando pail:

php artisan pail

Para aumentar la verbosidad de la salida y evitar la truncación (…), utiliza la opción -v:

php artisan pail -v

Para obtener la máxima verbosidad y mostrar rastros de pila de excepciones, utiliza la opción -vv:

php artisan pail -vv

Para dejar de seguir los registros, presiona Ctrl+C en cualquier momento.

Filtrando Registros

--filter

Puedes usar la opción --filter para filtrar registros por su tipo, archivo, mensaje y contenido de la traza de pila:

php artisan pail --filter="QueryException"

--message

Para filtrar logs solo por su mensaje, puedes usar la opción --message:

php artisan pail --message="User created"

--level

La opción --level se puede utilizar para filtrar registros por su nivel de registro:

php artisan pail --level=error

--user

Para mostrar solo los registros que se escribieron mientras un usuario dado estaba autenticado, puedes proporcionar la ID del usuario a la opción --user:

php artisan pail --user=1