protected function collectGarbage()
 {
     $table = new MultimeterEvent();
     $conn_w = $table->establishConnection('w');
     queryfx($conn_w, 'DELETE FROM %T WHERE epoch < %d LIMIT 100', $table->getTableName(), $this->getGarbageEpoch());
     return $conn_w->getAffectedRows() == 100;
 }
 public function collectGarbage()
 {
     $ttl = phutil_units('90 days in seconds');
     $table = new MultimeterEvent();
     $conn_w = $table->establishConnection('w');
     queryfx($conn_w, 'DELETE FROM %T WHERE epoch < %d LIMIT 100', $table->getTableName(), PhabricatorTime::getNow() - $ttl);
     return $conn_w->getAffectedRows() == 100;
 }
 public function handleRequest(AphrontRequest $request)
 {
     $viewer = $this->getViewer();
     $group_map = $this->getColumnMap();
     $group = explode('.', $request->getStr('group'));
     $group = array_intersect($group, array_keys($group_map));
     $group = array_fuse($group);
     if (empty($group['type'])) {
         $group['type'] = 'type';
     }
     $now = PhabricatorTime::getNow();
     $ago = $now - phutil_units('24 hours in seconds');
     $table = new MultimeterEvent();
     $conn = $table->establishConnection('r');
     $where = array();
     $where[] = qsprintf($conn, 'epoch >= %d AND epoch <= %d', $ago, $now);
     $with = array();
     foreach ($group_map as $key => $column) {
         // Don't let non-admins filter by viewers, this feels a little too
         // invasive of privacy.
         if ($key == 'viewer') {
             if (!$viewer->getIsAdmin()) {
                 continue;
             }
         }
         $with[$key] = $request->getStrList($key);
         if ($with[$key]) {
             $where[] = qsprintf($conn, '%T IN (%Ls)', $column, $with[$key]);
         }
     }
     $where = '(' . implode(') AND (', $where) . ')';
     $data = queryfx_all($conn, 'SELECT *,
       count(*) AS N,
       SUM(sampleRate * resourceCost) AS totalCost,
       SUM(sampleRate * resourceCost) / SUM(sampleRate) AS averageCost
     FROM %T
     WHERE %Q
     GROUP BY %Q
     ORDER BY totalCost DESC, MAX(id) DESC
     LIMIT 100', $table->getTableName(), $where, implode(', ', array_select_keys($group_map, $group)));
     $this->loadDimensions($data);
     $phids = array();
     foreach ($data as $row) {
         $viewer_name = $this->getViewerDimension($row['eventViewerID'])->getName();
         $viewer_phid = $this->getEventViewerPHID($viewer_name);
         if ($viewer_phid) {
             $phids[] = $viewer_phid;
         }
     }
     $handles = $viewer->loadHandles($phids);
     $rows = array();
     foreach ($data as $row) {
         if ($row['N'] == 1) {
             $events_col = $row['id'];
         } else {
             $events_col = $this->renderGroupingLink($group, 'id', pht('%s Event(s)', new PhutilNumber($row['N'])));
         }
         if (isset($group['request'])) {
             $request_col = $row['requestKey'];
             if (!$with['request']) {
                 $request_col = $this->renderSelectionLink('request', $row['requestKey'], $request_col);
             }
         } else {
             $request_col = $this->renderGroupingLink($group, 'request');
         }
         if (isset($group['viewer'])) {
             if ($viewer->getIsAdmin()) {
                 $viewer_col = $this->getViewerDimension($row['eventViewerID'])->getName();
                 $viewer_phid = $this->getEventViewerPHID($viewer_col);
                 if ($viewer_phid) {
                     $viewer_col = $handles[$viewer_phid]->getName();
                 }
                 if (!$with['viewer']) {
                     $viewer_col = $this->renderSelectionLink('viewer', $row['eventViewerID'], $viewer_col);
                 }
             } else {
                 $viewer_col = phutil_tag('em', array(), pht('(Masked)'));
             }
         } else {
             $viewer_col = $this->renderGroupingLink($group, 'viewer');
         }
         if (isset($group['context'])) {
             $context_col = $this->getContextDimension($row['eventContextID'])->getName();
             if (!$with['context']) {
                 $context_col = $this->renderSelectionLink('context', $row['eventContextID'], $context_col);
             }
         } else {
             $context_col = $this->renderGroupingLink($group, 'context');
         }
         if (isset($group['host'])) {
             $host_col = $this->getHostDimension($row['eventHostID'])->getName();
             if (!$with['host']) {
                 $host_col = $this->renderSelectionLink('host', $row['eventHostID'], $host_col);
             }
         } else {
             $host_col = $this->renderGroupingLink($group, 'host');
         }
         if (isset($group['label'])) {
             $label_col = $this->getLabelDimension($row['eventLabelID'])->getName();
             if (!$with['label']) {
                 $label_col = $this->renderSelectionLink('label', $row['eventLabelID'], $label_col);
             }
         } else {
             $label_col = $this->renderGroupingLink($group, 'label');
         }
         if ($with['type']) {
             $type_col = MultimeterEvent::getEventTypeName($row['eventType']);
         } else {
             $type_col = $this->renderSelectionLink('type', $row['eventType'], MultimeterEvent::getEventTypeName($row['eventType']));
         }
         $rows[] = array($events_col, $request_col, $viewer_col, $context_col, $host_col, $type_col, $label_col, MultimeterEvent::formatResourceCost($viewer, $row['eventType'], $row['averageCost']), MultimeterEvent::formatResourceCost($viewer, $row['eventType'], $row['totalCost']), $row['N'] == 1 ? $row['sampleRate'] : '-', phabricator_datetime($row['epoch'], $viewer));
     }
     $table = id(new AphrontTableView($rows))->setHeaders(array(pht('ID'), pht('Request'), pht('Viewer'), pht('Context'), pht('Host'), pht('Type'), pht('Label'), pht('Avg'), pht('Cost'), pht('Rate'), pht('Epoch')))->setColumnClasses(array(null, null, null, null, null, null, 'wide', 'n', 'n', 'n', null));
     $box = id(new PHUIObjectBoxView())->setHeaderText(pht('Samples'))->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)->setTable($table);
     $crumbs = $this->buildApplicationCrumbs();
     $crumbs->addTextCrumb(pht('Samples'), $this->getGroupURI(array(), true));
     $crumbs->setBorder(true);
     $crumb_map = array('host' => pht('By Host'), 'context' => pht('By Context'), 'viewer' => pht('By Viewer'), 'request' => pht('By Request'), 'label' => pht('By Label'), 'id' => pht('By ID'));
     $parts = array();
     foreach ($group as $item) {
         if ($item == 'type') {
             continue;
         }
         $parts[$item] = $item;
         $crumbs->addTextCrumb(idx($crumb_map, $item, $item), $this->getGroupURI($parts, true));
     }
     $header = id(new PHUIHeaderView())->setHeader(pht('Samples (%s - %s)', phabricator_datetime($ago, $viewer), phabricator_datetime($now, $viewer)))->setHeaderIcon('fa-motorcycle');
     $view = id(new PHUITwoColumnView())->setHeader($header)->setFooter($box);
     return $this->newPage()->setTitle(pht('Samples'))->setCrumbs($crumbs)->appendChild($view);
 }