@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add "request time" event and viewer and context data to Multimeter

Summary: Ref T6930. Only notable thing here is that I prevented non-admins from slicing down by viewing user, since it feels a little creepy to go see what pages you looked at, even though we only show which controllers you invoked. However, it feels important enough to be able to see users destorying the server with crazy requests to let admins see this data.

Test Plan: {F389718}

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T6930

Differential Revision: https://secure.phabricator.com/D12630

+77 -11
+16 -3
src/aphront/configuration/AphrontApplicationConfiguration.php
··· 125 125 126 126 $processing_exception = null; 127 127 try { 128 - $response = $application->processRequest($request, $access_log, $sink); 128 + $response = $application->processRequest( 129 + $request, 130 + $access_log, 131 + $sink, 132 + $multimeter); 129 133 $response_code = $response->getHTTPResponseCode(); 130 134 } catch (Exception $ex) { 131 135 $processing_exception = $ex; ··· 140 144 'T' => PhabricatorStartup::getMicrosecondsSinceStart(), 141 145 )); 142 146 147 + $multimeter->newEvent( 148 + MultimeterEvent::TYPE_REQUEST_TIME, 149 + $multimeter->getEventContext(), 150 + PhabricatorStartup::getMicrosecondsSinceStart()); 151 + 143 152 $access_log->write(); 144 153 145 154 $multimeter->saveEvents(); ··· 171 180 public function processRequest( 172 181 AphrontRequest $request, 173 182 PhutilDeferredLog $access_log, 174 - AphrontHTTPSink $sink) { 183 + AphrontHTTPSink $sink, 184 + MultimeterControl $multimeter) { 175 185 176 186 $this->setRequest($request); 177 187 178 188 list($controller, $uri_data) = $this->buildController(); 179 189 190 + $controller_class = get_class($controller); 180 191 $access_log->setData( 181 192 array( 182 - 'C' => get_class($controller), 193 + 'C' => $controller_class, 183 194 )); 195 + $multimeter->setEventContext('web.'.$controller_class); 184 196 185 197 $request->setURIMap($uri_data); 186 198 $controller->setRequest($request); ··· 198 210 'u' => $request->getUser()->getUserName(), 199 211 'P' => $request->getUser()->getPHID(), 200 212 )); 213 + $multimeter->setEventViewer('user.'.$request->getUser()->getPHID()); 201 214 } 202 215 203 216 if (!$response) {
+52 -8
src/applications/multimeter/controller/MultimeterSampleController.php
··· 33 33 34 34 $with = array(); 35 35 foreach ($group_map as $key => $column) { 36 + 37 + // Don't let non-admins filter by viewers, this feels a little too 38 + // invasive of privacy. 39 + if ($key == 'viewer') { 40 + if (!$viewer->getIsAdmin()) { 41 + continue; 42 + } 43 + } 44 + 36 45 $with[$key] = $request->getStrList($key); 37 46 if ($with[$key]) { 38 47 $where[] = qsprintf( ··· 58 67 implode(', ', array_select_keys($group_map, $group))); 59 68 60 69 $this->loadDimensions($data); 70 + $phids = array(); 71 + foreach ($data as $row) { 72 + $viewer_name = $this->getViewerDimension($row['eventViewerID']) 73 + ->getName(); 74 + $viewer_phid = $this->getEventViewerPHID($viewer_name); 75 + if ($viewer_phid) { 76 + $phids[] = $viewer_phid; 77 + } 78 + } 79 + $handles = $viewer->loadHandles($phids); 61 80 62 81 $rows = array(); 63 82 foreach ($data as $row) { ··· 75 94 } 76 95 77 96 if (isset($group['viewer'])) { 78 - $viewer_col = $this->getViewerDimension($row['eventViewerID']) 79 - ->getName(); 80 - if (!$with['viewer']) { 81 - $viewer_col = $this->renderSelectionLink( 82 - 'viewer', 83 - $row['eventViewerID'], 84 - $viewer_col); 97 + if ($viewer->getIsAdmin()) { 98 + $viewer_col = $this->getViewerDimension($row['eventViewerID']) 99 + ->getName(); 100 + 101 + $viewer_phid = $this->getEventViewerPHID($viewer_col); 102 + if ($viewer_phid) { 103 + $viewer_col = $handles[$viewer_phid]->getName(); 104 + } 105 + 106 + if (!$with['viewer']) { 107 + $viewer_col = $this->renderSelectionLink( 108 + 'viewer', 109 + $row['eventViewerID'], 110 + $viewer_col); 111 + } 112 + } else { 113 + $viewer_col = phutil_tag('em', array(), pht('(Masked)')); 85 114 } 86 115 } else { 87 116 $viewer_col = $this->renderGroupingLink($group, 'viewer'); ··· 148 177 MultimeterEvent::formatResourceCost( 149 178 $viewer, 150 179 $row['eventType'], 180 + $row['totalCost'] / $row['N']), 181 + MultimeterEvent::formatResourceCost( 182 + $viewer, 183 + $row['eventType'], 151 184 $row['totalCost']), 152 - $row['sampleRate'], 185 + ($row['N'] == 1) 186 + ? $row['sampleRate'] 187 + : '-', 153 188 phabricator_datetime($row['epoch'], $viewer), 154 189 ); 155 190 } ··· 164 199 pht('Host'), 165 200 pht('Type'), 166 201 pht('Label'), 202 + pht('Avg'), 167 203 pht('Cost'), 168 204 pht('Rate'), 169 205 pht('Epoch'), ··· 177 213 null, 178 214 null, 179 215 'wide', 216 + 'n', 180 217 'n', 181 218 'n', 182 219 null, ··· 279 316 'request' => 'requestKey', 280 317 'label' => 'eventLabelID', 281 318 ); 319 + } 320 + 321 + private function getEventViewerPHID($viewer_name) { 322 + if (!strncmp($viewer_name, 'user.', 5)) { 323 + return substr($viewer_name, 5); 324 + } 325 + return null; 282 326 } 283 327 284 328 }
+4
src/applications/multimeter/data/MultimeterControl.php
··· 149 149 return $this; 150 150 } 151 151 152 + public function getEventContext() { 153 + return $this->eventContext; 154 + } 155 + 152 156 public function setEventViewer($viewer) { 153 157 $this->eventViewer = $viewer; 154 158 return $this;
+5
src/applications/multimeter/storage/MultimeterEvent.php
··· 3 3 final class MultimeterEvent extends MultimeterDAO { 4 4 5 5 const TYPE_STATIC_RESOURCE = 0; 6 + const TYPE_REQUEST_TIME = 1; 6 7 7 8 protected $eventType; 8 9 protected $eventLabelID; ··· 29 30 switch ($type) { 30 31 case self::TYPE_STATIC_RESOURCE: 31 32 return pht('Static Resource'); 33 + case self::TYPE_REQUEST_TIME: 34 + return pht('Web Request'); 32 35 } 33 36 34 37 return pht('Unknown ("%s")', $type); ··· 42 45 switch ($type) { 43 46 case self::TYPE_STATIC_RESOURCE: 44 47 return pht('%s Req', new PhutilNumber($cost)); 48 + case self::TYPE_REQUEST_TIME: 49 + return pht('%s us', new PhutilNumber($cost)); 45 50 } 46 51 47 52 return pht('%s Unit(s)', new PhutilNumber($cost));