PHP code example of halilcosdu / laravel-slower

1. Go to this page and download the library: Download halilcosdu/laravel-slower library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

halilcosdu / laravel-slower example snippets


use Illuminate\Support\Facades\Gate;

Gate::define('viewSlower', function ($user = null) {
    return $user?->email === '[email protected]';
});

'dashboard' => [
    'enabled' => env('SLOWER_DASHBOARD_ENABLED', true),
    'path' => env('SLOWER_DASHBOARD_PATH', 'slower'),
    'domain' => env('SLOWER_DASHBOARD_DOMAIN'),
    'middleware' => [
        'web',
        HalilCosdu\Slower\Http\Middleware\Authorize::class,
    ],
    'per_page' => 25,
    'analyze_pending_limit' => 10,
],

// config/slower.php
'ai_payload' => [
    'send_raw_sql' => env('SLOWER_AI_SEND_RAW_SQL', false),
    'send_bindings' => env('SLOWER_AI_SEND_BINDINGS', false),
    'redactor' => App\Support\SlowerRedactor::class,
],

namespace App\Support;

use HalilCosdu\Slower\Contracts\PayloadRedactor;

class SlowerRedactor implements PayloadRedactor
{
    public function redactBindings(array $bindings): array
    {
        return array_map(
            fn ($value) => is_string($value) && str_contains($value, '@') ? '[email]' : $value,
            $bindings,
        );
    }

    public function redactRawSql(string $rawSql): string
    {
        return preg_replace('/\b[\w.+-]+@[\w-]+\.[\w.]+\b/', '[email]', $rawSql);
    }
}

// app/Providers/AppServiceProvider.php
use HalilCosdu\Slower\Events\SlowQueryFirstSeen;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Notification;

public function boot(): void
{
    Event::listen(function (SlowQueryFirstSeen $event) {
        Notification::route('slack', config('services.slack.alerts_webhook'))
            ->notify(new \App\Notifications\NewSlowQuery($event->record));
    });
}

// app/Notifications/NewSlowQuery.php (the interesting part)
public function toSlack(object $notifiable): SlackMessage
{
    $origin = $this->record->origin['action'] ?? $this->record->origin['job'] ?? 'unknown origin';

    return (new SlackMessage)
        ->text(sprintf(
            '🐌 New slow query (%.0f ms) from %s: %s',
            $this->record->time,
            $origin,
            \Illuminate\Support\Str::limit($this->record->sql, 120),
        ));
}

use HalilCosdu\Slower\Http\Middleware\Authorize;
use HalilCosdu\Slower\Models\SlowLog;

return [
    'enabled' => env('SLOWER_ENABLED', true),
    'threshold' => env('SLOWER_THRESHOLD', 10000), // ms
    'ai_service' => env('SLOWER_AI_SERVICE', 'openai'),
    'capture' => [
        'sample_rate' => env('SLOWER_SAMPLE_RATE', 1.0),
        'max_per_execution' => env('SLOWER_MAX_PER_EXECUTION', 50),
        'origin' => [
            'enabled' => env('SLOWER_CAPTURE_ORIGIN', true),
            'user_id' => env('SLOWER_CAPTURE_USER_ID', false),
        ],
    ],
    'resources' => [
        'table_name' => (new SlowLog)->getTable(),
        'model' => SlowLog::class,
    ],
    'dashboard' => [
        'enabled' => env('SLOWER_DASHBOARD_ENABLED', true),
        'path' => env('SLOWER_DASHBOARD_PATH', 'slower'),
        'domain' => env('SLOWER_DASHBOARD_DOMAIN'),
        'middleware' => [
            'web',
            Authorize::class,
        ],
        'per_page' => 25,
        'analyze_pending_limit' => 10,
    ],
    'ai_recommendation' => env('SLOWER_AI_RECOMMENDATION', true),
    // null = analyze synchronously; a queue name = analyze as background jobs
    'analyze_queue' => env('SLOWER_ANALYZE_QUEUE'),
    'ai_payload' => [
        'send_raw_sql' => env('SLOWER_AI_SEND_RAW_SQL', false),
        'send_bindings' => env('SLOWER_AI_SEND_BINDINGS', false),
        'redactor' => null, // class-string implementing Contracts\PayloadRedactor
    ],
    // null → a sensible low-cost default for the selected provider
    'recommendation_model' => env('SLOWER_AI_RECOMMENDATION_MODEL'),
    'recommendation_use_explain' => env('SLOWER_AI_RECOMMENDATION_USE_EXPLAIN', true),
    'ignore_explain_queries' => env('SLOWER_IGNORE_EXPLAIN_QUERIES', true),
    'ignore_insert_queries' => env('SLOWER_IGNORE_INSERT_QUERIES', true),
    'prompt' => env('SLOWER_PROMPT', '...'), // the system prompt sent to the AI
];

use HalilCosdu\Slower\AiServiceDrivers\AiServiceManager;
use HalilCosdu\Slower\AiServiceDrivers\Contracts\AiServiceDriver;

app(AiServiceManager::class)->extend('my-llm', fn () => new class implements AiServiceDriver
{
    public function analyze(string $userMessage): ?string
    {
        // Call your model. Return the recommendation text, or null to retry later.
    }
});

use HalilCosdu\Slower\Commands\AnalyzeQuery;
use HalilCosdu\Slower\Commands\SlowLogCleaner;

protected function schedule(Schedule $schedule): void
{
    $schedule->command(AnalyzeQuery::class)->runInBackground()->daily();
    $schedule->command(SlowLogCleaner::class)->runInBackground()->daily();
}

use HalilCosdu\Slower\Facades\Slower;
use HalilCosdu\Slower\Models\SlowLog;

// Analyze a single captured query — returns the analyzed model.
$record = SlowLog::first();

Slower::analyze($record);

$record->raw_sql;        // select count(*) as aggregate from "product_prices" where ...
$record->recommendation; // the AI's optimization advice (markdown)

use HalilCosdu\Slower\Facades\Slower;
use HalilCosdu\Slower\Models\SlowLog;

// How many queries are still waiting for analysis?
$pending = SlowLog::where('is_analyzed', false)->count();

// Analyze the twenty slowest unanalyzed queries.
SlowLog::query()
    ->where('is_analyzed', false)
    ->orderByDesc('time')
    ->limit(20)
    ->get()
    ->each(fn (SlowLog $log) => Slower::analyze($log));

// The most frequent slow query shapes (what the Grouped view shows).
SlowLog::query()
    ->whereNotNull('fingerprint')
    ->selectRaw('fingerprint, count(*) as occurrences, max(time) as max_time')
    ->groupBy('fingerprint')
    ->orderByDesc('occurrences')
    ->limit(5)
    ->get();

// Where did this one come from?
$record->fingerprint;        // 40-char shape hash, shared by all repeats
$record->origin;             // ['type' => 'http', 'route' => 'orders.index',
                             //  'action' => 'App\...\OrderController@index',
                             //  'frame' => 'app/Http/Controllers/OrderController.php:38']
bash
composer  vendor:publish --tag="slower-migrations"
php artisan migrate
bash
php artisan vendor:publish --tag="slower-config"
bash
php artisan slower:analyze           # analyze every record where is_analyzed=false
php artisan slower:analyze --queue   # ...as unique background jobs instead
php artisan slower:clean 15          # delete records older than 15 days
php artisan slower:fingerprint       # one-time: fingerprint records captured before v3.2
sql
SELECT COUNT(*) AS aggregate
FROM product_prices
WHERE product_id = 1 AND price = 0 AND discount_total > 0;