https://a.storyblok.com/f/270183/1368x665/5912b74ed1/laravel-nightwatch.jpg

Überwachen Sie Ihre Webhooks mit Laravel Nightwatch

Zuletzt aktualisiert am November 26, 2025

Lesedauer: 10 Minuten

Es gibt eine Vielzahl von Möglichkeiten, Ihre Anwendung zu überwachen, und als Entwickler kann das entmutigend sein. Für PHP-Entwickler gibt es die Möglichkeit von Blackfire und Tideways innerhalb des PHP-Bereichs oder externe Cloud-Plattformen wie Datadog, Sentry, Papertrail oder New Relic. Bei den letzten vier Beispielen handelt es sich um Application Performance Monitoring, aber alle sind Drittanbieter, die sich darauf konzentrieren, was ihre Reporting-Agents innerhalb der Cloud tun. Das gibt uns nicht viel Einblick in unseren CodeEs sei denn, Sie haben Ihren Unternehmens- oder Scale-up-Anwendungscode so geschrieben, dass er alles effizient protokolliert.

Ich habe die Einrichtung von Überwachungsagenten wie diesem als besonders mühsam und vielleicht auch ein wenig zu komplex empfunden. Dieser Artikel soll Ihnen zeigen, wie Laravel den Großteil der Komplexität beseitigt hat. Laravel Nightwatch zum Laufen zu bringen, und zwar mit einem Mock-Server-Anfragecode, um es zu testen.

Wenn Sie Webhooks in der Produktion einsetzen, kann leicht etwas schief gehen: Nachrichten schlagen fehl, Nutzdaten ändern sich oder Antworten verlangsamen sich. Als Entwickler greifen wir zu Überwachungs-Tools, um diese Probleme in den Griff zu bekommen, aber die Landschaft kann sich entmutigend anfühlen. Allein in der PHP-Welt gibt es Blackfire und Tideways, und dann die schwergewichtigen APMs wie Datadog, Sentry, Papertrail oder New Relic. Diese Tools sind leistungsstark, aber sie sind Drittanbieter-Agenten, die sich auf Cloud-seitiges Reporting konzentrieren, was uns nicht immer den gewünschten Einblick in das gibt, was unser Laravel-Code tatsächlich tut.

Und wenn wir ehrlich sind, ist die Einrichtung einiger dieser Agenten... mühsam. Sie funktionieren, aber sie fühlen sich oft aus der Not heraus übermäßig komplex an.

Laravel Nightwatch, das dieses Jahr eingeführt wurde, soll das ändern. Es bietet PHP-Entwicklern eine integrierte, Laravel-native Möglichkeit, Anwendungsereignisse und -leistung ohne die üblichen Konfigurationsprobleme zu überwachen. In diesem Tutorial werden wir einen einfachen Webhook-Empfänger mit RCS-Nachrichten von Vonage einrichten, etwas Mock-Traffic durch ihn schicken und beobachten, wie alles im Nightwatch-Dashboard zum Leben erwacht.

Laravel hat uns die meiste Arbeit bei der Überwachung von Anwendungen abgenommen. Mal sehen, wie weit wir mit nur wenigen Schritten kommen.

TLDR; Sie können den Projektcode hier finden.

Voraussetzungen

Einrichten der Laravel-App

Wir bauen eine Überwachungsanwendung, aber wir brauchen etwas zum Überwachen! Zu diesem Zweck werden wir eine Anwendung mit RCS Messaging erstellen. RCS Messaging ist ein neues Protokoll zum Versenden von SMS-ähnlichen Nachrichten, aber mit weit mehr Möglichkeiten. Sie können RCS-Nachrichten über die Vonage Messages API und einer Vonage Applikation senden und empfangen, genau wie SMS. Der Unterschied zwischen RCS und SMS liegt in der Qualität der übertragenen Medien (Audio, Bilder, Video), den größeren Dateigrößen und den interaktiven Elementen wie Antwortvorschlägen, Aktionsvorschlägen, Karten und Karussells.

Wenn ein Endnutzer auf seinem Gerät antwortet, wird eine funktionierende RCS-Anwendung so konfiguriert, dass sie Webhooks an eine bestimmte URL sendet, um die Daten zu verarbeiten.

Die Abkürzung, die wir hier nehmen können, ist, dass wir nicht all diese Konfigurationen vornehmen müssen: Was ich zeigen möchte, ist das konfigurierte Nightwatch Dashboard, das Anwendungsdaten empfängt.

Verwenden Sie das Laravel-Installationsprogramm (das sich um Composers create-project), erstellen Sie eine neue Laravel-Anwendung in Ihrem Terminal:

laravel new tutorials-rcs-webhooks_laravel_nightwatch

Sie können die Gerüstoptionen ignorieren, außer dass es sich wahrscheinlich lohnt, SQLite als Datenbank zu wählen, da es einfach zu starten ist.

Um zu erfahren, wie man mit SQLite anfängt, lesen Sie meinen früheren Artikel "Die Rückkehr von SQLite".

Sobald der Prozess abgeschlossen ist, laden Sie Ihre neue Laravel-Anwendung in die IDE Ihrer Wahl. Sie möchten die Möglichkeit haben, Datensätze in Ihrer Datenbank anzuzeigen. Wenn Sie also etwas wie VSCode verwenden, haben Sie ein SQL-Plugin, oder wenn Sie PHPStorm verwenden, richten Sie die Datenbankquelle ein.

Diese Anwendung wird eine Entität haben, Webhookdie das Modell der eingehenden Daten darstellt. Was sind die eingehenden Daten? Es handelt sich um einen RCS-Webhook von Vonage (oder eine Nachahmung davon). Wenn Sie sich die OpenAPI-Spezifikation ansehen, finden Sie ein Dummy-Beispiel:

{

   "Kanal": "rcs",
   "message_uuid": "aaaaaaaa-bbbb-4ccc-8ddd-0123456789ab",
   "to": "Vonage",
   "from": "447700900001",
   "timestamp": "2025-02-03T12:14:25Z",
   "context_status": "keine",
   "message_type": "text",
   "text": "Text der eingehenden Nachricht".
}

Modelle und Migrationen herstellen

Dazu benötigen wir ein Modell und eine Migration, die Sie mit einem Schlag über die Befehlszeile erstellen können:

php artisan make:model Webhook --migration

Mit dem Schalter --migration Schalter erstellt der Befehl sowohl das Modell als auch die Migration. Die Welt der KI hat die Dinge heutzutage etwas weniger mühsam gemacht, also habe ich, um meinen Migrationscode herauszubekommen, dieses JSON in einen KI-Agenten geworfen und gesagt: "Generiere den Migrationscode für dieses JSON", was er prompt tat (und überraschenderweise ohne Fehler!). Hier ist, was die Migration sieht aus wie:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
   /**
    * Run the migrations.
    */
   public function up(): void
   {
       Schema::create('webhooks', function (Blueprint $table) {
           $table->id();
           $table->string('channel');
           $table->uuid('message_uuid')->unique();
           $table->string('to');
           $table->string('from');
           $table->timestamp('timestamp');
           $table->string('context_status')->nullable();
           $table->string('message_type')->nullable();
           $table->text('text')->nullable();
           $table->timestamps();
       });
   }

   /**
    * Reverse the migrations.
    */

   public function down(): void
   {
       Schema::dropIfExists('webhook_messages');
   }
};

So weit, so gut. Dieses Modell wird von einem Controller hydriert werden, so dass Sie, um dies so schnell wie möglich zu tun, müssen Sie das Modell bearbeiten, um alle Eigenschaften zu machen fillable. Gehen Sie zu Ihrem app\Models\Webhook.php und bearbeite das Modell so, dass es so aussieht:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Webhook extends Model
{
   protected $fillable = [
       'channel',
       'message_uuid',
       'to',
       'from',
       'timestamp',
       'context_status',
       'message_type',
       'text',
   ];

   protected $casts = [
       'timestamp' => 'datetime',
   ];
}

Hervorragend, das Modell kann nun automatisch mit eingehenden Daten befüllt werden (und Sie brauchen die eingehenden Daten nicht zu überprüfen, weil Sie Vonage vertrauen, richtig? Aber im Ernst, in der Produktion, validieren Sie immer Ihre Eingaben).

Erstellen Sie die Route und den Controller

Um die eingehenden Daten zu verarbeiten, benötigen wir eine Route, die an eine Controller-Methode gebunden ist. Sie könnten diese Logik direkt in die web.php Routendatei als Closure schreiben, aber in diesem Tutorial werde ich es ein bisschen traditioneller machen.

php artisan make:controller WebhookController

Ich habe in diesem Controller so wenige Codezeilen wie möglich verwendet, um die Nutzlast zu verarbeiten:

<?php



namespace App\Http\Controllers;



use App\Models\Webhook;

use Illuminate\Http\Request;

class WebhookController extends Controller
{
   public function handle(Request $request)
   {
       $data = $request->all();

       Webhook::create($data);

       return response('Webhook Handled', 200);
   }
}

In unseren Routen müssen wir angeben, dass die Route an die handle() Methode der WebhookController. Die Methode handle() Methode macht nur eine einzige Sache (vielleicht das einzige Mal, dass ich das Prinzip der einzigen Verantwortung befolgt habe!), nämlich den Request Body zu nehmen, ihn in eine Webhook Entität zu verwandeln und sie in der Datenbank zu speichern.

Gehen Sie zu Routes\web.phpund fügen Sie die Route hinzu:

Route::post('/webhook', [WebhookController::class, 'handle']);

Das Senden einer Anfrage an diesen Endpunkt (Sie können es ausprobieren, wenn Sie möchten!) wird derzeit nicht funktionieren. Die Route ist da, der Controller ist da, aber es wird nur eine 419 Antwort geben. Das liegt daran, dass ich ein schlechter Laravel-Entwickler war, aber ich kann Ihnen sagen, wie Sie ein guter Laravel-Entwickler werden. Ich versuche, dies mit so wenig Logik wie möglich zu tun, also habe ich keine API-Boilerplate eingebaut, die da ist, wenn Sie sie wollen. Da sich diese Route in web.phpliegt, ist Laravel so konfiguriert, dass es erwartet, dass es sich um GET und POST Anforderungen, die HTML kompilieren und nicht Echtzeit-API REST JSON. Es gibt also eine HTTP 419, weil es eine Art von Formularanforderung unter einer POST, und diese haben ein Cross-Site Request Forgery-Token enthalten.

Der schnelle und schmutzige Weg, um dies zu umgehen, ist, die Middleware zu hacken (tun Sie dies nie in der Produktion!). Ich dachte, ich würde es einschließen, um ein wenig über das, was zur Laufzeit mit Laravel unter der Haube passiert zu zeigen. Gehen Sie zu Ihrer Framework-Bootstrap-Datei, die sich in bootstrap\app.php.

Diese Datei dient als erster Konfigurationspunkt für Ihre Anwendung, gleich nach dem Einstiegspunkt. Sie können benutzerdefinierte Routing-Dateien, benutzerdefinierte Fehlerhandler auf globaler Ebene und benutzerdefinierte Middleware konfigurieren. In meinen Jahren der Laravel-Entwicklung würde ich sagen, dass es wahrscheinlich eine schlechte Idee ist etwas auf globaler Ebene zu bearbeiten, aber ich bin auch sehr daran interessiert, dass unsere Anfrage abgeschlossen wird.

bootstrap\app.php

use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;

return Application::configure(basePath: dirname(__DIR__))
   ->withRouting(
       web: DIR.'/../routes/web.php',
       commands: DIR.'/../routes/console.php',
       health: '/up',
   )
   ->withMiddleware(function (Middleware $middleware): void {
       $middleware->validateCsrfTokens(except: [
           '/webhook',
       ]);
   })

   ->withExceptions(function (Exceptions $exceptions): void {
       //
   })->create();

Sie können sehen, dass withMiddleware() die spezielle Methode validateCsrfTokens() um jegliche Cross-Site-Forgery zu verhindern. Praktisch, wenn Sie die Regeln umgehen wollen!

Ein Mock NodeJS Server

In der realen Welt geht es bei der Verwendung von Nighwatch um die Überwachung der Anwendungsleistung, was zwangsläufig bedeutet, dass Sie mit vielen asynchronen Jobs in der Warteschlange, viel Caching, viel Logging und vielen Anfragen zu tun haben werden. Es ist an der Zeit, so zu tun, als ob wir es schaffen, und ich habe den einfachsten Weg gewählt, um ein Dashboard zu zeigen, das sich füllt: Anfragen.

Es gibt nur eine Art von eingehenden Anfragen, und das ist der Webhook. Daher brauchen wir einen Code oder einen Server, um diese Anfragen zu generieren und sie an unsere Anwendung zu senden. Es gibt alle möglichen API-Tools für diese Art von Aufgaben: Prisma, Postman, Insomnia, Wiremock und so weiter. Um eine meiner Philosophien zu zitieren, entschied ich mich für "keep it simple, stupid!". Eine JavaScript-Datei, die in einer Schleife als Server fungiert.

Legen Sie im Stammverzeichnis Ihres Projekts ein Verzeichnis an und benennen Sie es entsprechend:

mkdir mock_server
cd mock_server
npm init -y
touch mock-webhook-server.js

Diese vier Befehle erstellen das Verzeichnis, fügen die Abhängigkeitsverwaltung hinzu und erstellen die Datei, die wir als Server ausführen werden. Es gibt drei Dinge, die wir brauchen, um diese Anfragen in einer Schleife zu senden:

  • Axioszum Senden von AJAX-Anfragen

  • UUID, um eindeutige Dummy-IDs für die Dummy-Webhooks zu erzeugen

  • Fakereine Bibliothek zur Erzeugung von Telefon- und Textdummy-Daten.

Um alles auf einmal zu installieren, geben Sie Folgendes in Ihre Befehlszeile ein:

npm i axios uuid @faker-js/faker

Hier ist der fertige Servercode:

const axios = require('axios');
const { v4: uuidv4 } = require('uuid');
const { faker } = require('@faker-js/faker');
const ERROR_RATE = 0.025;
const ERROR_FIELDS = ['message_uuid', 'from', 'timestamp', 'text'];

function generateWebhookPayload() {

   const payload = {
       channel: "rcs",
       message_uuid: uuidv4(),
       to: "Vonage",
       from: faker.phone.number({ style: 'international' }).replace('+', ''),
       timestamp: new Date().toISOString(),
       context_status: "none",
       message_type: "text",
       text: faker.lorem.text().slice(0, 300)
   };

   if (Math.random() < ERROR_RATE) {
       const fieldToRemove = faker.helpers.arrayElement(ERROR_FIELDS);

       delete payload[fieldToRemove];

       console.warn[WARN] Sending malformed webhook (missing '${fieldToRemove}'));
   }
   return payload;
}

function sendWebhook() {
   const payload = generateWebhookPayload();

   axios.post('http://tutorial-voice-rcs_laravel_nightwatch.test/webhook', payload)
       .then(() => {
           console.log[${new Date().toISOString()}] Sent: ${payload.message_uuid});
       })
       .catch(error => {
           console.error[${new Date().toISOString()}] Error: ${error.message});
       });
}

setInterval(sendWebhook, 200);

console.log("Running Mock Webhook Server");

Entpacken des Server-Codes

Wir haben zwei Konstanten, ERROR_RATE und ERROR_FIELDS. Die erste ist ein Dezimalwert, der die Wahrscheinlichkeit eines Fehlers beim Senden von Anfragen angibt, und die zweite gibt an, welche Felder aus dem gesendeten JSON entfernt werden, die den Fehler verursachen.

generateWebhookPayload() ist die Methode zur Formung der JSON-Nutzlast, die auch entscheidet, ob die Nutzlast gültig ist oder nicht. Schließlich sollte man nie dem Code eines anderen vertrauen, nicht wahr? Dies ist der Punkt wo rufen wir die Hilfsfunktion uuidv4() auf, um die UUID zu generieren, und faker, um einen Dummy-Text zu erzeugen, der bis zu 300 Zeichen lang ist (dies ist willkürlich, RCS-Nachrichten können bis zu 3000 Zeichen lang sein).

Unsere clevere kleine mathematische Zeile if (Math.random() < ERROR_RATE) { errechnet, ob sie eines der erforderlichen Felder entfernen wird. Schließlich ist Nightwatch dazu da, Problempunkte innerhalb Ihrer Anwendung zu visualisieren.

sendWebhook() ist die Methode, die in einer Ereignisschleife aufgerufen wird, um die Nutzdaten zu erzeugen und sie dann an unsere Anwendung zu senden. Dies geschieht direkt unterhalb der Logik der Methode, in setInterval(sendWebhook, 200) // <- set this according to how quick you want to generate dummy data

Sie können es jetzt ausführen, aber denken Sie daran, dass sich Ihre SQLite-Datenbank schnell füllen wird. Es ist Zeit für Nightwatch.

Einrichten der Nachtwache

Das Schöne an Nightwatch ist, dass es kostenlos ist und man damit herumspielen kann. Die kostenlose Version umfasst bis zu 300.000 Anwendungsereignisse, die in der Cloud-Plattform aufgezeichnet werden, also genug, um damit zu spielen.

Gehen Sie auf die Nightwatch-Website und erstellen Sie einen Account und eine Bewerbung. Die vier Schritte sind dort sehr gut dokumentiert. Benennen Sie zunächst Ihre Anwendung und wählen Sie eine für Ihren Standort geeignete Speicherregion.

Screenshot showing user account setup for a Nightwatch applicationSetting up your Nightwatch applicationAls nächstes folgen die Teile, die das Einrichten eines APM wirklich erleichtern. Sie werden angewiesen, Nightwatch zunächst über Composer zu installieren:

composer require laravel/nightwatch

Sie erhalten eine Reihe von Schlüsseln, die Sie in Ihre Umgebungsvariablendatei eintragen müssen (dies sind Dummy-Schlüssel für die Sicherheitsfanatiker da draußen):

Screenshot showing the agent setup promptEverything you need to know to get your agent reportingSchritt drei verhindert, dass Ihr Nightwatch Account innerhalb der ersten Stunde sein Kontingent erreicht: Denken Sie daran, dass Sie hier möglicherweise Millionen von Ereignissen überwachen, daher bietet Nightwatch die Möglichkeit, die Stichprobengröße als Umgebungsvariable zu definieren:

Screenshot showing the agent sample size configurationHow much data do you want?Schließlich starten Sie Nightwatch lokal in Ihrer Konsole, und diese sendet die Abtastrate an die Nightwatch-Server:

Screenshot of the panel showing you how to start the Nightwatch agent from the command lineRun your agent through php artisan, same as everything else

In nur vier Schritten haben Sie ein APM. Führen Sie Ihren Mock Node Webhook Server aus, und schon kommen die Daten:

Screenshot showing a populated Nightwatch dashboard monitoring your appElegant application monitoring is here!Irgendwie habe ich es sogar geschafft, eine bösartige Anforderung zu erstellen, die die CPU-Zeit in Anspruch genommen hat, was Sie als Spitzenwert im Leistungsdiagramm auf der rechten Seite sehen können. Sie erhalten eine Vielzahl von Funktionen, mit denen Sie die Daten Ihrer Anwendung genauer untersuchen können: SQL-Verletzungen, Speicherausnahmen, unvollständige Aufträge, was immer Sie wollen. Da ich nach dem Zufallsprinzip Ausnahmen erzeugte, musste ich nachsehen, wie diese aussahen:

Screenshow showing exceptions rates on the Nightwatch dashboardWatch out for your exception ratesSchön. Es teilt sie auch in behandelte und unbehandelte auf, so dass Sie einen besseren Überblick darüber erhalten, wie defensiv der Code Ihrer Anwendung arbeitet.

Schlussfolgerung

Jedes Jahr scheinen Entwickler einen weiteren Teil des Laravel Application Stacks zu bekommen, der noch nicht abgedeckt wurde, und dies ist keine Ausnahme. Das Besondere an Nightwatch ist, dass Drittanbieter von Application Monitoring- und Performance-Tools nicht auf Laravel zugeschnitten sind, im Gegensatz zu etwas von Laravel selbst. In dieser Hinsicht ist dies für Verbraucher großer Datenmengen (die Verwendung der Vonage Verify, Messages API oder Voice API hat Event-Webhook-Systeme, die große Mengen an Webhooks generieren) ein so einfacher Gewinn, dass es schwer zu ignorieren ist.

Haben Sie eine Frage oder möchten Sie etwas mitteilen? Beteiligen Sie sich am Gespräch auf dem Vonage Community Slackund bleiben Sie auf dem Laufenden mit dem Entwickler-Newsletter, folgen Sie uns auf X (früher Twitter), abonnieren Sie unseren YouTube-Kanal für Video-Tutorials, und folgen Sie der Vonage Entwickler-Seite auf LinkedInein Raum für Entwickler, um zu lernen und sich mit der Community zu vernetzen. Bleiben Sie in Verbindung, teilen Sie Ihre Fortschritte und halten Sie sich über die neuesten Nachrichten, Tipps und Veranstaltungen für Entwickler auf dem Laufenden!

Teilen Sie:

https://a.storyblok.com/f/270183/400x385/12b3020c69/james-seconde.png
James SecondeSenior PHP Entwickler Advocate

Als ausgebildeter Schauspieler mit einer Dissertation in Standup-Comedy bin ich über die Meetup-Szene zur PHP-Entwicklung gekommen. Man findet mich, wenn ich über Technik spreche oder schreibe, oder wenn ich seltsame Platten aus meiner Vinylsammlung spiele oder kaufe.