Laravel: Escribiendo un Driver Personalizado para logs en Bases de Datos
En uno de los proyectos recientes para crear un sistema CRM, necesité hacer que los logs fueran más simples para los usuarios no tech, y además, añadir búsqueda y filtros preestablecidos.
Claro, se puede lograr un comportamiento similar simplemente leyendo el archivo de logs, pero ¿para qué complicarse, especialmente cuando el archivo es muy grande y la lectura del disco consume demasiados recursos del servidor? Por supuesto, decidí transferir esta carga a PostgreSQL.
Creación del Driver
El mecanismo de logs integrado en Laravel utiliza Monolog. Nos enfocaremos en una extensión basada en él en esta nota.
Para crear un nuevo driver de logs, simplemente creamos una nueva instancia de Monolog Logger y establecemos un manejador en él.
namespace App\Services;
use Monolog\Logger;
class DatabaseLogger
{
public function __invoke(array $config)
{
return new Logger('Database', [
new DatabaseHandler(),
]);
}
}
En el manejador, creamos un nuevo mensaje que, de hecho, es un modelo Eloquent estándar. Ahora tienes campos con los que puedes realizar búsquedas, agrupaciones y otras utilidades para tu usuario.
namespace App\Services;
use Monolog\Handler\AbstractProcessingHandler;
use App\Models\LogMessage;
class DatabaseHandler extends AbstractProcessingHandler
{
protected function write(array $record): void
{
LogMessage::create([
'level' => $record['level'],
'level_name' => $record['level_name'],
'message' => $record['message'],
'logged_at' => $record['datetime'],
'context' => $record['context'],
'extra' => $record['extra'],
]);
}
}
Conexión del Driver
Para conectar el driver que acabamos de crear, añade un nuevo canal en config/logging.php y listo, tu driver personalizado está listo para usarse.
use App\Services\DatabaseLogger;
return [
'channels' => [
'db' => [
'driver' => 'custom',
'via' => DatabaseLogger::class,
],
]
]
No olvides crear tu modelo LogMessage y su migración:
php artisan make:model LogMessage -m
Ahora simplemente puedes registrar en este canal de esta manera:
use Illuminate\Support\Facades\Log;
Log::channel('db')->info('Tu mensaje');
Entre los beneficios no tan obvios, puedes convertir el cuerpo del mensaje en JSON, lo que hara la búsqueda en los logs aún más cómoda e util.