Мониторинг производительности приложения (Application Performance Monitoring или APM) Модуль содержит API подписчика события, который позволяет приложениям отслеживать команды и внутреннюю активность, которая относится к «Спецификации обнаружения и мониторинга серверов». В этом руководстве будет продемонстрирован мониторинг команд с помощью интерфейса MongoDB\Driver\Monitoring\CommandSubscriber. Интерфейс MongoDB\Driver\Monitoring\CommandSubscriber определяет три метода: commandStarted, commandSucceeded и commandFailed. Каждый из них принимает один параметр event класса, соответствующего нужному событию. К примеру, commandSucceeded принимает аргумент $event класса MongoDB\Driver\Monitoring\CommandSucceededEvent. В данном руководстве вы реализуем подписчика, который создаёт список профилировок всех запросов и среднего времени их исполнения.
Класс подписчик Scaffolding Мы начнём с шаблона для нашего подписчика: ]]>
Регистрация подписчика Как только объект подписчика создан, необходимо его зарегистрировать в системе мониторинга модуля. Регистрация производится методом MongoDB\Driver\Monitoring\addSubscriber или MongoDB\Driver\Manager::addSubscriber для регистрации подписчика глобально или с помощью определённого класса Manager соответственно. ]]>
Реализуем логику Теперь займёмся реализацией логики класа подписчика. Для сопоставления двух событий, относящихся к успешно выполненной команды (commandStarted and commandSucceeded), каждый объект события предоставляет поле requestId. Для записи среднего времени выполнения запроса мы начнём с отслеживания команды find в событии commandStarted. Мы будем добавлять элемент в массив pendingCommands с индексом соответствующим requestId и значением, соответствующим запросу. Когда мы получим соответствующее событие commandSucceeded с соответствующим requestId, мы добавим время выполнения (из durationMicros) к общему времени и увеличим счётчик операций. Если мы получим событие commandFailed, мы просто удалим соответствующую запись из pendingCommands. getCommand() ) ) { $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://localhost:27016' ); /* Добавляем подписчика */ \MongoDB\Driver\Monitoring\addSubscriber( new QueryTimeCollector() ); /* Запускаем пачку запросов */ $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 ); ?> ]]>