Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/multimeter/controller/MultimeterSampleController.php
12256 views
1
<?php
2
3
final class MultimeterSampleController extends MultimeterController {
4
5
public function shouldAllowPublic() {
6
return true;
7
}
8
9
public function handleRequest(AphrontRequest $request) {
10
$viewer = $this->getViewer();
11
$group_map = $this->getColumnMap();
12
13
$group = explode('.', $request->getStr('group'));
14
$group = array_intersect($group, array_keys($group_map));
15
$group = array_fuse($group);
16
17
if (empty($group['type'])) {
18
$group['type'] = 'type';
19
}
20
21
$now = PhabricatorTime::getNow();
22
$ago = ($now - phutil_units('24 hours in seconds'));
23
24
$table = new MultimeterEvent();
25
$conn = $table->establishConnection('r');
26
27
$where = array();
28
$where[] = qsprintf(
29
$conn,
30
'epoch >= %d AND epoch <= %d',
31
$ago,
32
$now);
33
34
$with = array();
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
45
$with[$key] = $request->getStrList($key);
46
if ($with[$key]) {
47
$where[] = qsprintf(
48
$conn,
49
'%T IN (%Ls)',
50
$column,
51
$with[$key]);
52
}
53
}
54
55
$data = queryfx_all(
56
$conn,
57
'SELECT *,
58
count(*) AS N,
59
SUM(sampleRate * resourceCost) AS totalCost,
60
SUM(sampleRate * resourceCost) / SUM(sampleRate) AS averageCost
61
FROM %T
62
WHERE %LA
63
GROUP BY %LC
64
ORDER BY totalCost DESC, MAX(id) DESC
65
LIMIT 100',
66
$table->getTableName(),
67
$where,
68
array_select_keys($group_map, $group));
69
70
$this->loadDimensions($data);
71
$phids = array();
72
foreach ($data as $row) {
73
$viewer_name = $this->getViewerDimension($row['eventViewerID'])
74
->getName();
75
$viewer_phid = $this->getEventViewerPHID($viewer_name);
76
if ($viewer_phid) {
77
$phids[] = $viewer_phid;
78
}
79
}
80
$handles = $viewer->loadHandles($phids);
81
82
$rows = array();
83
foreach ($data as $row) {
84
85
if ($row['N'] == 1) {
86
$events_col = $row['id'];
87
} else {
88
$events_col = $this->renderGroupingLink(
89
$group,
90
'id',
91
pht('%s Event(s)', new PhutilNumber($row['N'])));
92
}
93
94
if (isset($group['request'])) {
95
$request_col = $row['requestKey'];
96
if (!$with['request']) {
97
$request_col = $this->renderSelectionLink(
98
'request',
99
$row['requestKey'],
100
$request_col);
101
}
102
} else {
103
$request_col = $this->renderGroupingLink($group, 'request');
104
}
105
106
if (isset($group['viewer'])) {
107
if ($viewer->getIsAdmin()) {
108
$viewer_col = $this->getViewerDimension($row['eventViewerID'])
109
->getName();
110
111
$viewer_phid = $this->getEventViewerPHID($viewer_col);
112
if ($viewer_phid) {
113
$viewer_col = $handles[$viewer_phid]->getName();
114
}
115
116
if (!$with['viewer']) {
117
$viewer_col = $this->renderSelectionLink(
118
'viewer',
119
$row['eventViewerID'],
120
$viewer_col);
121
}
122
} else {
123
$viewer_col = phutil_tag('em', array(), pht('(Masked)'));
124
}
125
} else {
126
$viewer_col = $this->renderGroupingLink($group, 'viewer');
127
}
128
129
if (isset($group['context'])) {
130
$context_col = $this->getContextDimension($row['eventContextID'])
131
->getName();
132
if (!$with['context']) {
133
$context_col = $this->renderSelectionLink(
134
'context',
135
$row['eventContextID'],
136
$context_col);
137
}
138
} else {
139
$context_col = $this->renderGroupingLink($group, 'context');
140
}
141
142
if (isset($group['host'])) {
143
$host_col = $this->getHostDimension($row['eventHostID'])
144
->getName();
145
if (!$with['host']) {
146
$host_col = $this->renderSelectionLink(
147
'host',
148
$row['eventHostID'],
149
$host_col);
150
}
151
} else {
152
$host_col = $this->renderGroupingLink($group, 'host');
153
}
154
155
if (isset($group['label'])) {
156
$label_col = $this->getLabelDimension($row['eventLabelID'])
157
->getName();
158
if (!$with['label']) {
159
$label_col = $this->renderSelectionLink(
160
'label',
161
$row['eventLabelID'],
162
$label_col);
163
}
164
} else {
165
$label_col = $this->renderGroupingLink($group, 'label');
166
}
167
168
if ($with['type']) {
169
$type_col = MultimeterEvent::getEventTypeName($row['eventType']);
170
} else {
171
$type_col = $this->renderSelectionLink(
172
'type',
173
$row['eventType'],
174
MultimeterEvent::getEventTypeName($row['eventType']));
175
}
176
177
$rows[] = array(
178
$events_col,
179
$request_col,
180
$viewer_col,
181
$context_col,
182
$host_col,
183
$type_col,
184
$label_col,
185
MultimeterEvent::formatResourceCost(
186
$viewer,
187
$row['eventType'],
188
$row['averageCost']),
189
MultimeterEvent::formatResourceCost(
190
$viewer,
191
$row['eventType'],
192
$row['totalCost']),
193
($row['N'] == 1)
194
? $row['sampleRate']
195
: '-',
196
phabricator_datetime($row['epoch'], $viewer),
197
);
198
}
199
200
$table = id(new AphrontTableView($rows))
201
->setHeaders(
202
array(
203
pht('ID'),
204
pht('Request'),
205
pht('Viewer'),
206
pht('Context'),
207
pht('Host'),
208
pht('Type'),
209
pht('Label'),
210
pht('Avg'),
211
pht('Cost'),
212
pht('Rate'),
213
pht('Epoch'),
214
))
215
->setColumnClasses(
216
array(
217
null,
218
null,
219
null,
220
null,
221
null,
222
null,
223
'wide',
224
'n',
225
'n',
226
'n',
227
null,
228
));
229
230
$box = id(new PHUIObjectBoxView())
231
->setHeaderText(pht('Samples'))
232
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
233
->setTable($table);
234
235
$crumbs = $this->buildApplicationCrumbs();
236
$crumbs->addTextCrumb(
237
pht('Samples'),
238
$this->getGroupURI(array(), true));
239
$crumbs->setBorder(true);
240
241
$crumb_map = array(
242
'host' => pht('By Host'),
243
'context' => pht('By Context'),
244
'viewer' => pht('By Viewer'),
245
'request' => pht('By Request'),
246
'label' => pht('By Label'),
247
'id' => pht('By ID'),
248
);
249
250
$parts = array();
251
foreach ($group as $item) {
252
if ($item == 'type') {
253
continue;
254
}
255
$parts[$item] = $item;
256
$crumbs->addTextCrumb(
257
idx($crumb_map, $item, $item),
258
$this->getGroupURI($parts, true));
259
}
260
261
$header = id(new PHUIHeaderView())
262
->setHeader(
263
pht(
264
'Samples (%s - %s)',
265
phabricator_datetime($ago, $viewer),
266
phabricator_datetime($now, $viewer)))
267
->setHeaderIcon('fa-motorcycle');
268
269
$view = id(new PHUITwoColumnView())
270
->setHeader($header)
271
->setFooter($box);
272
273
return $this->newPage()
274
->setTitle(pht('Samples'))
275
->setCrumbs($crumbs)
276
->appendChild($view);
277
278
}
279
280
private function renderGroupingLink(array $group, $key, $name = null) {
281
$group[] = $key;
282
$uri = $this->getGroupURI($group);
283
284
if ($name === null) {
285
$name = pht('(All)');
286
}
287
288
return phutil_tag(
289
'a',
290
array(
291
'href' => $uri,
292
'style' => 'font-weight: bold',
293
),
294
$name);
295
}
296
297
private function getGroupURI(array $group, $wipe = false) {
298
unset($group['type']);
299
$uri = clone $this->getRequest()->getRequestURI();
300
301
$group = implode('.', $group);
302
if (!strlen($group)) {
303
$uri->removeQueryParam('group');
304
} else {
305
$uri->replaceQueryParam('group', $group);
306
}
307
308
if ($wipe) {
309
foreach ($this->getColumnMap() as $key => $column) {
310
$uri->removeQueryParam($key);
311
}
312
}
313
314
return $uri;
315
}
316
317
private function renderSelectionLink($key, $value, $link_text) {
318
$value = (array)$value;
319
320
$uri = clone $this->getRequest()->getRequestURI();
321
$uri->replaceQueryParam($key, implode(',', $value));
322
323
return phutil_tag(
324
'a',
325
array(
326
'href' => $uri,
327
),
328
$link_text);
329
}
330
331
private function getColumnMap() {
332
return array(
333
'type' => 'eventType',
334
'host' => 'eventHostID',
335
'context' => 'eventContextID',
336
'viewer' => 'eventViewerID',
337
'request' => 'requestKey',
338
'label' => 'eventLabelID',
339
'id' => 'id',
340
);
341
}
342
343
private function getEventViewerPHID($viewer_name) {
344
if (!strncmp($viewer_name, 'user.', 5)) {
345
return substr($viewer_name, 5);
346
}
347
return null;
348
}
349
350
}
351
352