<?php
include_once $_SERVER['DOCUMENT_ROOT'] . '/include/shared-manual.inc';
$TOC = array();
$TOC_DEPRECATED = array();
$PARENTS = array();
include_once dirname(__FILE__) ."/toc/mongodb.tutorial.inc";
$setup = array (
  'home' => 
  array (
    0 => 'index.php',
    1 => 'PHP Manual',
  ),
  'head' => 
  array (
    0 => 'UTF-8',
    1 => 'ru',
  ),
  'this' => 
  array (
    0 => 'mongodb.tutorial.apm.php',
    1 => 'Мониторинг производительности приложения (Application Performance Monitoring, или APM)',
    2 => 'Мониторинг производительности приложения (Application Performance Monitoring, или APM)',
  ),
  'up' => 
  array (
    0 => 'mongodb.tutorial.php',
    1 => 'Обучающие материалы',
  ),
  'prev' => 
  array (
    0 => 'mongodb.tutorial.library.php',
    1 => 'Работа библиотеки PHP с драйвером MongoDB (PHPLIB)',
  ),
  'next' => 
  array (
    0 => 'mongodb.architecture.php',
    1 => 'Архитектура и внутреннее устройство драйвера',
  ),
  'alternatives' => 
  array (
  ),
  'source' => 
  array (
    'lang' => 'ru',
    'path' => 'reference/mongodb/tutorial/apm.xml',
  ),
  'history' => 
  array (
  ),
);
$setup["toc"] = $TOC;
$setup["toc_deprecated"] = $TOC_DEPRECATED;
$setup["parents"] = $PARENTS;
manual_setup($setup);

contributors($setup);

?>
<div id="mongodb.tutorial.apm" class="section">
 <h2 class="title">Мониторинг производительности приложения (Application Performance Monitoring, или APM)</h2>

 <p class="para">
  Модуль содержит API-интерфейс подписчика события, который разрешает приложениям отслеживать команды и внутреннюю активность,
  которая относится к <a href="https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-discovery-and-monitoring.md" class="link external">&raquo;&nbsp;Спецификации обнаружения и мониторинга серверов</a>.
  Это руководство продемонстрирует мониторинг команд
  через интерфейс <span class="classname"><a href="class.mongodb-driver-monitoring-commandsubscriber.php" class="classname">MongoDB\Driver\Monitoring\CommandSubscriber</a></span>.
 </p>

 <p class="para">
  Интерфейс <span class="classname"><a href="class.mongodb-driver-monitoring-commandsubscriber.php" class="classname">MongoDB\Driver\Monitoring\CommandSubscriber</a></span>
  определяет три метода: <code class="literal">commandStarted</code>,
  <code class="literal">commandSucceeded</code> и <code class="literal">commandFailed</code>.
  Каждый из них принимает один параметр <code class="parameter">event</code> класса,
  соответствующего нужному событию. К примеру, <code class="literal">commandSucceeded</code>
  принимает аргумент <code class="parameter">$event</code> класса
  <span class="classname"><a href="class.mongodb-driver-monitoring-commandsucceededevent.php" class="classname">MongoDB\Driver\Monitoring\CommandSucceededEvent</a></span>.
 </p>

 <p class="para">
  Руководство реализует подписчика, который создаст список
  профилировок каждого запроса и среднего времени, которое заняли запросы.
 </p>

 <div class="section">
  <h2 class="title">Класс-подписчик Scaffolding</h2>

  <p class="para">
   Начнём с шаблона для подписчика:
  </p>

  <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br /></span><span style="color: #007700">class </span><span style="color: #0000BB">QueryTimeCollector </span><span style="color: #007700">implements </span><span style="color: #0000BB">\MongoDB\Driver\Monitoring\CommandSubscriber<br /></span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">commandStarted</span><span style="color: #007700">( </span><span style="color: #0000BB">\MongoDB\Driver\Monitoring\CommandStartedEvent $event </span><span style="color: #007700">): </span><span style="color: #0000BB">void </span><span style="color: #007700">{}<br /><br />    public function </span><span style="color: #0000BB">commandSucceeded</span><span style="color: #007700">( </span><span style="color: #0000BB">\MongoDB\Driver\Monitoring\CommandSucceededEvent $event </span><span style="color: #007700">): </span><span style="color: #0000BB">void </span><span style="color: #007700">{}<br /><br />    public function </span><span style="color: #0000BB">commandFailed</span><span style="color: #007700">( </span><span style="color: #0000BB">\MongoDB\Driver\Monitoring\CommandFailedEvent $event </span><span style="color: #007700">): </span><span style="color: #0000BB">void </span><span style="color: #007700">{}<br />}<br /><br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
  </div>

 </div>

 <div class="section">
  <h2 class="title">Регистрация подписчика</h2>

  <p class="para">
   Как только объект подписчика создали, подписчика необходимо зарегистрировать
   в системе мониторинга модуля. Глобально подписчика регистрируют методом
   <span class="methodname"><a href="function.mongodb.driver.monitoring.addsubscriber.php" class="methodname">MongoDB\Driver\Monitoring\addSubscriber()</a></span>,
   а для конкретного объекта класса Manager — методом
   <span class="methodname"><a href="mongodb-driver-manager.addsubscriber.php" class="methodname">MongoDB\Driver\Manager::addSubscriber()</a></span>.
  </p>

  <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br />\MongoDB\Driver\Monitoring\addSubscriber</span><span style="color: #007700">( new </span><span style="color: #0000BB">QueryTimeCollector</span><span style="color: #007700">() );<br /><br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
  </div>

 </div>

 <div class="section">
  <h2 class="title">Реализуем логику</h2>

  <p class="para">
   Теперь займёмся реализацией логики класа подписчика.
   Для сопоставления двух событий, относящихся к успешно выполненной
   команды (commandStarted and commandSucceeded), каждый объект события
   предоставляет поле <code class="literal">requestId</code>.
  </p>
  <p class="para">
   Для записи среднего времени выполнения запроса мы начнём с
   отслеживания команды <code class="literal">find</code> в событии commandStarted.
   Мы будем добавлять элемент в массив <code class="literal">pendingCommands</code>
   с индексом соответствующим <code class="literal">requestId</code> и значением, соответствующим
   запросу.
  </p>
  <p class="para">
   Когда мы получим соответствующее событие commandSucceeded с соответствующим
   <code class="literal">requestId</code>, мы добавим время выполнения (из
   <code class="literal">durationMicros</code>) к общему времени и увеличим счётчик операций.
  </p>
  <p class="para">
   Если мы получим событие commandFailed, мы просто удалим соответствующую запись из
   <code class="literal">pendingCommands</code>.
  </p>

  <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br /></span><span style="color: #007700">class </span><span style="color: #0000BB">QueryTimeCollector </span><span style="color: #007700">implements </span><span style="color: #0000BB">\MongoDB\Driver\Monitoring\CommandSubscriber<br /></span><span style="color: #007700">{<br />    private </span><span style="color: #0000BB">$pendingCommands </span><span style="color: #007700">= [];<br />    private </span><span style="color: #0000BB">$queryShapeStats </span><span style="color: #007700">= [];<br /><br />    </span><span style="color: #FF8000">/* Создаёт форму запроса из аргумента фильтра. Учитываются<br />     * только поля верхнего уровня. */<br />    </span><span style="color: #007700">private function </span><span style="color: #0000BB">createQueryShape</span><span style="color: #007700">(array </span><span style="color: #0000BB">$filter</span><span style="color: #007700">)<br />    {<br />        return </span><span style="color: #0000BB">json_encode</span><span style="color: #007700">(</span><span style="color: #0000BB">array_keys</span><span style="color: #007700">(</span><span style="color: #0000BB">$filter</span><span style="color: #007700">));<br />    }<br /><br />    public function </span><span style="color: #0000BB">commandStarted</span><span style="color: #007700">(</span><span style="color: #0000BB">\MongoDB\Driver\Monitoring\CommandStartedEvent $event</span><span style="color: #007700">): </span><span style="color: #0000BB">void<br />    </span><span style="color: #007700">{<br />        if (</span><span style="color: #DD0000">'find' </span><span style="color: #007700">=== </span><span style="color: #0000BB">$event</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getCommandName</span><span style="color: #007700">()) {<br />            </span><span style="color: #0000BB">$queryShape </span><span style="color: #007700">= </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">createQueryShape</span><span style="color: #007700">((array) </span><span style="color: #0000BB">$event</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getCommand</span><span style="color: #007700">()-&gt;</span><span style="color: #0000BB">filter</span><span style="color: #007700">);<br />            </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">pendingCommands</span><span style="color: #007700">[</span><span style="color: #0000BB">$event</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getRequestId</span><span style="color: #007700">()] = </span><span style="color: #0000BB">$queryShape</span><span style="color: #007700">;<br />        }<br />    }<br /><br />    public function </span><span style="color: #0000BB">commandSucceeded</span><span style="color: #007700">(</span><span style="color: #0000BB">\MongoDB\Driver\Monitoring\CommandSucceededEvent $event</span><span style="color: #007700">): </span><span style="color: #0000BB">void<br />    </span><span style="color: #007700">{<br />        </span><span style="color: #0000BB">$requestId </span><span style="color: #007700">= </span><span style="color: #0000BB">$event</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getRequestId</span><span style="color: #007700">();<br />        if (</span><span style="color: #0000BB">array_key_exists</span><span style="color: #007700">(</span><span style="color: #0000BB">$requestId</span><span style="color: #007700">, </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">pendingCommands</span><span style="color: #007700">)) {<br />            </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">queryShapeStats</span><span style="color: #007700">[</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">pendingCommands</span><span style="color: #007700">[</span><span style="color: #0000BB">$requestId</span><span style="color: #007700">]][</span><span style="color: #DD0000">'count'</span><span style="color: #007700">]++;<br />            </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">queryShapeStats</span><span style="color: #007700">[</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">pendingCommands</span><span style="color: #007700">[</span><span style="color: #0000BB">$requestId</span><span style="color: #007700">]][</span><span style="color: #DD0000">'duration'</span><span style="color: #007700">] += </span><span style="color: #0000BB">$event</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getDurationMicros</span><span style="color: #007700">();<br />            unset(</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">pendingCommands</span><span style="color: #007700">[</span><span style="color: #0000BB">$requestId</span><span style="color: #007700">]);<br />        }<br />    }<br /><br />    public function </span><span style="color: #0000BB">commandFailed</span><span style="color: #007700">(</span><span style="color: #0000BB">\MongoDB\Driver\Monitoring\CommandFailedEvent $event</span><span style="color: #007700">): </span><span style="color: #0000BB">void<br />    </span><span style="color: #007700">{<br />        if (</span><span style="color: #0000BB">array_key_exists</span><span style="color: #007700">(</span><span style="color: #0000BB">$event</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getRequestId</span><span style="color: #007700">(), </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">pendingCommands</span><span style="color: #007700">)) {<br />            unset(</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">pendingCommands</span><span style="color: #007700">[</span><span style="color: #0000BB">$event</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getRequestId</span><span style="color: #007700">()]);<br />        }<br />    }<br /><br />    public function </span><span style="color: #0000BB">__destruct</span><span style="color: #007700">()<br />    {<br />        foreach (</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">queryShapeStats </span><span style="color: #007700">as </span><span style="color: #0000BB">$shape </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">$stats</span><span style="color: #007700">) {<br />            echo </span><span style="color: #DD0000">"Shape: "</span><span style="color: #007700">, </span><span style="color: #0000BB">$shape</span><span style="color: #007700">, </span><span style="color: #DD0000">" ("</span><span style="color: #007700">, </span><span style="color: #0000BB">$stats</span><span style="color: #007700">[</span><span style="color: #DD0000">'count'</span><span style="color: #007700">], </span><span style="color: #DD0000">")\n  "</span><span style="color: #007700">,<br />            </span><span style="color: #0000BB">$stats</span><span style="color: #007700">[</span><span style="color: #DD0000">'duration'</span><span style="color: #007700">] / </span><span style="color: #0000BB">$stats</span><span style="color: #007700">[</span><span style="color: #DD0000">'count'</span><span style="color: #007700">], </span><span style="color: #DD0000">"µs\n\n"</span><span style="color: #007700">;<br />        }<br />    }<br />}<br /><br /></span><span style="color: #0000BB">$m </span><span style="color: #007700">= new </span><span style="color: #0000BB">\MongoDB\Driver\Manager</span><span style="color: #007700">(</span><span style="color: #DD0000">'mongodb://localhost:27016'</span><span style="color: #007700">);<br /><br /></span><span style="color: #FF8000">/* Добавляем подписчика */<br /></span><span style="color: #0000BB">\MongoDB\Driver\Monitoring\addSubscriber</span><span style="color: #007700">(new </span><span style="color: #0000BB">QueryTimeCollector</span><span style="color: #007700">());<br /><br /></span><span style="color: #FF8000">/* Запускаем пачку запросов */<br /></span><span style="color: #0000BB">$query </span><span style="color: #007700">= new </span><span style="color: #0000BB">\MongoDB\Driver\Query</span><span style="color: #007700">([<br />    </span><span style="color: #DD0000">'region_slug' </span><span style="color: #007700">=&gt; </span><span style="color: #DD0000">'scotland-highlands'</span><span style="color: #007700">, </span><span style="color: #DD0000">'age' </span><span style="color: #007700">=&gt; [</span><span style="color: #DD0000">'$gte' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">20</span><span style="color: #007700">]<br />]);<br /></span><span style="color: #0000BB">$cursor </span><span style="color: #007700">= </span><span style="color: #0000BB">$m</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">executeQuery</span><span style="color: #007700">(</span><span style="color: #DD0000">'dramio.whisky'</span><span style="color: #007700">, </span><span style="color: #0000BB">$query</span><span style="color: #007700">);<br /><br /></span><span style="color: #0000BB">$query </span><span style="color: #007700">= new </span><span style="color: #0000BB">\MongoDB\Driver\Query</span><span style="color: #007700">([<br />    </span><span style="color: #DD0000">'region_slug' </span><span style="color: #007700">=&gt; </span><span style="color: #DD0000">'scotland-lowlands'</span><span style="color: #007700">, </span><span style="color: #DD0000">'age' </span><span style="color: #007700">=&gt; [</span><span style="color: #DD0000">'$gte' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">15</span><span style="color: #007700">]<br />]);<br /></span><span style="color: #0000BB">$cursor </span><span style="color: #007700">= </span><span style="color: #0000BB">$m</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">executeQuery</span><span style="color: #007700">(</span><span style="color: #DD0000">'dramio.whisky'</span><span style="color: #007700">, </span><span style="color: #0000BB">$query</span><span style="color: #007700">);<br /><br /></span><span style="color: #0000BB">$query </span><span style="color: #007700">= new </span><span style="color: #0000BB">\MongoDB\Driver\Query</span><span style="color: #007700">([</span><span style="color: #DD0000">'region_slug' </span><span style="color: #007700">=&gt; </span><span style="color: #DD0000">'scotland-lowlands'</span><span style="color: #007700">]);<br /></span><span style="color: #0000BB">$cursor </span><span style="color: #007700">= </span><span style="color: #0000BB">$m</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">executeQuery</span><span style="color: #007700">(</span><span style="color: #DD0000">'dramio.whisky'</span><span style="color: #007700">, </span><span style="color: #0000BB">$query</span><span style="color: #007700">);<br /><br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
  </div>

 </div>

</div><?php manual_footer($setup); ?>