Laravel-Exceptions als Push aufs Handy
Laravel meldet Exceptions schon selbst: ins Log und, mit einem Log-Kanal wie Slack, in einen Chat. Ärgerlich wird es, wenn dieselbe Exception 300-mal in einer Minute auftritt. Du willst einmal davon erfahren, mit genug Details zum Handeln, und dann Ruhe haben, bis etwas Neues kaputtgeht.
Diese Anleitung richtet das mit dem Paket honk-me/honk-me und Laravel 13 ein. Exceptions werden zu Pushes, Wiederholungen desselben Fehlers landen in einer Gruppe, und geplante Tasks melden, wenn sie fehlschlagen und wenn sie wieder laufen.
Voraussetzungen
- Laravel 13 auf PHP 8.3 oder neuer.
- Ein Honk-Konto (vorerst nur auf Einladung: Zugang anfragen) und ein Projekt mit Ingest-Schlüssel: Öffne in der Web-App das Projekt, dann Schlüssel.
1. Das Paket installieren
composer require honk-me/honk-me
# publishes config/honk.php and adds HONK_URL and HONK_KEY to .env.example
php artisan honk:installTrag Server-URL und Schlüssel in .env ein. Committe den Schlüssel nie, in .env.example gehören nur leere Platzhalter.
HONK_URL=https://honk-me.app
HONK_KEY=honk_xxxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxDann prüfst du die Verbindung. honk:test sendet ein Leichtes Hupen und gibt die ID der Nachricht aus:
php artisan honk:test # sends a light honk and prints the message id
php artisan about --only=honk # URL, key prefix (never the secret), queue, Context metadata2. Exceptions melden
Eine Zeile in bootstrap/app.php:
// bootstrap/app.php
use HonkMe\Laravel\Facades\Honk;
->withExceptions(function (Exceptions $exceptions): void {
$exceptions->report(Honk::reportable());
})Ab jetzt wird jede gemeldete Exception als Langes Hupen gesendet, und zwar als Problem. Drei Details sorgen für Ruhe:
- Eine Gruppe pro Stelle im Code. Der Gruppenschlüssel ist
exceptions/<Class>@<file>:<line>. 300 identische Exceptions sind also ein Vorfall mit Zähler, eine andere Exception ist ein anderer Vorfall. - Höchstens ein Hupen pro Gruppe alle 5 Minuten. Die Drosselung läuft über deinen Cache, die 299 Wiederholungen verlassen deinen Server also gar nicht erst.
- Gesendet nach der Antwort. Der Standardmodus
defersendet erst, wenn die HTTP-Antwort raus ist. Ein langsames Netzwerk bremst also nie eine Seite aus.
Fehlt HONK_URL oder HONK_KEY, passiert nichts. So bleiben lokale Entwicklung und CI still. Eine Exception wirft das Paket nie.
Pro App kannst du eine andere Stufe oder ein anderes Zeitfenster wählen, zum Beispiel Dauerhupen mit einer Minute Drosselung für einen Zahlungsdienst:
$exceptions->report(Honk::reportable(severity: 'blast', throttleSeconds: 60));Alles Weitere steht in config/honk.php. Dort überspringst du erwartbare Exceptions, etwa eine abgelehnte Zahlung, die die Oberfläche schon erklärt, und legst fest, wie gesendet wird:
// config/honk.php (published by php artisan honk:install)
'exceptions' => [
'enabled' => (bool) env('HONK_EXCEPTIONS', true),
'severity' => 'long',
'channel' => 'exceptions',
'throttle' => 300, // seconds per group
'mode' => 'defer', // defer (after the response), sync or queue
'ignore' => [
\App\Exceptions\PaymentDeclined::class, // expected, already handled in the UI
],
],Exception-Meldungen werden unverändert gesendet und bei Bedarf gekürzt. Schreib keine personenbezogenen Daten hinein, sonst landen sie in einem Push.
3. Sofort, nach der Antwort oder über die Queue
Dieselbe Wahl hast du für alles, was du selbst sendest:
use HonkMe\Laravel\Facades\Honk;
use HonkMe\Message;
Honk::defer()->beep('New order', "{$order->email} paid {$order->total} €"); // after the response
Honk::queue(Message::make('Imported 1 204 rows')->beep()->channel('imports')); // a queued job
Honk::loud('Disk 91%', '/var on app-01', ['groupKey' => 'disk/app-01/var']); // right nowHonk::defer()läuft in diesem Prozess nach der Antwort. Ein Worker ist nicht nötig. Stirbt der Prozess vorher, geht dieses Hupen verloren. Für die meisten Alarme ist das in Ordnung.Honk::queue()läuft in einem Queue-Worker mit Wiederholungen und Backoff und übersteht Neustarts. Nimm es für alles, was ankommen muss.- Die einfachen Helfer senden sofort, mit Wiederholungen. Das passt zu Commands, Jobs und dem Scheduler.
defer() und queue() prüfen die Nachricht sofort. Ein fehlerhaftes Feld fällt also in deinem Code auf, nicht erst später in einem Worker.
4. Geplante Tasks
// routes/console.php
Schedule::command('backup:run')->daily()->honkOnFailure(); // problem on failure, recovery once it works again
Schedule::command('reports:send')->hourly()->honkOnSuccess(); // a beep after every successful runhonkOnFailure() sendet ein Problem mit dem Exit-Code und dem Ende der Ausgabe, gruppiert pro Task. Beim nächsten erfolgreichen Lauf folgt eine Entwarnung, aber nur nach einem Fehlschlag. Ein Task, der sauber läuft, meldet sich also nie. honkOnSuccess() sendet nach jedem erfolgreichen Lauf ein Tüt-tüt. Das ist für Berichte gedacht, die du wirklich sehen willst.
5. Testen
Honk::fake() zeichnet auf, was gesendet oder in die Queue gestellt würde, und schickt nichts übers Netzwerk. Es validiert wie der echte Client, eine ungültige Nachricht lässt den Test also trotzdem scheitern:
use HonkMe\Laravel\Facades\Honk;
use HonkMe\Message;
use HonkMe\Severity;
Honk::fake();
$this->post(route('quote.store'), $data);
Honk::assertSent(fn (Message $m) => $m->groupKey === 'requests/1' && $m->severity === Severity::Light);
Honk::assertSentTimes(1);
Honk::assertNotSent(fn (Message $m) => $m->severity === Severity::Blast);
Honk::assertQueued(fn (Message $m, string $idempotencyKey) => $m->channel === 'imports');
Honk::assertNothingSent(); // also assertNothingQueued(), assertNothingOutgoing()Was Honk ergänzt
Dein Log bekommt weiterhin jede Exception. Dazu kommt von Honk ein Push pro neuem Fehler, auf iPhone, Apple Watch oder im Browser. Wiederholungen werden mit Zähler gebündelt und landen im selben Posteingang wie deine Cronjobs und Server. Willst du einige davon anders behandeln, ohne den Code anzufassen, reicht eine Regel im Projekt: Schick zum Beispiel exceptions/ aus einer lauten Integration in die Zusammenfassung.
Honk gibt es vorerst nur auf Einladung: Zugang anfragen. Alles in dieser Anleitung funktioniert schon im Free-Tarif.