Como Generar logs que registren las Consultas a base de datos en Laravel

Con este post crearemos un fichero de log por cada día y URL que nos permitirá descubrir problemas como Consultas N+1 y analizar si estamos ejecutando una carga excesiva a la base de datos.

1. Base de Datos의 Creamos el Logger 프로피오 데



Lo podemos dar de alta por ejemplo en app/Services/Database/Logger.php :

<?php declare(strict_types=1);

namespace App\Services\Database;

use DateTime;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Request;

class Logger
{
    /**
     * @var string
     */
    protected static string $file = '';

    /**
     * @return void
     */
    public static function listen(): void
    {
        if (static::$file) {
            return;
        }

        static::load();
        static::write('['.date('Y-m-d H:i:s').'] ['.Request::method().'] '.Request::fullUrl());

        DB::listen(static function ($sql) {
            foreach ($sql->bindings as $i => $binding) {
                if ($binding instanceof DateTime) {
                    $sql->bindings[$i] = $binding->format('Y-m-d H:i:s');
                } elseif (is_string($binding)) {
                    $sql->bindings[$i] = "'${binding}'";
                } elseif (is_bool($binding)) {
                    $sql->bindings[$i] = $binding ? 'true' : 'false';
                }
            }

            static::write(vsprintf(str_replace(['%', '?'], ['%%', '%s'], $sql->sql), $sql->bindings));
        });
    }

    /**
     * @return void
     */
    protected static function load(): void
    {
        static::file();

        if (is_dir($dir = dirname(static::$file)) === false) {
            mkdir($dir, 0755, true);
        }
    }

    /**
     * @return void
     */
    protected static function file(): void
    {
        $file = array_filter(explode('-', preg_replace('/[^a-z0-9]+/i', '-', Request::path())));
        $file = implode('-', array_map(static fn ($value) => substr($value, 0, 20), $file)) ?: '-';

        static::$file = storage_path('logs/query/'.date('Y-m-d').'/'.substr($file, 0, 150).'.log');
    }

    /**
     * @param string $message
     *
     * @return void
     */
    protected static function write(string $message): void
    {
        file_put_contents(static::$file, "\n\n".$message, FILE_APPEND | LOCK_EX);
    }
}


Ahora podemos crear un ServiceProvider que gestione el debug. Lo haremos en app/Providers/Debug.php :

<?php declare(strict_types=1);

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\Services\Database\Logger as LoggerDatabase;

class Debug extends ServiceProvider
{
    /**
     * @return void
     */
    public function boot()
    {
        $this->logging();
    }

    /**
     * @return void
     */
    protected function logging(): void
    {
        $this->loggingDatabase();
    }

    /**
     * @return void
     */
    protected function loggingDatabase(): void
    {
        if (config('logging.channels.database.enabled')) {
            LoggerDatabase::listen();
        }
    }
}


En este mismo ServiceProvider podríamos, por ejemplo, añadir también un log que registre los envíos de correos (esto irá en un nuevo post).

Una vez tengamos el servicio, lo añadimos en config/app.php en el array de providers :

    ...

    'providers' => [
        ...

        /*
         * Application Service Providers...
         */
        App\Providers\Debug::class,
    ],
];


También añadimos su opción de configuración en config/logging.php:

    ...

    'channels' => [
        ...

        'database' => [
            'enabled' => env('LOG_DATABASE', false),
        ],
    ],


Y lo completamos con el valor en .env :

LOG_DATABASE=true


De este modo nos creará en storage/logs/query/ con cada día y dentro un fichero con el slug del path de cada petición.

El codigo completo lo podeis encontrar aquí https://gist.github.com/eusonlito/c0a87467b55165a9585a640f1ba4083e

Y ya sabes, si te ha parecido interesante, comparte!

좋은 웹페이지 즐겨찾기