Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(63)

Side by Side Diff: pkg/analysis_server/tool/instrumentation/page/stats_page.dart

Issue 2338883003: Add a tool for viewing instrumentation logs (Closed)
Patch Set: Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 import 'dart:collection';
6
7 import '../log/log.dart';
8 import 'page_writer.dart';
9
10 /**
11 * A page writer that will produce the page containing statistics about an
12 * instrumentation log.
13 */
14 class StatsPage extends PageWriter {
15 /**
16 * The instrumentation log to be written.
17 */
18 final InstrumentationLog log;
19
20 /**
21 * A table mapping the kinds of entries in the log to the number of each kind.
22 */
23 final Map<String, int> entryCounts = new HashMap<String, int>();
24
25 /**
26 * The number of responses that returned an error.
27 */
28 int errorCount = 0;
29
30 /**
31 * A table mapping request method names to a list of the latencies associated
32 * with those requests, where the latency is defined to be the time between
33 * when the request was sent by the client and when the server started
34 * processing the request.
35 */
36 final Map<String, List<int>> latencyData = new HashMap<String, List<int>>();
37
38 /**
39 * A list of the number of milliseconds between a completion request and the
40 * first event for that request.
41 */
42 final List<int> completionResponseTimes = <int>[];
43
44 /**
45 * Initialize a newly created page writer to write information about the given
46 * instrumentation [log].
47 */
48 StatsPage(this.log) {
49 _processEntries(log.logEntries);
50 }
51
52 @override
53 void writeBody(StringSink sink) {
54 writeMenu(sink);
55 sink.writeln('<div id="container">');
56 sink.writeln(' <div id="content">');
57 sink.writeln(' <div id="leftColumn">');
58 sink.writeln(' <div class="inset">');
59 _writeLeftColumn(sink);
60 sink.writeln(' </div>');
61 sink.writeln(' </div>');
62 sink.writeln(' <div id="rightColumn">');
63 sink.writeln(' <div class="inset">');
64 _writeRightColumn(sink);
65 sink.writeln(' </div>');
66 sink.writeln(' </div>');
67 sink.writeln(' </div>');
68 sink.writeln('</div>');
69 }
70
71 /**
72 * Write the content of the style sheet (without the 'script' tag) for the
73 * page to the given [sink].
74 */
75 void writeStyleSheet(StringSink sink) {
76 super.writeStyleSheet(sink);
77 sink.writeln('#leftColumn {');
78 sink.writeln(' float: left;');
79 sink.writeln(' height: 100%;');
80 sink.writeln(' overflow: auto;');
81 sink.writeln(' width: 50%;');
82 sink.writeln('}');
83 sink.writeln('#rightColumn {');
84 sink.writeln(' float: right;');
85 sink.writeln(' height: 100%;');
86 sink.writeln(' overflow: auto;');
87 sink.writeln(' width: 50%;');
88 sink.writeln('}');
89 }
90
91 /**
92 * Return the mean of the values in the given list of [latencies].
93 */
94 int _mean(List<int> latencies) {
scheglov 2016/09/14 16:17:17 The parameter could have a more generic name.
Brian Wilkerson 2016/09/14 16:39:27 Done
95 int sum = latencies.fold(0, (int sum, int latency) => sum + latency);
96 return sum ~/ latencies.length;
97 }
98
99 /**
100 * Return a table mapping the kinds of the given [entries] to the number of
101 * each kind.
102 */
103 void _processEntries(List<LogEntry> entries) {
104 void increment/*<K>*/(Map<dynamic/*=K*/, int> map, dynamic/*=K*/ key) {
105 map[key] = (map[key] ?? 0) + 1;
106 }
107
108 for (LogEntry entry in entries) {
109 String kind = entry.kind;
110 increment(entryCounts, kind);
111 if (entry is ResponseEntry) {
112 if (entry.result('error') != null) {
113 errorCount++;
114 }
115 }
116
117 if (entry is RequestEntry) {
118 String method = entry.method;
119 int latency = entry.timeStamp - entry.clientRequestTime;
120 latencyData.putIfAbsent(method, () => new List<int>()).add(latency);
121 if (method == 'completion.getSuggestions') {
122 ResponseEntry response = log.responseFor(entry);
123 if (response != null) {
124 String id = response.result('id');
125 if (id != null) {
126 List<NotificationEntry> events = log.completionEventsWithId(id);
127 if (events != null && events.length > 0) {
128 completionResponseTimes
129 .add(events[0].timeStamp - entry.timeStamp);
130 }
131 }
132 }
133 }
134 }
135 }
136 }
137
138 void _writeLeftColumn(StringSink sink) {
139 List<String> filePaths = log.logFilePaths;
140 List<LogEntry> entries = log.logEntries;
141 DateTime startDate = entries[0].toTime;
142 DateTime endDate = entries[entries.length - 1].toTime;
143 Duration duration = endDate.difference(startDate);
144 List<String> entryKinds = entryCounts.keys.toList()..sort();
145
146 sink.writeln('<h3>General</h3>');
147 sink.writeln('<p>');
148 if (filePaths.length == 1) {
149 sink.write('<span class="label">Log file:</span> ');
150 sink.write(filePaths[0]);
151 } else {
152 sink.write('<span class="label">Log files:</span> ');
153 bool needsSeparator = false;
154 for (String path in filePaths) {
155 if (needsSeparator) {
156 sink.write(', ');
157 } else {
158 needsSeparator = true;
159 }
160 sink.write(path);
161 }
162 }
163 sink.writeln('<br>');
164 sink.write('<span class="label">Start time:</span> ');
165 writeDate(sink, startDate);
166 sink.writeln('<br>');
167 sink.write('<span class="label">End time:</span> ');
168 writeDate(sink, endDate);
169 sink.writeln('<br>');
170 sink.write('<span class="label">Duration:</span> ');
171 sink.write(duration.toString());
172 sink.writeln('</p>');
173
174 sink.writeln('<h3>Entries</h3>');
175 sink.write('<p>');
176 sink.write('<span class="label">Number of entries:</span> ');
177 sink.write(entries.length);
178 sink.writeln('</p>');
179 sink.writeln('<table>');
180 sink.writeln('<tr><th>count</th><th>kind</th></tr>');
181 for (String kind in entryKinds) {
182 sink.write('<tr><td class="int">');
183 sink.write(entryCounts[kind]);
184 sink.write('</td><td>');
185 sink.write(kind);
186 sink.writeln('</td></tr>');
187 }
188 sink.write('<tr><td class="int">');
189 sink.write(entries.length);
190 sink.writeln('</td><td>Total</td></tr>');
191 sink.writeln('</table>');
192 }
193
194 void _writeRightColumn(StringSink sink) {
195 List<String> methodNames = latencyData.keys.toList()..sort();
196 completionResponseTimes.sort();
197
198 sink.writeln('<h3>Latency</h3>');
199 sink.write('<p>');
200 sink.write('<span class="label">Latency by method</span>');
201 sink.writeln('</p>');
202 sink.writeln('<table>');
203 sink.writeln(
204 '<tr><th>min</th><th>mean</th><th>max</th><th>method</th></tr>');
205 for (String method in methodNames) {
206 List<int> latencies = latencyData[method]..sort();
207 // TODO(brianwilkerson) Add a spark-line distribution graph.
208 sink.write('<tr><td class="int">');
209 sink.write(latencies[0]);
210 sink.write('</td><td class="int">');
211 sink.write(_mean(latencies));
212 sink.write('</td><td class="int">');
213 sink.write(latencies[latencies.length - 1]);
214 sink.write('</td><td>');
215 sink.write(method);
216 sink.writeln('</td></tr>');
217 }
218 sink.writeln('</table>');
219
220 sink.writeln('<h3>Completion</h3>');
221 sink.write('<p>');
222 sink.write('<span class="label">Time to first notification:</span> ');
223 sink.write(completionResponseTimes[0]);
224 sink.write(', ');
225 sink.write(_mean(completionResponseTimes));
226 sink.write(', ');
227 sink.write(completionResponseTimes[completionResponseTimes.length - 1]);
228 sink.writeln('</p>');
229 }
230 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698