Merge lp:~huwshimi/launchpad/ajax-time into lp:launchpad

Proposed by Huw Wilkins
Status: Merged
Approved by: Robert Collins
Approved revision: no longer in the source branch.
Merged at revision: 12699
Proposed branch: lp:~huwshimi/launchpad/ajax-time
Merge into: lp:launchpad
Diff against target: 183 lines (+132/-4)
4 files modified
lib/canonical/launchpad/icing/style-3-0.css (+38/-2)
lib/canonical/launchpad/templates/launchpad-loginstatus.pt (+7/-1)
lib/lp/app/javascript/ajax_log.js (+85/-0)
lib/lp/app/templates/base-layout.pt (+2/-1)
To merge this branch: bzr merge lp:~huwshimi/launchpad/ajax-time
Reviewer Review Type Date Requested Status
Robert Collins (community) Approve
William Grant code* Approve
Review via email: mp+55257@code.launchpad.net

Commit message

[r=lifeless,wgrant][no-qa] Added a visible log of all AJAX events.

Description of the change

We want to expose the time AJAX events take. This branch adds a visible log of all AJAX events to the user logout area. It exposes time taken, the internal AJAX event id, HTTP status and OOPS ID (if applicable).

The log also highlights if the AJAX event takes more than 1 second.

A screencast can be found here: http://people.canonical.com/~huwshimi/ajax_time_log.ogv

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) wrote :

Looks really nice, but a few comments:

 - That JS should be somewhere other than the template. Probably in a new file in lib/lp/app/javascript.
 - The spacing around the new link is also a little off... it might be best to just remove the • from the render time.
 - You construct HTML in JS with string concatenation. While the values that you're including should always be safe, I'd prefer if you constructed a node from a literal string and injected the text using YUI/DOM methods.
 - Could the click handler use toggleClass instead of add/removeClass?

review: Needs Fixing (code*)
Revision history for this message
Huw Wilkins (huwshimi) wrote :

> - That JS should be somewhere other than the template. Probably in a new file
> in lib/lp/app/javascript.

Done.

> - The spacing around the new link is also a little off... it might be best to
> just remove the • from the render time.

Fixed. Not great, but better.

> - You construct HTML in JS with string concatenation. While the values that
> you're including should always be safe, I'd prefer if you constructed a node
> from a literal string and injected the text using YUI/DOM methods.

Done.

> - Could the click handler use toggleClass instead of add/removeClass?

Absolutely. Thanks for educating me.

Revision history for this message
William Grant (wgrant) wrote :

Looks much better, thanks. A couple of remaining niggles:

 - Can you merge the two visible_render_time sections in base-layout.pt?
 - I think your JS XHTML construction could be a little cleaner still. I've pushed up some suggestions to lp:~wgrant/launchpad/ajax-time.

review: Approve (code*)
Revision history for this message
Huw Wilkins (huwshimi) wrote :

> - Can you merge the two visible_render_time sections in base-layout.pt?
> - I think your JS XHTML construction could be a little cleaner still. I've
> pushed up some suggestions to lp:~wgrant/launchpad/ajax-time.

Done and done.

Revision history for this message
Robert Collins (lifeless) wrote :

/* Maximum amount of time we want AJAX requests to take, in seconds.

-> perhaps 'requests slower than this are marked as 'slow''. Also suggest s/MAX/OK/ or similar - its not a cap on the duration the request takes, but a threshold for reporting.

This is kindof trivial, but likely to confuse, I think.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/canonical/launchpad/icing/style-3-0.css'
--- lib/canonical/launchpad/icing/style-3-0.css 2011-03-29 07:24:43 +0000
+++ lib/canonical/launchpad/icing/style-3-0.css 2011-03-30 06:26:31 +0000
@@ -1102,7 +1102,7 @@
1102 font-size: 12px;1102 font-size: 12px;
1103 text-decoration: underline;1103 text-decoration: underline;
1104 }1104 }
1105.unseen {1105.unseen, .hidden {
1106 display: none;1106 display: none;
1107 }1107 }
1108.invisible-link {1108.invisible-link {
@@ -1169,10 +1169,46 @@
1169 }1169 }
1170#rendertime {1170#rendertime {
1171 float: left;1171 float: left;
1172 margin: 0.2em 1.2em 0 0;1172 margin: 0.1em 1.2em 0 0;
1173 color: #666;1173 color: #666;
1174 font-size: 10px;1174 font-size: 10px;
1175 }1175 }
1176#ajax-time {
1177 float: left;
1178 margin: 0 1.2em 0 0.2em;
1179 position: relative;
1180 }
1181#ajax-time-list {
1182 position: absolute;
1183 z-index: 10;
1184 top: 20px;
1185 right: 0;
1186 width: 200px;
1187 background-color: #f2f2f2;
1188 border: 2px solid #fff;
1189 -moz-box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
1190 -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
1191 box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
1192 -webkit-border-radius: 4px;
1193 -moz-border-radius: 4px;
1194 border-radius: 4px;
1195 }
1196#ajax-time-list li {
1197 border-bottom: 1px solid #e0e0e0;
1198 padding: 3px 5px;
1199 }
1200#ajax-time-list li:last-child {
1201 border-bottom: none;
1202 }
1203#ajax-time-list li span {
1204 color: #999;
1205 font-size: 11px;
1206 display: block;
1207 }
1208#ajax-time-list strong.warning {
1209 color: #f00;
1210 background-color: transparent;
1211 }
1176div.watermark-apps-portlet {1212div.watermark-apps-portlet {
1177 clear: both;1213 clear: both;
1178 margin-bottom: .5em;1214 margin-bottom: .5em;
11791215
=== modified file 'lib/canonical/launchpad/templates/launchpad-loginstatus.pt'
--- lib/canonical/launchpad/templates/launchpad-loginstatus.pt 2011-02-07 07:39:36 +0000
+++ lib/canonical/launchpad/templates/launchpad-loginstatus.pt 2011-03-30 06:26:31 +0000
@@ -9,7 +9,13 @@
9<div id="logincontrol" tal:condition="view/logged_in">9<div id="logincontrol" tal:condition="view/logged_in">
10 <form action="+logout" method="post">10 <form action="+logout" method="post">
11 <input type="hidden" name="loggingout" value="1" />11 <input type="hidden" name="loggingout" value="1" />
12 <div id="rendertime" tal:condition="request/features/visible_render_time">Loading... &bull;</div>12 <div id="rendertime" tal:condition="request/features/visible_render_time">Loading...</div>
13 <div id="ajax-time" tal:condition="request/features/visible_render_time">
14 <a href="" class="js-action">AJAX Log &darr;</a>
15 <ul id="ajax-time-list" class="hidden">
16 <li class="no-events">No AJAX events detected</li>
17 </ul>
18 </div>
13 <a tal:replace="structure request/lp:person/fmt:name_link" /> &bull;19 <a tal:replace="structure request/lp:person/fmt:name_link" /> &bull;
14 <input type="submit" name="logout" value="Log Out" />20 <input type="submit" name="logout" value="Log Out" />
15 </form>21 </form>
1622
=== added file 'lib/lp/app/javascript/ajax_log.js'
--- lib/lp/app/javascript/ajax_log.js 1970-01-01 00:00:00 +0000
+++ lib/lp/app/javascript/ajax_log.js 2011-03-30 06:26:31 +0000
@@ -0,0 +1,85 @@
1/* Log time taken for AJAX requests.
2*/
3function start_ajax_logging() {
4 /* Requests slower than this are marked as slow. Value in seconds.
5 */
6 var AJAX_OK_TIME = 1;
7
8 LPS.use('node', 'lazr.anim', function(Y) {
9 Y.on('contentready', function() {
10 var node = Y.one('#ajax-time-list');
11 var ajax_request_times = {};
12 var ajax_menu_animating = false;
13 var flash_menu = Y.lazr.anim.green_flash({node:'#ajax-time'});
14 flash_menu.on('end', function() {
15 ajax_menu_animating = false;
16 });
17 /* When an AJAX event starts, record the time.
18 */
19 Y.on('io:start', function(transactionid) {
20 var now = new Date();
21 ajax_request_times[transactionid] = now;
22 });
23 /* When an AJAX event finishes add it to the log.
24 */
25 Y.on('io:complete', function(transactionid, arguments) {
26 /* The AJAX event has finished so record the time.
27 */
28 var finish_time = new Date();
29 /* Remove the initial message in the log.
30 */
31 Y.all('#ajax-time-list li.no-events').remove();
32 if (ajax_request_times[transactionid]) {
33 var start_time = ajax_request_times[transactionid];
34 /* The time take for the AJAX event, in seconds.
35 */
36 var time_taken = (finish_time - start_time)/1000;
37 var log_node = Y.Node.create(
38 '<li>Time: <strong></strong><span></span></li>');
39 log_node.addClass('transaction-' + transactionid);
40 log_node.one('strong').set(
41 'text', time_taken.toFixed(2) + ' seconds');
42 /* If the AJAX event takes longer than AJAX_OK_TIME
43 then add a warning.
44 */
45 if (time_taken > AJAX_OK_TIME) {
46 log_node.one('strong').addClass('warning');
47 }
48 log_node.one('span').set(
49 'text',
50 'ID: ' + transactionid +
51 ', status: ' + arguments.status +
52 ' (' + arguments.statusText + ')');
53 var oops = arguments.getResponseHeader('X-Lazr-OopsId');
54 if (oops) {
55 var oops_node = Y.Node.create('<a/>');
56 oops_node.setAttribute(
57 'href', 'http://pad.lv/' + oops);
58 oops_node.set('text', oops);
59 log_node.one('span').append(', OOPS ID:&nbsp;');
60 log_node.one('span').append(oops_node);
61 }
62 node.prepend(log_node);
63 /* Highlight the new entry in the log.
64 */
65 Y.lazr.anim.green_flash({
66 node: '#ajax-time-list li.transaction-'+transactionid
67 }).run();
68 /* Signify a new entry has been added to the log.
69 */
70 if (ajax_menu_animating == false) {
71 flash_menu.run();
72 ajax_menu_animating = true;
73 }
74 }
75 });
76
77 /* Open/close the log.
78 */
79 Y.on('click', function(e) {
80 e.halt();
81 Y.one('#ajax-time-list').toggleClass('hidden');
82 }, '#ajax-time a');
83 }, '#ajax-time');
84 });
85}
086
=== modified file 'lib/lp/app/templates/base-layout.pt'
--- lib/lp/app/templates/base-layout.pt 2011-02-28 06:28:16 +0000
+++ lib/lp/app/templates/base-layout.pt 2011-03-30 06:26:31 +0000
@@ -191,7 +191,8 @@
191 tal:condition="request/features/visible_render_time"191 tal:condition="request/features/visible_render_time"
192 define="render_time modules/canonical.launchpad.webapp.adapter/summarize_requests;"192 define="render_time modules/canonical.launchpad.webapp.adapter/summarize_requests;"
193 replace='structure string:&lt;script type="text/javascript"&gt;193 replace='structure string:&lt;script type="text/javascript"&gt;
194 var render_time = "${render_time} &amp;bull;";194 start_ajax_logging();
195 var render_time = "${render_time}";
195 LPS.use("node", function(Y) {196 LPS.use("node", function(Y) {
196 Y.on("domready", function() {197 Y.on("domready", function() {
197 var node = Y.one("#rendertime");198 var node = Y.one("#rendertime");