У Laravel 11+ обробник винятків налаштовується не в класі Handler, а в bootstrap/app.php через withExceptions:
use Illuminate\Foundation\Configuration\Exceptions;
use Psr\Log\LogLevel;
->withExceptions(function (Exceptions $exceptions): void {
// власне звітування для конкретного типу
$exceptions->report(function (InvalidOrderException $e) {
Notification::route('slack', config('services.slack.ops'))->notify(new OrderAlert($e));
});
// не звітувати зовсім
$exceptions->dontReport([
CardDeclinedException::class,
]);
// інший рівень логування для типу
$exceptions->level(PDOException::class, LogLevel::CRITICAL);
// додатковий контекст до кожного звіту
$exceptions->context(fn () => [
'tenant_id' => tenant()?->id,
]);
})
Важлива деталь report(): колбек виконується на додачу до стандартного логування. Щоб стандартне звітування не відбувалося, колбек має повернути false або ланцюжок має закінчуватися ->stop():
$exceptions->report(function (InvalidOrderException $e) {
// ...
})->stop();
Тип винятку визначається з type hint параметра колбека - окремо вказувати клас не потрібно.
Інші способи не звітувати:
- інтерфейс
ShouldntReportна класі винятку - позначка прямо в класі; dontReportWhen(fn (Throwable $e) => ...)- умова за вмістом винятку;dontReportDuplicates()- той самий екземпляр винятку, переданий уreport()кілька разів, звітується лише раз.
Контекст на рівні винятку: метод context() у самому класі винятку додає його дані до запису в логу:
class InvalidOrderException extends Exception
{
public function __construct(private int $orderId) { parent::__construct('Invalid order'); }
public function context(): array
{
return ['order_id' => $this->orderId];
}
}
Laravel 13: dontRetry - список винятків, при яких завдання в черзі не повторюється, навіть якщо спроби ще лишилися. Наприклад, видалений клієнт у стороннього API: повтор нічого не змінить.
Практика: тримати в dontReport лише очікувані бізнес-ситуації. Помилка, яку ніхто не бачить, - це баг, про який ніхто не знає.