此擴充功能包含一個事件訂閱者 API,允許應用程式監控與「伺服器探索和監控規範」相關的命令和內部活動。» 伺服器探索和監控規範。本教學課程將示範如何使用 MongoDB\Driver\Monitoring\CommandSubscriber 介面進行命令監控。
MongoDB\Driver\Monitoring\CommandSubscriber 介面定義了三個方法:commandStarted
、commandSucceeded
和 commandFailed
。這三個方法都接受一個 event
參數,其類別會根據對應的事件而有所不同。例如,commandSucceeded
的 $event
參數是一個 MongoDB\Driver\Monitoring\CommandSucceededEvent 物件。
在本教學中,我們將實作一個訂閱器,用於建立所有查詢設定檔及其平均執行時間的列表。
我們先從訂閱器的框架開始
<?php
class QueryTimeCollector implements \MongoDB\Driver\Monitoring\CommandSubscriber
{
public function commandStarted( \MongoDB\Driver\Monitoring\CommandStartedEvent $event ): void
{
}
public function commandSucceeded( \MongoDB\Driver\Monitoring\CommandSucceededEvent $event ): void
{
}
public function commandFailed( \MongoDB\Driver\Monitoring\CommandFailedEvent $event ): void
{
}
}
?>
一旦訂閱器物件被實例化,就需要將其註冊到擴充套件的監控系統中。這可以透過呼叫 MongoDB\Driver\Monitoring\addSubscriber() 或 MongoDB\Driver\Manager::addSubscriber() 分別將訂閱器全域註冊或向特定 Manager 註冊來完成。
<?php
\MongoDB\Driver\Monitoring\addSubscriber( new QueryTimeCollector() );
?>
註冊物件後,剩下的就是實作訂閱器類別中的邏輯。為了關聯組成成功執行指令的兩個事件(commandStarted 和 commandSucceeded),每個事件物件都會公開一個 requestId
欄位。
為了記錄每個查詢形狀的平均時間,我們將首先在 commandStarted 事件中檢查 find
指令。然後,我們會將一個項目新增到以其 requestId
作為索引的 pendingCommands
屬性中,其值代表查詢形狀。
如果我們收到具有相同 requestId
的對應 commandSucceeded 事件,我們會將事件的持續時間(來自 durationMicros
)新增到總時間,並增加操作計數。
如果遇到對應的 commandFailed 事件,我們只需從 pendingCommands
屬性中移除該項目。
<?php
class QueryTimeCollector implements \MongoDB\Driver\Monitoring\CommandSubscriber
{
private $pendingCommands = [];
private $queryShapeStats = [];
/* Creates a query shape out of the filter argument. Right now it only
* takes the top level fields into account */
private function createQueryShape( array $filter )
{
return json_encode( array_keys( $filter ) );
}
public function commandStarted( \MongoDB\Driver\Monitoring\CommandStartedEvent $event ): void
{
if ( 'find' === $event->getCommandName() )
{
$queryShape = $this->createQueryShape( (array) $event->getCommand()->filter );
$this->pendingCommands[$event->getRequestId()] = $queryShape;
}
}
public function commandSucceeded( \MongoDB\Driver\Monitoring\CommandSucceededEvent $event ): void
{
$requestId = $event->getRequestId();
if ( array_key_exists( $requestId, $this->pendingCommands ) )
{
$this->queryShapeStats[$this->pendingCommands[$requestId]]['count']++;
$this->queryShapeStats[$this->pendingCommands[$requestId]]['duration'] += $event->getDurationMicros();
unset( $this->pendingCommands[$requestId] );
}
}
public function commandFailed( \MongoDB\Driver\Monitoring\CommandFailedEvent $event ): void
{
if ( array_key_exists( $event->getRequestId(), $this->pendingCommands ) )
{
unset( $this->pendingCommands[$event->getRequestId()] );
}
}
public function __destruct()
{
foreach( $this->queryShapeStats as $shape => $stats )
{
echo "Shape: ", $shape, " (", $stats['count'], ")\n ",
$stats['duration'] / $stats['count'], "µs\n\n";
}
}
}
$m = new \MongoDB\Driver\Manager( 'mongodb://127.0.0.1:27016' );
/* Add the subscriber */
\MongoDB\Driver\Monitoring\addSubscriber( new QueryTimeCollector() );
/* Do a bunch of queries */
$query = new \MongoDB\Driver\Query( [
'region_slug' => 'scotland-highlands', 'age' => [ '$gte' => 20 ]
] );
$cursor = $m->executeQuery( 'dramio.whisky', $query );
$query = new \MongoDB\Driver\Query( [
'region_slug' => 'scotland-lowlands', 'age' => [ '$gte' => 15 ]
] );
$cursor = $m->executeQuery( 'dramio.whisky', $query );
$query = new \MongoDB\Driver\Query( [ 'region_slug' => 'scotland-lowlands' ] );
$cursor = $m->executeQuery( 'dramio.whisky', $query );
?>