-
Notifications
You must be signed in to change notification settings - Fork 1
/
kalogs.user.js
168 lines (149 loc) · 5.28 KB
/
kalogs.user.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
// ==UserScript==
// @match https://appengine.google.com/logs*
// ==/UserScript==
/**
* @fileoverview Custom tweaks to Google App Engine logs as viewed in their
* web UI to make some things stand out more, and clean up some noise.
*
* @author Ben Komalo (benkomalo@gmail.com)
*/
var $ = function(s, node) {
return (node || document).querySelector(s);
};
var $$ = function(s, node) {
return (node || document).querySelectorAll(s);
};
var forEach = function(s, nodeOrFunc, node) {
var handler;
if (typeof nodeOrFunc === 'function') {
handler = nodeOrFunc;
node = node || document;
} else {
handler = node;
node = nodeOrFunc;
}
var list = $$(s, node);
for (var i = 0, el; el = list[i]; i++) {
handler(el);
}
};
/**
* A flag to indicate we're modifying the DOM from our own fixes.
* This prevents infinite loops, since we want to re-apply the fixes
* everytime the DOM changes.
*/
var fixing = false;
var applyFixes = function() {
if (fixing) {
return;
}
fixing = true;
// TODO(benkomalo): a lot of these can be done by applying a class and
// injecting CSS instead. Oh well.
// Highlight any internal error codes.
var statusCss = 'font-weight: bold;' +
'font-size: 16px;' +
'margin: 0 8px;';
forEach('.ae-logs-reqlog span[title=\'Status\']', function(statusBox) {
if (statusBox.innerText === '500') {
statusBox.style.cssText = 'color:red;' + statusCss;
} else {
statusBox.style.cssText = statusCss;
}
});
// Supress all DEBUG lines that are part of the event logger.
forEach('.ae-logs-applog span[title=\'Logging Severity: Debug\']',
function(severity) {
var line = $('span.snippet', severity.parentNode).innerText;
if (line.indexOf('KALOG;') === 0) {
severity.parentNode.style.display = 'none';
}
});
// Suppress all response sizes.
forEach('.ae-logs-reqlog span[title=\'Response Size\']', function(el) {
el.style.visibility = 'hidden';
});
// Color response times
forEach('.ae-logs-reqlog span[title=\'Request Time/Latency\']',
function(el) {
var msTime = Number(el.innerText.slice(0, -2)),
color;
if (msTime < 500) {
color = 'green';
} else if (msTime < 1000) {
color = 'orange';
} else {
color = 'red';
}
el.style.color = color;
});
// Simplify datetime stamps.
forEach('.ae-logs-reqlog h5 > span:first-child', function(el) {
var datetimeStr = el.innerText;
var datetime = datetimeStr.split(' ');
if (datetime.length !== 2) {
return;
}
var time = datetime[1];
el.setAttribute('title', datetimeStr);
el.innerText = time.split('.')[0];
el.style.fontFamily = 'Courier, monospace';
el.style.fontSize = '14px';
});
forEach('.ae-logs-applog h5 > span:nth-child(2)', function(el) {
// The timestamps for individual log lines aren't that useful in
// collapsed mode, since the header line has a timestamp.
// We probably want to show it in expanded mode, though.
var entryParent = el.parentNode.parentNode.parentNode.parentNode;
if (entryParent.className.indexOf('ae-log-expanded') === -1) {
el.style.display = 'none';
}
});
// Simplify user agents.
var collapseUserAgent = function(el, simplified) {
var title = el.innerText;
el.setAttribute('title', title);
el.innerText = simplified;
};
forEach('.ae-logs-reqlog span[title=\'User Agent\']', function(el) {
var contents = el.innerText;
if (contents.indexOf('AppEngine-Google;') === 0) {
collapseUserAgent(el, 'GAE Internal');
} else if (contents.indexOf('iPad') > -1) {
collapseUserAgent(el, 'iPad');
} else if (contents.indexOf('Chrome/') > -1) {
// TODO: care about Chrome mobile?
collapseUserAgent(el, 'Chrome');
}
var match;
if (match = /MSIE\s+([^;]*);/.exec(contents)) {
collapseUserAgent(el, 'IE ' + match[1]);
} else if (match = /Firefox\/([^\s]*)/.exec(contents)) {
collapseUserAgent(el, 'Firefox ' + match[1]);
} else if (match = /Version\/([^\s]*) Safari\//.exec(contents)) {
collapseUserAgent(el, 'Safari ' + match[1]);
} else if (match = /Android ([^;]*);/.exec(contents)) {
// TODO: distinguish between Android browsers
collapseUserAgent(el, 'Android ' + match[1]);
}
});
window.setTimeout(function() {
fixing = false;
}, 1000);
};
var init = function() {
applyFixes();
// Navigation or additional filters in the logs web UI modify the internal
// DOM structure instead of does full page loads. We listen for them
// here so we can re-apply the changes we want.
var observer = new WebKitMutationObserver(function(mutations) {
if (!fixing) {
window.setTimeout(applyFixes, 0);
}
});
observer.observe($('#ae-logs'), {
subtree: true,
attributes: true
});
};
init();