Signatur
Beschreibung
Das Interface MongoDB\Driver\Monitoring\Subscriber ist das grundlegende Marker-Interface des MongoDB-PHP-Treibers für das Command-Monitoring-System. Es definiert selbst keine Methoden, sondern dient als gemeinsame Basis für spezialisierte Abonnenten-Interfaces wie CommandSubscriber, SDAMSubscriber oder ServerMonitoringSubscriber.
Um auf bestimmte Treiberereignisse (z. B. ausgeführte Befehle, Topologie-Änderungen oder Heartbeat-Ereignisse) reagieren zu können, muss eine Klasse das entsprechende spezialisierte Interface implementieren, welches seinerseits Subscriber erweitert. Anschließend wird die Abonnenten-Instanz über MongoDB\Driver\Monitoring\addSubscriber() global oder über MongoDB\Driver\Manager::addSubscriber() pro Verbindung registriert.
Typische Anwendungsfälle sind das Loggen von Datenbankabfragen, das Messen von Ausführungszeiten, das Debugging von Treiberkommunikation oder das Einbinden in APM-Tools (Application Performance Monitoring). Da das Interface selbst keine Methoden vorschreibt, kann eine Klasse mehrere spezialisierte Subscriber-Interfaces gleichzeitig implementieren und so auf verschiedene Ereignistypen reagieren.
Direkte Instanzen von Subscriber ohne eines der spezialisierten Interfaces können zwar registriert werden, empfangen jedoch keine Ereignisse – erst durch die Implementierung der spezifischen Interfaces werden die entsprechenden Callback-Methoden aufgerufen.
Beispiele
Einfacher Command-Subscriber zur Abfrageprotokollierung
<?php
use MongoDB\Driver\Monitoring\CommandSubscriber;
use MongoDB\Driver\Monitoring\CommandStartedEvent;
use MongoDB\Driver\Monitoring\CommandSucceededEvent;
use MongoDB\Driver\Monitoring\CommandFailedEvent;
use MongoDB\Driver\Monitoring\addSubscriber;
class QueryLogger implements CommandSubscriber
{
public function commandStarted(CommandStartedEvent $event): void
{
echo sprintf(
"[START] Befehl '%s' auf DB '%s' (RequestId: %d)\n",
$event->getCommandName(),
$event->getDatabaseName(),
$event->getRequestId()
);
}
public function commandSucceeded(CommandSucceededEvent $event): void
{
echo sprintf(
"[OK] Befehl '%s' in %.3f ms abgeschlossen\n",
$event->getCommandName(),
$event->getDurationMicros() / 1000
);
}
public function commandFailed(CommandFailedEvent $event): void
{
echo sprintf(
"[FAIL] Befehl '%s' fehlgeschlagen: %s\n",
$event->getCommandName(),
$event->getError()->getMessage()
);
}
}
// Subscriber global registrieren
\MongoDB\Driver\Monitoring\addSubscriber(new QueryLogger());
$manager = new \MongoDB\Driver\Manager('mongodb://127.0.0.1/');
$query = new \MongoDB\Driver\Query(['status' => 'aktiv']);
$cursor = $manager->executeQuery('mydb.users', $query);
Mehrere Subscriber-Interfaces kombinieren
<?php
use MongoDB\Driver\Monitoring\CommandSubscriber;
use MongoDB\Driver\Monitoring\SDAMSubscriber;
use MongoDB\Driver\Monitoring\CommandStartedEvent;
use MongoDB\Driver\Monitoring\CommandSucceededEvent;
use MongoDB\Driver\Monitoring\CommandFailedEvent;
use MongoDB\Driver\Monitoring\ServerOpeningEvent;
use MongoDB\Driver\Monitoring\ServerClosedEvent;
use MongoDB\Driver\Monitoring\ServerDescriptionChangedEvent;
use MongoDB\Driver\Monitoring\TopologyOpeningEvent;
use MongoDB\Driver\Monitoring\TopologyClosedEvent;
use MongoDB\Driver\Monitoring\TopologyDescriptionChangedEvent;
use MongoDB\Driver\Monitoring\ServerHeartbeatStartedEvent;
use MongoDB\Driver\Monitoring\ServerHeartbeatSucceededEvent;
use MongoDB\Driver\Monitoring\ServerHeartbeatFailedEvent;
/**
* Diese Klasse implementiert sowohl CommandSubscriber als auch SDAMSubscriber
* und ist damit ein gültiger Subscriber (erbt beide "extends Subscriber"-Ketten).
*/
class UniversalMonitor implements CommandSubscriber, SDAMSubscriber
{
// --- CommandSubscriber ---
public function commandStarted(CommandStartedEvent $event): void
{
echo "CMD gestartet: " . $event->getCommandName() . "\n";
}
public function commandSucceeded(CommandSucceededEvent $event): void {}
public function commandFailed(CommandFailedEvent $event): void {}
// --- SDAMSubscriber ---
public function serverOpening(ServerOpeningEvent $event): void
{
echo "Server verbunden: " . $event->getHost() . ":" . $event->getPort() . "\n";
}
public function serverClosed(ServerClosedEvent $event): void {}
public function serverDescriptionChanged(ServerDescriptionChangedEvent $event): void {}
public function topologyOpening(TopologyOpeningEvent $event): void {}
public function topologyClosed(TopologyClosedEvent $event): void {}
public function topologyDescriptionChanged(TopologyDescriptionChangedEvent $event): void {}
public function serverHeartbeatStarted(ServerHeartbeatStartedEvent $event): void {}
public function serverHeartbeatSucceeded(ServerHeartbeatSucceededEvent $event): void {}
public function serverHeartbeatFailed(ServerHeartbeatFailedEvent $event): void {}
}
$monitor = new UniversalMonitor();
\MongoDB\Driver\Monitoring\addSubscriber($monitor);
$manager = new \MongoDB\Driver\Manager('mongodb://127.0.0.1/');
echo "Monitor registriert.\n";
// Wichtig · Fallstricke
Marker-Interface ohne eigene Methoden: Subscriber selbst schreibt keine Methoden vor. Wer ausschließlich dieses Interface implementiert (ohne ein spezialisiertes Sub-Interface), kann zwar registriert werden, erhält aber keinerlei Ereignisbenachrichtigungen.
Gültigkeitsbereich der Registrierung: Mit MongoDB\Driver\Monitoring\addSubscriber() wird der Abonnent global für alle Manager-Instanzen registriert. Für eine isolierte Überwachung einzelner Verbindungen sollte stattdessen MongoDB\Driver\Manager::addSubscriber() verwendet werden, um unerwünschte Seiteneffekte in größeren Anwendungen zu vermeiden.
Performance-Hinweis: Jeder registrierte Subscriber erhält synchron Ereignisse und blockiert dabei den Treiber. Aufwändige Operationen (z. B. Netzwerkaufrufe, synchrones Schreiben in Datenbanken) innerhalb der Callback-Methoden können die Latenz von MongoDB-Operationen spürbar erhöhen. Für Produktivumgebungen empfiehlt sich asynchrones Puffern der Ereignisse.