diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 0a8d32e..d20003e 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -70,12 +70,16 @@ class AppServiceProvider extends ServiceProvider } /** - * Overwrite last-sql.json before each query so an OOM still leaves the dying SQL. + * Keep the current process's last SQL in memory. On memory-exhaustion + * shutdown, append it to oom-sql.log (shared last-sql.json is useless + * under many FPM workers). */ private function recordLastSql(): void { - $path = storage_path('logs/last-sql.json'); - DB::beforeExecuting(function (string $query, array $bindings) use ($path): void { + $oomPath = storage_path('logs/oom-sql.log'); + $snap = (object) ['line' => '']; + + DB::beforeExecuting(function (string $query, array $bindings) use ($snap): void { $uri = 'cli'; try { if (app()->runningInConsole()) { @@ -86,26 +90,41 @@ class AppServiceProvider extends ServiceProvider } } catch (\Throwable) { } - @file_put_contents($path, json_encode([ + $snap->line = json_encode([ 'at' => date('c'), + 'pid' => getmypid(), 'mem' => memory_get_usage(true), 'uri' => $uri, - 'sql' => substr($query, 0, 2000), - 'bindings' => array_slice($bindings, 0, 12), - ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); + 'sql' => substr($query, 0, 1500), + 'bindings' => array_slice($bindings, 0, 8), + ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?: ''; }); - DB::listen(function ($event) use ($path): void { - if ($event->time < 500 && memory_get_usage(true) < 64 * 1024 * 1024) { + register_shutdown_function(function () use ($oomPath, $snap): void { + $err = error_get_last(); + $msg = (string) ($err['message'] ?? ''); + if ($msg === '' || ! str_contains($msg, 'Allowed memory size')) { + return; + } + $line = $snap->line !== '' ? $snap->line : json_encode([ + 'at' => date('c'), + 'pid' => getmypid(), + 'mem' => memory_get_usage(true), + 'uri' => 'unknown', + 'sql' => '', + 'error' => substr($msg, 0, 240), + ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); + @file_put_contents($oomPath, $line."\n", FILE_APPEND | LOCK_EX); + }); + + DB::listen(function ($event): void { + if ($event->time < 800 && memory_get_usage(true) < 80 * 1024 * 1024) { return; } - $raw = @file_get_contents($path); - $last = is_string($raw) ? json_decode($raw, true) : null; Log::warning('slow_or_heavy_query', [ 'ms' => $event->time, 'mem' => memory_get_usage(true), - 'uri' => is_array($last) ? ($last['uri'] ?? '') : '', - 'sql' => substr((string) $event->sql, 0, 500), + 'sql' => substr((string) $event->sql, 0, 400), ]); }); }