Path: blob/master/src/applications/multimeter/controller/MultimeterSampleController.php
12256 views
<?php12final class MultimeterSampleController extends MultimeterController {34public function shouldAllowPublic() {5return true;6}78public function handleRequest(AphrontRequest $request) {9$viewer = $this->getViewer();10$group_map = $this->getColumnMap();1112$group = explode('.', $request->getStr('group'));13$group = array_intersect($group, array_keys($group_map));14$group = array_fuse($group);1516if (empty($group['type'])) {17$group['type'] = 'type';18}1920$now = PhabricatorTime::getNow();21$ago = ($now - phutil_units('24 hours in seconds'));2223$table = new MultimeterEvent();24$conn = $table->establishConnection('r');2526$where = array();27$where[] = qsprintf(28$conn,29'epoch >= %d AND epoch <= %d',30$ago,31$now);3233$with = array();34foreach ($group_map as $key => $column) {3536// Don't let non-admins filter by viewers, this feels a little too37// invasive of privacy.38if ($key == 'viewer') {39if (!$viewer->getIsAdmin()) {40continue;41}42}4344$with[$key] = $request->getStrList($key);45if ($with[$key]) {46$where[] = qsprintf(47$conn,48'%T IN (%Ls)',49$column,50$with[$key]);51}52}5354$data = queryfx_all(55$conn,56'SELECT *,57count(*) AS N,58SUM(sampleRate * resourceCost) AS totalCost,59SUM(sampleRate * resourceCost) / SUM(sampleRate) AS averageCost60FROM %T61WHERE %LA62GROUP BY %LC63ORDER BY totalCost DESC, MAX(id) DESC64LIMIT 100',65$table->getTableName(),66$where,67array_select_keys($group_map, $group));6869$this->loadDimensions($data);70$phids = array();71foreach ($data as $row) {72$viewer_name = $this->getViewerDimension($row['eventViewerID'])73->getName();74$viewer_phid = $this->getEventViewerPHID($viewer_name);75if ($viewer_phid) {76$phids[] = $viewer_phid;77}78}79$handles = $viewer->loadHandles($phids);8081$rows = array();82foreach ($data as $row) {8384if ($row['N'] == 1) {85$events_col = $row['id'];86} else {87$events_col = $this->renderGroupingLink(88$group,89'id',90pht('%s Event(s)', new PhutilNumber($row['N'])));91}9293if (isset($group['request'])) {94$request_col = $row['requestKey'];95if (!$with['request']) {96$request_col = $this->renderSelectionLink(97'request',98$row['requestKey'],99$request_col);100}101} else {102$request_col = $this->renderGroupingLink($group, 'request');103}104105if (isset($group['viewer'])) {106if ($viewer->getIsAdmin()) {107$viewer_col = $this->getViewerDimension($row['eventViewerID'])108->getName();109110$viewer_phid = $this->getEventViewerPHID($viewer_col);111if ($viewer_phid) {112$viewer_col = $handles[$viewer_phid]->getName();113}114115if (!$with['viewer']) {116$viewer_col = $this->renderSelectionLink(117'viewer',118$row['eventViewerID'],119$viewer_col);120}121} else {122$viewer_col = phutil_tag('em', array(), pht('(Masked)'));123}124} else {125$viewer_col = $this->renderGroupingLink($group, 'viewer');126}127128if (isset($group['context'])) {129$context_col = $this->getContextDimension($row['eventContextID'])130->getName();131if (!$with['context']) {132$context_col = $this->renderSelectionLink(133'context',134$row['eventContextID'],135$context_col);136}137} else {138$context_col = $this->renderGroupingLink($group, 'context');139}140141if (isset($group['host'])) {142$host_col = $this->getHostDimension($row['eventHostID'])143->getName();144if (!$with['host']) {145$host_col = $this->renderSelectionLink(146'host',147$row['eventHostID'],148$host_col);149}150} else {151$host_col = $this->renderGroupingLink($group, 'host');152}153154if (isset($group['label'])) {155$label_col = $this->getLabelDimension($row['eventLabelID'])156->getName();157if (!$with['label']) {158$label_col = $this->renderSelectionLink(159'label',160$row['eventLabelID'],161$label_col);162}163} else {164$label_col = $this->renderGroupingLink($group, 'label');165}166167if ($with['type']) {168$type_col = MultimeterEvent::getEventTypeName($row['eventType']);169} else {170$type_col = $this->renderSelectionLink(171'type',172$row['eventType'],173MultimeterEvent::getEventTypeName($row['eventType']));174}175176$rows[] = array(177$events_col,178$request_col,179$viewer_col,180$context_col,181$host_col,182$type_col,183$label_col,184MultimeterEvent::formatResourceCost(185$viewer,186$row['eventType'],187$row['averageCost']),188MultimeterEvent::formatResourceCost(189$viewer,190$row['eventType'],191$row['totalCost']),192($row['N'] == 1)193? $row['sampleRate']194: '-',195phabricator_datetime($row['epoch'], $viewer),196);197}198199$table = id(new AphrontTableView($rows))200->setHeaders(201array(202pht('ID'),203pht('Request'),204pht('Viewer'),205pht('Context'),206pht('Host'),207pht('Type'),208pht('Label'),209pht('Avg'),210pht('Cost'),211pht('Rate'),212pht('Epoch'),213))214->setColumnClasses(215array(216null,217null,218null,219null,220null,221null,222'wide',223'n',224'n',225'n',226null,227));228229$box = id(new PHUIObjectBoxView())230->setHeaderText(pht('Samples'))231->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)232->setTable($table);233234$crumbs = $this->buildApplicationCrumbs();235$crumbs->addTextCrumb(236pht('Samples'),237$this->getGroupURI(array(), true));238$crumbs->setBorder(true);239240$crumb_map = array(241'host' => pht('By Host'),242'context' => pht('By Context'),243'viewer' => pht('By Viewer'),244'request' => pht('By Request'),245'label' => pht('By Label'),246'id' => pht('By ID'),247);248249$parts = array();250foreach ($group as $item) {251if ($item == 'type') {252continue;253}254$parts[$item] = $item;255$crumbs->addTextCrumb(256idx($crumb_map, $item, $item),257$this->getGroupURI($parts, true));258}259260$header = id(new PHUIHeaderView())261->setHeader(262pht(263'Samples (%s - %s)',264phabricator_datetime($ago, $viewer),265phabricator_datetime($now, $viewer)))266->setHeaderIcon('fa-motorcycle');267268$view = id(new PHUITwoColumnView())269->setHeader($header)270->setFooter($box);271272return $this->newPage()273->setTitle(pht('Samples'))274->setCrumbs($crumbs)275->appendChild($view);276277}278279private function renderGroupingLink(array $group, $key, $name = null) {280$group[] = $key;281$uri = $this->getGroupURI($group);282283if ($name === null) {284$name = pht('(All)');285}286287return phutil_tag(288'a',289array(290'href' => $uri,291'style' => 'font-weight: bold',292),293$name);294}295296private function getGroupURI(array $group, $wipe = false) {297unset($group['type']);298$uri = clone $this->getRequest()->getRequestURI();299300$group = implode('.', $group);301if (!strlen($group)) {302$uri->removeQueryParam('group');303} else {304$uri->replaceQueryParam('group', $group);305}306307if ($wipe) {308foreach ($this->getColumnMap() as $key => $column) {309$uri->removeQueryParam($key);310}311}312313return $uri;314}315316private function renderSelectionLink($key, $value, $link_text) {317$value = (array)$value;318319$uri = clone $this->getRequest()->getRequestURI();320$uri->replaceQueryParam($key, implode(',', $value));321322return phutil_tag(323'a',324array(325'href' => $uri,326),327$link_text);328}329330private function getColumnMap() {331return array(332'type' => 'eventType',333'host' => 'eventHostID',334'context' => 'eventContextID',335'viewer' => 'eventViewerID',336'request' => 'requestKey',337'label' => 'eventLabelID',338'id' => 'id',339);340}341342private function getEventViewerPHID($viewer_name) {343if (!strncmp($viewer_name, 'user.', 5)) {344return substr($viewer_name, 5);345}346return null;347}348349}350351352