├── .gitignore
├── assets
├── bold.png
├── logo_640x640.png
├── screen1_1280x800.png
├── screen2_1280x800.png
├── screen3_1280x800.png
├── screen4_1280x800.png
├── screen5_1280x800.png
├── screen_banner_1400x560.png
├── screen_banner_440x280.png
└── screen_banner_920x680.png
├── img
├── logo_128.png
├── logo_16.png
├── logo_32.png
└── logo_64.png
├── manifest.json
├── hello.html
├── LICENSE
├── DetailedDescription.md
├── README.md
├── colorize.js
└── lib
└── ansi_up.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .history
2 | archieve
3 | *.zip
4 | .idea
5 |
--------------------------------------------------------------------------------
/assets/bold.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ilhan-mstf/colorize_cloudwatch_logs/HEAD/assets/bold.png
--------------------------------------------------------------------------------
/img/logo_128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ilhan-mstf/colorize_cloudwatch_logs/HEAD/img/logo_128.png
--------------------------------------------------------------------------------
/img/logo_16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ilhan-mstf/colorize_cloudwatch_logs/HEAD/img/logo_16.png
--------------------------------------------------------------------------------
/img/logo_32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ilhan-mstf/colorize_cloudwatch_logs/HEAD/img/logo_32.png
--------------------------------------------------------------------------------
/img/logo_64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ilhan-mstf/colorize_cloudwatch_logs/HEAD/img/logo_64.png
--------------------------------------------------------------------------------
/assets/logo_640x640.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ilhan-mstf/colorize_cloudwatch_logs/HEAD/assets/logo_640x640.png
--------------------------------------------------------------------------------
/assets/screen1_1280x800.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ilhan-mstf/colorize_cloudwatch_logs/HEAD/assets/screen1_1280x800.png
--------------------------------------------------------------------------------
/assets/screen2_1280x800.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ilhan-mstf/colorize_cloudwatch_logs/HEAD/assets/screen2_1280x800.png
--------------------------------------------------------------------------------
/assets/screen3_1280x800.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ilhan-mstf/colorize_cloudwatch_logs/HEAD/assets/screen3_1280x800.png
--------------------------------------------------------------------------------
/assets/screen4_1280x800.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ilhan-mstf/colorize_cloudwatch_logs/HEAD/assets/screen4_1280x800.png
--------------------------------------------------------------------------------
/assets/screen5_1280x800.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ilhan-mstf/colorize_cloudwatch_logs/HEAD/assets/screen5_1280x800.png
--------------------------------------------------------------------------------
/assets/screen_banner_1400x560.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ilhan-mstf/colorize_cloudwatch_logs/HEAD/assets/screen_banner_1400x560.png
--------------------------------------------------------------------------------
/assets/screen_banner_440x280.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ilhan-mstf/colorize_cloudwatch_logs/HEAD/assets/screen_banner_440x280.png
--------------------------------------------------------------------------------
/assets/screen_banner_920x680.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ilhan-mstf/colorize_cloudwatch_logs/HEAD/assets/screen_banner_920x680.png
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Colorize AWS CloudWatch Logs",
3 | "description" : "Group logs visually on AWS CloudWatch",
4 | "version": "0.5.1",
5 | "homepage_url": "https://github.com/ilhan-mstf/colorize_cloudwatch_logs",
6 | "manifest_version": 2,
7 | "icons": {
8 | "16": "img/logo_16.png",
9 | "32": "img/logo_32.png",
10 | "64": "img/logo_64.png",
11 | "128": "img/logo_128.png"
12 | },
13 | "browser_action": {
14 | "default_popup": "hello.html",
15 | "default_icon": "img/logo_16.png"
16 | },
17 | "content_scripts": [{
18 | "matches": [
19 | "https://*.console.aws.amazon.com/cloudwatch/*"
20 | ],
21 | "js": [
22 | "lib/ansi_up.js",
23 | "colorize.js"
24 | ]
25 | }]
26 | }
27 |
--------------------------------------------------------------------------------
/hello.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
14 | Colorize CloudWatch Logs
15 | Group logs visually on AWS CloudWatch
16 | This extension adds background color to boundaries of AWS Lambda logs, changes text color of lines having ANSI terminal codes and makes bold "REPORT", "[ERROR]" and "[Error " logs.
17 | There is a shortcut for fullscreen.
18 | If you enable "Follow tail", it refreshes the logs periodically to load new items.
19 | This extension doesn't collect any user and web page information. It only runs on AWS CloudWatch Logs web page. It is free to use.
20 | Github project
21 | v0.5.1
22 |
23 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) 2018 Mustafa İlhan
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/DetailedDescription.md:
--------------------------------------------------------------------------------
1 | The purpose of this extension is to group logs visually on AWS CloudWatch. There are three rules:
2 | - Set a different background color for each log group of AWS Lambda invocation. Therefore, you can easily recognize beginning, body and end of the logs of the same invocation.
3 | - Set font weight of lines having `REPORT`, `[ERROR]` and `[Error ` keywords to bold.
4 | - Set text color of ANSI terminal codes in the logs. (by https://github.com/oguimbal)
5 |
6 | Further, there is two functionality for better log viewing experience (by https://github.com/oguimbal):
7 | - Switching to fullscreen,
8 | - Refreshing the logs periodically to load new items.
9 |
10 | This extension doesn't collect any user and web page information. It only runs on AWS CloudWatch Logs web page. It is free to use.
11 |
12 | Overhead is very low, colorize operation takes ~7 milliseconds, listen operation for new event logs takes just ~0.5 milliseconds in every second.
13 |
14 | Contributions are welcome. To contribute please visit project page: https://github.com/ilhan-mstf/colorize_cloudwatch_logs
15 |
16 | Release Log:
17 | --------------------
18 | Version 0.5.1:
19 | - Enable font override on new ui
20 |
21 | Version 0.5.0:
22 | - Handle new ui
23 | - Case insensitive error line search
24 |
25 | Version 0.4.11:
26 | - Add `[Error ` as a special line to make it bold
27 | - Add "Fullscreen" and "Follow tail" buttons
28 |
29 | Version 0.3.8:
30 | - Set text color of ANSI terminal codes
31 | - Update extension logo
32 | - Improve performance
33 |
34 | Version 0.2.1:
35 | - Make bold font weight of `REPORT` and `[ERROR]` lines
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Colorize CloudWatch Logs
2 | ========================
3 |
4 | This is a Google Chrome extension. You can install this extension by this address: [Chrome Web Store](https://chrome.google.com/webstore/detail/colorize-cloudwatch-logs/fkagnmcbeokmapmcbecbcmpccmlbhkpl).
5 |
6 | The purpose of this extension is to group logs visually on AWS CloudWatch. There are three rules:
7 | - Set a different background color for each log group of AWS Lambda invocation. Therefore, you can easily recognize beginning, body and end of the logs of the same invocation.
8 | 
9 | - Set font wieght of lines having `REPORT`, `[ERROR]` and `[Error ` keywords to bold.
10 | 
11 | - Set color of ANSI terminal codes in the logs. (by [@oguimbal](https://github.com/oguimbal))
12 | 
13 |
14 | Further, there is two functionality for better log viewing experience (by [@oguimbal](https://github.com/oguimbal)):
15 | - Switching to fullscreen,
16 | - Refreshing the logs periodically to load new items.
17 | 
18 |
19 | This extension doesn't collect any user and web page information. It only runs on AWS CloudWatch Logs web page. It is free to use.
20 |
21 | Overhead is very low, colorize operation takes ~7 milliseconds, listen operation for new event logs takes just ~0.5 milliseconds in every second.
22 |
23 | ### Contributions
24 | Contributions are welcome. Please follow the standart.js convention if you want to contribute.
25 |
26 | ### Contributors
27 | - [@oguimbal](https://github.com/oguimbal)
28 | - [@svikrant2014](https://github.com/svikrant2014)
29 | - [@ktwbc](https://github.com/ktwbc)
30 |
31 | ### Open Source
32 | - [ansi_up.js](http://github.com/drudru/ansi_up)
--------------------------------------------------------------------------------
/colorize.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * License: MIT
3 | * Author: Mustafa İlhan, http://ilhan-mstf.github.io/
4 | * Contributors:
5 | * - Olivier Guimbal, https://github.com/oguimbal
6 | * - Vikrant Sharma, https://github.com/svikrant2014
7 | * - Kris Thom White, https://github.com/ktwbc
8 | */
9 |
10 | 'use strict'
11 |
12 | /* global AnsiUp, localStorage */
13 |
14 | const colors = ["#F9DBBD", "#CDC7E5", "#F6A5A2", "#FFF399", "#C4F4C7", "#E8E1EF", "#D9FFF8", "#ADFFE5", "#E6DBD0", "#C7FFDA", "#FCA17D", "#FCD0A1", "#FAFFD8", "#A3F7B5", "#D8B4E2"]
15 |
16 | const ansiTransform = new AnsiUp()
17 | delete window.AnsiUp // just delete it so its hidden from global space
18 |
19 | function insertStylesheet () {
20 | // dont know why, but all "spans" that are insterted in cwdb-ellipsis are blinking
21 | // this class prevents that from happening
22 | const style = document.createElement('style')
23 | style.textContent = `
24 | .ansiColorized span {
25 | -webkit-animation-name: unset !important;
26 | -moz-animation-name: unset !important;
27 | -ms-animation-name: unset !important;
28 | animation-name: unset !important;
29 | }
30 |
31 | /* The container */
32 | .container-checkbox {
33 | display: block;
34 | position: relative;
35 | padding-left: 20px;
36 | cursor: pointer;
37 | font-size: 13px;
38 | -webkit-user-select: none;
39 | -moz-user-select: none;
40 | -ms-user-select: none;
41 | user-select: none;
42 | }
43 |
44 | /* Hide the browser's default checkbox */
45 | .container-checkbox input {
46 | position: absolute;
47 | opacity: 0;
48 | cursor: pointer;
49 | }
50 |
51 | /* Create a custom checkbox */
52 | .container-checkbox .checkmark {
53 | position: absolute;
54 | top: 0;
55 | left: 0;
56 | height: 16px;
57 | width: 16px;
58 | background-color: #eee;
59 | }
60 |
61 | /* On mouse-over, add a grey background color */
62 | .container-checkbox:hover input ~ .checkmark {
63 | background-color: #ccc;
64 | }
65 |
66 | /* When the checkbox is checked, add a blue background */
67 | .container-checkbox input:checked ~ .checkmark {
68 | background-color: #2196F3;
69 | }
70 |
71 | /* Create the checkmark/indicator (hidden when not checked) */
72 | .container-checkbox .checkmark:after {
73 | content: "";
74 | position: absolute;
75 | display: none;
76 | }
77 |
78 | /* Show the checkmark when checked */
79 | .container-checkbox input:checked ~ .checkmark:after {
80 | display: block;
81 | }
82 |
83 | /* Style the checkmark/indicator */
84 | .container-checkbox .checkmark:after {
85 | left: 4px;
86 | top: 0px;
87 | width: 5px;
88 | height: 10px;
89 | border: solid white;
90 | border-width: 0 3px 3px 0;
91 | -webkit-transform: rotate(45deg);
92 | -ms-transform: rotate(45deg);
93 | transform: rotate(45deg);
94 | }
95 |
96 | #logs-tweaker-panel {
97 | position: fixed;
98 | z-index: 1000000;
99 | bottom: 30px;
100 | right: 20px;
101 | background: white;
102 | border-radius: 4px;
103 | box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23);
104 | padding: 5px;
105 | }
106 |
107 | .cwdb-log-viewer-table-container.fullscreen .cwdb-log-viewer-table-body {
108 | position: fixed;
109 | background: white;
110 | margin-top: 0;
111 | top: 40px;
112 | left: 0;
113 | bottom: 0;
114 | right: 0;
115 | height: unset;
116 | }
117 |
118 | .logs__log-events-table__cell {
119 | font-family: "Helvetica Neue", Roboto, Arial, sans-serif;
120 | font-size: 14px;
121 | }
122 |
123 | .logs__log-events-table__cursor-text {
124 | font-family: "Helvetica Neue", Roboto, Arial, sans-serif;
125 | font-size: 14px;
126 | }
127 |
128 | .logs__log-events-table__timestamp-cell {
129 | font-family: "Helvetica Neue", Roboto, Arial, sans-serif;
130 | font-size: 14px;
131 | }
132 |
133 | `
134 | document.head.appendChild(style)
135 | }
136 |
137 | function insertTools () {
138 | const panel = document.createElement('div')
139 | let panelHtml = ``
140 | if (isNewDesign()) {
141 | panelHtml = `${ panelHtml }
142 | Replace Fonts
143 |
144 |
145 |
146 | `
147 | } else {
148 | panelHtml = `${ panelHtml }
149 | Fullscreen
150 |
151 |
152 |
153 | Follow tail
154 |
155 |
156 |
157 | `
158 | }
159 |
160 | panel.innerHTML = panelHtml + '
'
161 | document.body.append(panel)
162 |
163 | if (isNewDesign()) {
164 | setupNewToggles()
165 | } else {
166 | setupOldToggles()
167 | }
168 | }
169 |
170 | function setupOldToggles () {
171 | // toggle fullscreen
172 | document.getElementById('logs-tweaker-fullscreen').onchange = t => {
173 | const { checked } = t.target
174 | if (checked) {
175 | localStorage.setItem('logs-tweaker-fullscreen', 'yes')
176 | } else {
177 | localStorage.removeItem('logs-tweaker-fullscreen')
178 | }
179 | refreshFullscreen()
180 | }
181 |
182 | // toggle auto refresh
183 | document.getElementById('logs-tweaker-autorefresh').onchange = t => {
184 | const { checked } = t.target
185 | if (checked) {
186 | localStorage.setItem('logs-tweaker-autorefresh', 'yes')
187 | } else {
188 | localStorage.removeItem('logs-tweaker-autorefresh')
189 | }
190 | refreshAutoRefresh()
191 | }
192 |
193 | }
194 |
195 | function setupNewToggles () {
196 | // toggle replace fonts
197 | document.getElementById('logs-tweaker-fonts').onchange = t => {
198 | const { checked } = t.target
199 | if (checked) {
200 | localStorage.setItem('logs-tweaker-fonts', 'yes')
201 | } else {
202 | localStorage.removeItem('logs-tweaker-fonts')
203 | }
204 | refreshFonts()
205 | }
206 | }
207 |
208 | function removeTools () {
209 | const element = document.getElementById('logs-tweaker-panel')
210 | if (element) {
211 | element.parentNode.removeChild(element)
212 | }
213 | }
214 |
215 | // add "auto refresh" & "fullscreen"
216 | setInterval(() => {
217 | if (window.location.hash.includes('#logEventViewer') || isNewDesign()) {
218 | if (!isNewDesign()) {
219 | refreshOldDesign()
220 | } else {
221 | refreshNewDesign()
222 | }
223 | if (document.getElementById('logs-tweaker-panel')) {
224 | return
225 | }
226 | insertStylesheet()
227 | insertTools()
228 | } else {
229 | removeTools()
230 | }
231 | }, 1000)
232 |
233 | function refreshOldDesign () {
234 | refreshAutoRefresh()
235 | refreshFullscreen()
236 | }
237 |
238 | function refreshNewDesign () {
239 | refreshAutoRefresh()
240 | refreshFullscreen()
241 | }
242 |
243 | function fullscreenOn () {
244 | return !!localStorage.getItem('logs-tweaker-fullscreen')
245 | }
246 |
247 | function fontsOn () {
248 | return !!localStorage.getItem('logs-tweaker-fonts')
249 | }
250 |
251 | function refreshFullscreen () {
252 | const elt = document.getElementsByClassName('cwdb-log-viewer-table-container')[0]
253 | if (!elt) {
254 | return
255 | }
256 | if (fullscreenOn()) {
257 | if (!elt.classList.contains('fullscreen')) {
258 | elt.classList.add('fullscreen')
259 | }
260 | } else {
261 | elt.classList.remove('fullscreen')
262 | }
263 | }
264 |
265 | function autorefreshOn () {
266 | return !!localStorage.getItem('logs-tweaker-autorefresh')
267 | }
268 |
269 | let autorefreshInterval = null
270 |
271 | function refreshAutoRefresh () {
272 | if (autorefreshOn()) {
273 | if (!autorefreshInterval) {
274 | autorefreshInterval = setInterval(refreshTail, 3000)
275 | refreshTail()
276 | }
277 | } else {
278 | clearInterval(autorefreshInterval)
279 | autorefreshInterval = null
280 | }
281 | }
282 |
283 | function refreshFonts () {
284 | const elements = getElements()
285 | elements.forEach(element => changeFontElement(element, fontsOn() ? 'set' : 'clear'))
286 | }
287 |
288 | function refreshTail () {
289 | const refresh = document.getElementsByClassName('cwdb-log-viewer-table-infinite-loader-bottom')[0]
290 | if (!refresh) {
291 | return
292 | }
293 | let a = refresh.firstElementChild
294 | while (a && a.tagName !== 'A') {
295 | a = a.nextElementSibling
296 | }
297 | if (a) {
298 | a.click()
299 | // scroll to bottom
300 | const div = document.getElementsByClassName('cwdb-log-viewer-table-body')[0]
301 | if (div) {
302 | div.scrollTop = div.scrollHeight
303 | }
304 | }
305 | }
306 |
307 | function isCheckedForDecorated (element) {
308 | return element.dataset.checkedForDecorated !== 'yes'
309 | }
310 |
311 | function setCheckedForDecorated (element) {
312 | element.dataset.checkedForDecorated = 'yes'
313 | return element
314 | }
315 |
316 | function isCheckedForBold (element) {
317 | return element.dataset.checkedForBold !== 'yes'
318 | }
319 |
320 | function setCheckedForBold (element) {
321 | element.dataset.checkedForBold = 'yes'
322 | return element
323 | }
324 |
325 | function isStartLine (element) {
326 | return element.innerHTML.includes('START RequestId:')
327 | }
328 |
329 | function isEndLine (element) {
330 | return element.innerHTML.includes('REPORT RequestId:')
331 | }
332 |
333 | function isErrorLine (element) {
334 | const text = element.innerHTML.toLowerCase()
335 | return text.includes('error')
336 | }
337 |
338 | function isErrorOrEndLine (element) {
339 | return isErrorLine(element) || isEndLine(element)
340 | }
341 |
342 | function isStartOrEnd (element) {
343 | return isStartLine(element) || isEndLine(element)
344 | }
345 |
346 | function hasId (element, id) {
347 | return element.innerHTML.includes(id)
348 | }
349 |
350 | function colorizeElement (element, color) {
351 | element.style.backgroundColor = color
352 | return element
353 | }
354 |
355 | function changeFontElement (element, action) {
356 | if (element.dataset.isFontHandled !== 'yes' || action) {
357 | element.dataset.isFontHandled = 'yes'
358 | element.height = '20px'
359 | element.lineHeight = '20px'
360 |
361 | let subElements = element.getElementsByClassName('logs__log-events-table__cell')
362 | for (let e of subElements) {
363 | if (action === 'clear') {
364 | e.style.fontFamily = null;
365 | e.style.fontSize = null;
366 | e.style.paddingLeft = null;
367 | } else {
368 | e.style.fontFamily = '"Helvetica Neue", Roboto, Arial, sans-serif'
369 | e.style.fontSize = '0.9em'
370 | e.style.paddingLeft = '5px'
371 | }
372 | }
373 | }
374 | return element
375 | }
376 |
377 | function makeBoldElement (element) {
378 | element.style.fontWeight = 600
379 | return element
380 | }
381 |
382 | function makeBold (elements) {
383 | elements
384 | .filter(isCheckedForBold)
385 | .map(setCheckedForBold)
386 | .filter(isErrorOrEndLine)
387 | .forEach(makeBoldElement)
388 | }
389 |
390 | function getEventId (element) {
391 | return element
392 | .innerHTML
393 | .replace(/\n/g, ' ')
394 | .match(/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/g)[0]
395 | }
396 |
397 | function getUniqueEventIds (eventIds) {
398 | return Array.from(
399 | new Set(
400 | eventIds
401 | .filter(isCheckedForDecorated)
402 | .map(setCheckedForDecorated)
403 | .filter(isStartOrEnd)
404 | .map(getEventId)))
405 | }
406 |
407 | function changeFontOnGroup (elements) {
408 | elements.forEach(changeFontElement)
409 | }
410 |
411 | function colorizeGroup (elements) {
412 | let color = colors[Math.floor((Math.random() * 10000)) % colors.length]
413 | elements.forEach(element => colorizeElement(element, color))
414 | }
415 |
416 | function decorateGroups (elements) {
417 | let eventIds = getUniqueEventIds(elements)
418 | let newDesign = isNewDesign()
419 | if (eventIds) {
420 | eventIds.forEach(
421 | id => {
422 | colorizeGroup(elements.filter(element => hasId(element, id)))
423 | if (newDesign && fontsOn()) changeFontOnGroup(elements)
424 | })
425 | }
426 | }
427 |
428 | function applyAnsiTransform (e) {
429 | if (e) {
430 | const txt = e.childNodes[0]
431 | const textValue = txt.textContent || ''
432 | if (/(^|\x1b)\[(\d+)m/.test(textValue)) {
433 | e.classList.add('ansiColorized')
434 | e.innerHTML = ansiTransform.ansi_to_html(textValue)
435 | }
436 | }
437 | }
438 |
439 | function colorizeAnsi (elements) {
440 | for (let e of elements) {
441 | if (e.dataset.isAnsiColorizedHandled !== 'yes') {
442 | e.dataset.isAnsiColorizedHandled = 'yes'
443 | applyAnsiTransform(e.getElementsByClassName("logs__log-events-table__cell")[1])
444 | }
445 | }
446 | }
447 |
448 | function getElements () {
449 | let elements
450 |
451 | const newDesignElements = document.querySelectorAll('iframe#microConsole-Logs')[0]
452 |
453 | if (newDesignElements) {
454 | elements = newDesignElements.contentDocument.getElementsByClassName('awsui-table-row')
455 | } else {
456 | elements = document.getElementsByClassName('cwdb-ellipsis')
457 | }
458 |
459 | return [].slice.call(elements)
460 | }
461 |
462 | function isNewDesign () {
463 | return window.location.hash.includes('#logsV2:log-groups/log-group') && window.location.hash.includes('/log-events')
464 | }
465 |
466 | function colorizeAll () {
467 | // console.time('cost-of-colorize')
468 | // console.time('cost-of-getting-elements')
469 | const elements = getElements()
470 | // console.timeEnd('cost-of-getting-elements')
471 |
472 | // console.time('cost-of-colorize-groups')
473 | decorateGroups(elements)
474 | // console.timeEnd('cost-of-colorize-groups')
475 |
476 | // console.time('cost-of-colorize-ansi')
477 | colorizeAnsi(elements)
478 | // console.timeEnd('cost-of-colorize-ansi')
479 |
480 | // console.time('cost-of-bold')
481 | makeBold(elements)
482 | // console.timeEnd('cost-of-bold')
483 | // console.timeEnd('cost-of-colorize')
484 | }
485 |
486 | setInterval(colorizeAll, 1000)
487 |
--------------------------------------------------------------------------------
/lib/ansi_up.js:
--------------------------------------------------------------------------------
1 | /* ansi_up.js
2 | * author : Dru Nelson
3 | * license : MIT
4 | * http://github.com/drudru/ansi_up
5 | */
6 | (function (root, factory) {
7 | if (typeof define === 'function' && define.amd) {
8 | // AMD. Register as an anonymous module.
9 | define(['exports'], factory);
10 | } else if (typeof exports === 'object' && typeof exports.nodeName !== 'string') {
11 | // CommonJS
12 | factory(exports);
13 | } else {
14 | // Browser globals
15 | var exp = {};
16 | factory(exp);
17 | root.AnsiUp = exp.default;
18 | }
19 | }(this, function (exports) {
20 | "use strict";
21 | var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
22 | if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
23 | return cooked;
24 | };
25 | var PacketKind;
26 | (function (PacketKind) {
27 | PacketKind[PacketKind["EOS"] = 0] = "EOS";
28 | PacketKind[PacketKind["Text"] = 1] = "Text";
29 | PacketKind[PacketKind["Incomplete"] = 2] = "Incomplete";
30 | PacketKind[PacketKind["ESC"] = 3] = "ESC";
31 | PacketKind[PacketKind["Unknown"] = 4] = "Unknown";
32 | PacketKind[PacketKind["SGR"] = 5] = "SGR";
33 | PacketKind[PacketKind["OSCURL"] = 6] = "OSCURL";
34 | })(PacketKind || (PacketKind = {}));
35 | var AnsiUp = (function () {
36 | function AnsiUp() {
37 | this.VERSION = "4.0.3";
38 | this.setup_palettes();
39 | this._use_classes = false;
40 | this._escape_for_html = true;
41 | this.bold = false;
42 | this.fg = this.bg = null;
43 | this._buffer = '';
44 | this._url_whitelist = { 'http': 1, 'https': 1 };
45 | }
46 | Object.defineProperty(AnsiUp.prototype, "use_classes", {
47 | get: function () {
48 | return this._use_classes;
49 | },
50 | set: function (arg) {
51 | this._use_classes = arg;
52 | },
53 | enumerable: true,
54 | configurable: true
55 | });
56 | Object.defineProperty(AnsiUp.prototype, "escape_for_html", {
57 | get: function () {
58 | return this._escape_for_html;
59 | },
60 | set: function (arg) {
61 | this._escape_for_html = arg;
62 | },
63 | enumerable: true,
64 | configurable: true
65 | });
66 | Object.defineProperty(AnsiUp.prototype, "url_whitelist", {
67 | get: function () {
68 | return this._url_whitelist;
69 | },
70 | set: function (arg) {
71 | this._url_whitelist = arg;
72 | },
73 | enumerable: true,
74 | configurable: true
75 | });
76 | AnsiUp.prototype.setup_palettes = function () {
77 | var _this = this;
78 | this.ansi_colors =
79 | [
80 | [
81 | { rgb: [0, 0, 0], class_name: "ansi-black" },
82 | { rgb: [187, 0, 0], class_name: "ansi-red" },
83 | { rgb: [0, 187, 0], class_name: "ansi-green" },
84 | { rgb: [187, 187, 0], class_name: "ansi-yellow" },
85 | { rgb: [0, 0, 187], class_name: "ansi-blue" },
86 | { rgb: [187, 0, 187], class_name: "ansi-magenta" },
87 | { rgb: [0, 187, 187], class_name: "ansi-cyan" },
88 | { rgb: [255, 255, 255], class_name: "ansi-white" }
89 | ],
90 | [
91 | { rgb: [85, 85, 85], class_name: "ansi-bright-black" },
92 | { rgb: [255, 85, 85], class_name: "ansi-bright-red" },
93 | { rgb: [0, 255, 0], class_name: "ansi-bright-green" },
94 | { rgb: [255, 255, 85], class_name: "ansi-bright-yellow" },
95 | { rgb: [85, 85, 255], class_name: "ansi-bright-blue" },
96 | { rgb: [255, 85, 255], class_name: "ansi-bright-magenta" },
97 | { rgb: [85, 255, 255], class_name: "ansi-bright-cyan" },
98 | { rgb: [255, 255, 255], class_name: "ansi-bright-white" }
99 | ]
100 | ];
101 | this.palette_256 = [];
102 | this.ansi_colors.forEach(function (palette) {
103 | palette.forEach(function (rec) {
104 | _this.palette_256.push(rec);
105 | });
106 | });
107 | var levels = [0, 95, 135, 175, 215, 255];
108 | for (var r = 0; r < 6; ++r) {
109 | for (var g = 0; g < 6; ++g) {
110 | for (var b = 0; b < 6; ++b) {
111 | var col = { rgb: [levels[r], levels[g], levels[b]], class_name: 'truecolor' };
112 | this.palette_256.push(col);
113 | }
114 | }
115 | }
116 | var grey_level = 8;
117 | for (var i = 0; i < 24; ++i, grey_level += 10) {
118 | var gry = { rgb: [grey_level, grey_level, grey_level], class_name: 'truecolor' };
119 | this.palette_256.push(gry);
120 | }
121 | };
122 | AnsiUp.prototype.escape_txt_for_html = function (txt) {
123 | return txt.replace(/[&<>]/gm, function (str) {
124 | if (str === "&")
125 | return "&";
126 | if (str === "<")
127 | return "<";
128 | if (str === ">")
129 | return ">";
130 | });
131 | };
132 | AnsiUp.prototype.append_buffer = function (txt) {
133 | var str = this._buffer + txt;
134 | this._buffer = str;
135 | };
136 | AnsiUp.prototype.get_next_packet = function () {
137 | var pkt = {
138 | kind: PacketKind.EOS,
139 | text: '',
140 | url: ''
141 | };
142 | var len = this._buffer.length;
143 | if (len == 0)
144 | return pkt;
145 | var pos = this._buffer.indexOf("\x1B");
146 | if (pos == -1) {
147 | pkt.kind = PacketKind.Text;
148 | pkt.text = this._buffer;
149 | this._buffer = '';
150 | return pkt;
151 | }
152 | if (pos > 0) {
153 | pkt.kind = PacketKind.Text;
154 | pkt.text = this._buffer.slice(0, pos);
155 | this._buffer = this._buffer.slice(pos);
156 | return pkt;
157 | }
158 | if (pos == 0) {
159 | if (len == 1) {
160 | pkt.kind = PacketKind.Incomplete;
161 | return pkt;
162 | }
163 | var next_char = this._buffer.charAt(1);
164 | if ((next_char != '[') && (next_char != ']')) {
165 | pkt.kind = PacketKind.ESC;
166 | pkt.text = this._buffer.slice(0, 1);
167 | this._buffer = this._buffer.slice(1);
168 | return pkt;
169 | }
170 | if (next_char == '[') {
171 | if (!this._csi_regex) {
172 | this._csi_regex = rgx(__makeTemplateObject(["\n ^ # beginning of line\n #\n # First attempt\n (?: # legal sequence\n \u001B[ # CSI\n ([<-?]?) # private-mode char\n ([d;]*) # any digits or semicolons\n ([ -/]? # an intermediate modifier\n [@-~]) # the command\n )\n | # alternate (second attempt)\n (?: # illegal sequence\n \u001B[ # CSI\n [ -~]* # anything legal\n ([\0-\u001F:]) # anything illegal\n )\n "], ["\n ^ # beginning of line\n #\n # First attempt\n (?: # legal sequence\n \\x1b\\[ # CSI\n ([\\x3c-\\x3f]?) # private-mode char\n ([\\d;]*) # any digits or semicolons\n ([\\x20-\\x2f]? # an intermediate modifier\n [\\x40-\\x7e]) # the command\n )\n | # alternate (second attempt)\n (?: # illegal sequence\n \\x1b\\[ # CSI\n [\\x20-\\x7e]* # anything legal\n ([\\x00-\\x1f:]) # anything illegal\n )\n "]));
173 | }
174 | var match = this._buffer.match(this._csi_regex);
175 | if (match === null) {
176 | pkt.kind = PacketKind.Incomplete;
177 | return pkt;
178 | }
179 | if (match[4]) {
180 | pkt.kind = PacketKind.ESC;
181 | pkt.text = this._buffer.slice(0, 1);
182 | this._buffer = this._buffer.slice(1);
183 | return pkt;
184 | }
185 | if ((match[1] != '') || (match[3] != 'm'))
186 | pkt.kind = PacketKind.Unknown;
187 | else
188 | pkt.kind = PacketKind.SGR;
189 | pkt.text = match[2];
190 | var rpos = match[0].length;
191 | this._buffer = this._buffer.slice(rpos);
192 | return pkt;
193 | }
194 | if (next_char == ']') {
195 | if (len < 4) {
196 | pkt.kind = PacketKind.Incomplete;
197 | return pkt;
198 | }
199 | if ((this._buffer.charAt(2) != '8')
200 | || (this._buffer.charAt(3) != ';')) {
201 | pkt.kind = PacketKind.ESC;
202 | pkt.text = this._buffer.slice(0, 1);
203 | this._buffer = this._buffer.slice(1);
204 | return pkt;
205 | }
206 | if (!this._osc_st) {
207 | this._osc_st = rgxG(__makeTemplateObject(["\n (?: # legal sequence\n (\u001B\\) # ESC | # alternate\n (\u0007) # BEL (what xterm did)\n )\n | # alternate (second attempt)\n ( # illegal sequence\n [\0-\u0006] # anything illegal\n | # alternate\n [\b-\u001A] # anything illegal\n | # alternate\n [\u001C-\u001F] # anything illegal\n )\n "], ["\n (?: # legal sequence\n (\\x1b\\\\) # ESC \\\n | # alternate\n (\\x07) # BEL (what xterm did)\n )\n | # alternate (second attempt)\n ( # illegal sequence\n [\\x00-\\x06] # anything illegal\n | # alternate\n [\\x08-\\x1a] # anything illegal\n | # alternate\n [\\x1c-\\x1f] # anything illegal\n )\n "]));
208 | }
209 | this._osc_st.lastIndex = 0;
210 | {
211 | var match_1 = this._osc_st.exec(this._buffer);
212 | if (match_1 === null) {
213 | pkt.kind = PacketKind.Incomplete;
214 | return pkt;
215 | }
216 | if (match_1[3]) {
217 | pkt.kind = PacketKind.ESC;
218 | pkt.text = this._buffer.slice(0, 1);
219 | this._buffer = this._buffer.slice(1);
220 | return pkt;
221 | }
222 | }
223 | {
224 | var match_2 = this._osc_st.exec(this._buffer);
225 | if (match_2 === null) {
226 | pkt.kind = PacketKind.Incomplete;
227 | return pkt;
228 | }
229 | if (match_2[3]) {
230 | pkt.kind = PacketKind.ESC;
231 | pkt.text = this._buffer.slice(0, 1);
232 | this._buffer = this._buffer.slice(1);
233 | return pkt;
234 | }
235 | }
236 | if (!this._osc_regex) {
237 | this._osc_regex = rgx(__makeTemplateObject(["\n ^ # beginning of line\n #\n \u001B]8; # OSC Hyperlink\n [ -:<-~]* # params (excluding ;)\n ; # end of params\n ([!-~]{0,512}) # URL capture\n (?: # ST\n (?:\u001B\\) # ESC | # alternate\n (?:\u0007) # BEL (what xterm did)\n )\n ([!-~]+) # TEXT capture\n \u001B]8;; # OSC Hyperlink End\n (?: # ST\n (?:\u001B\\) # ESC | # alternate\n (?:\u0007) # BEL (what xterm did)\n )\n "], ["\n ^ # beginning of line\n #\n \\x1b\\]8; # OSC Hyperlink\n [\\x20-\\x3a\\x3c-\\x7e]* # params (excluding ;)\n ; # end of params\n ([\\x21-\\x7e]{0,512}) # URL capture\n (?: # ST\n (?:\\x1b\\\\) # ESC \\\n | # alternate\n (?:\\x07) # BEL (what xterm did)\n )\n ([\\x21-\\x7e]+) # TEXT capture\n \\x1b\\]8;; # OSC Hyperlink End\n (?: # ST\n (?:\\x1b\\\\) # ESC \\\n | # alternate\n (?:\\x07) # BEL (what xterm did)\n )\n "]));
238 | }
239 | var match = this._buffer.match(this._osc_regex);
240 | if (match === null) {
241 | pkt.kind = PacketKind.ESC;
242 | pkt.text = this._buffer.slice(0, 1);
243 | this._buffer = this._buffer.slice(1);
244 | return pkt;
245 | }
246 | pkt.kind = PacketKind.OSCURL;
247 | pkt.url = match[1];
248 | pkt.text = match[2];
249 | var rpos = match[0].length;
250 | this._buffer = this._buffer.slice(rpos);
251 | return pkt;
252 | }
253 | }
254 | };
255 | AnsiUp.prototype.ansi_to_html = function (txt) {
256 | this.append_buffer(txt);
257 | var blocks = [];
258 | while (true) {
259 | var packet = this.get_next_packet();
260 | if ((packet.kind == PacketKind.EOS)
261 | || (packet.kind == PacketKind.Incomplete))
262 | break;
263 | if ((packet.kind == PacketKind.ESC)
264 | || (packet.kind == PacketKind.Unknown))
265 | continue;
266 | if (packet.kind == PacketKind.Text)
267 | blocks.push(this.transform_to_html(this.with_state(packet)));
268 | else if (packet.kind == PacketKind.SGR)
269 | this.process_ansi(packet);
270 | else if (packet.kind == PacketKind.OSCURL)
271 | blocks.push(this.process_hyperlink(packet));
272 | }
273 | return blocks.join("");
274 | };
275 | AnsiUp.prototype.with_state = function (pkt) {
276 | return { bold: this.bold, fg: this.fg, bg: this.bg, text: pkt.text };
277 | };
278 | AnsiUp.prototype.process_ansi = function (pkt) {
279 | var sgr_cmds = pkt.text.split(';');
280 | while (sgr_cmds.length > 0) {
281 | var sgr_cmd_str = sgr_cmds.shift();
282 | var num = parseInt(sgr_cmd_str, 10);
283 | if (isNaN(num) || num === 0) {
284 | this.fg = this.bg = null;
285 | this.bold = false;
286 | }
287 | else if (num === 1) {
288 | this.bold = true;
289 | }
290 | else if (num === 22) {
291 | this.bold = false;
292 | }
293 | else if (num === 39) {
294 | this.fg = null;
295 | }
296 | else if (num === 49) {
297 | this.bg = null;
298 | }
299 | else if ((num >= 30) && (num < 38)) {
300 | this.fg = this.ansi_colors[0][(num - 30)];
301 | }
302 | else if ((num >= 40) && (num < 48)) {
303 | this.bg = this.ansi_colors[0][(num - 40)];
304 | }
305 | else if ((num >= 90) && (num < 98)) {
306 | this.fg = this.ansi_colors[1][(num - 90)];
307 | }
308 | else if ((num >= 100) && (num < 108)) {
309 | this.bg = this.ansi_colors[1][(num - 100)];
310 | }
311 | else if (num === 38 || num === 48) {
312 | if (sgr_cmds.length > 0) {
313 | var is_foreground = (num === 38);
314 | var mode_cmd = sgr_cmds.shift();
315 | if (mode_cmd === '5' && sgr_cmds.length > 0) {
316 | var palette_index = parseInt(sgr_cmds.shift(), 10);
317 | if (palette_index >= 0 && palette_index <= 255) {
318 | if (is_foreground)
319 | this.fg = this.palette_256[palette_index];
320 | else
321 | this.bg = this.palette_256[palette_index];
322 | }
323 | }
324 | if (mode_cmd === '2' && sgr_cmds.length > 2) {
325 | var r = parseInt(sgr_cmds.shift(), 10);
326 | var g = parseInt(sgr_cmds.shift(), 10);
327 | var b = parseInt(sgr_cmds.shift(), 10);
328 | if ((r >= 0 && r <= 255) && (g >= 0 && g <= 255) && (b >= 0 && b <= 255)) {
329 | var c = { rgb: [r, g, b], class_name: 'truecolor' };
330 | if (is_foreground)
331 | this.fg = c;
332 | else
333 | this.bg = c;
334 | }
335 | }
336 | }
337 | }
338 | }
339 | };
340 | AnsiUp.prototype.transform_to_html = function (fragment) {
341 | var txt = fragment.text;
342 | if (txt.length === 0)
343 | return txt;
344 | if (this._escape_for_html)
345 | txt = this.escape_txt_for_html(txt);
346 | if (!fragment.bold && fragment.fg === null && fragment.bg === null)
347 | return txt;
348 | var styles = [];
349 | var classes = [];
350 | var fg = fragment.fg;
351 | var bg = fragment.bg;
352 | if (fragment.bold)
353 | styles.push('font-weight:bold');
354 | if (!this._use_classes) {
355 | if (fg)
356 | styles.push("color:rgb(" + fg.rgb.join(',') + ")");
357 | if (bg)
358 | styles.push("background-color:rgb(" + bg.rgb + ")");
359 | }
360 | else {
361 | if (fg) {
362 | if (fg.class_name !== 'truecolor') {
363 | classes.push(fg.class_name + "-fg");
364 | }
365 | else {
366 | styles.push("color:rgb(" + fg.rgb.join(',') + ")");
367 | }
368 | }
369 | if (bg) {
370 | if (bg.class_name !== 'truecolor') {
371 | classes.push(bg.class_name + "-bg");
372 | }
373 | else {
374 | styles.push("background-color:rgb(" + bg.rgb.join(',') + ")");
375 | }
376 | }
377 | }
378 | var class_string = '';
379 | var style_string = '';
380 | if (classes.length)
381 | class_string = " class=\"" + classes.join(' ') + "\"";
382 | if (styles.length)
383 | style_string = " style=\"" + styles.join(';') + "\"";
384 | return "" + txt + " ";
385 | };
386 | ;
387 | AnsiUp.prototype.process_hyperlink = function (pkt) {
388 | var parts = pkt.url.split(':');
389 | if (parts.length < 1)
390 | return '';
391 | if (!this._url_whitelist[parts[0]])
392 | return '';
393 | var result = "" + this.escape_txt_for_html(pkt.text) + " ";
394 | return result;
395 | };
396 | return AnsiUp;
397 | }());
398 | function rgx(tmplObj) {
399 | var subst = [];
400 | for (var _i = 1; _i < arguments.length; _i++) {
401 | subst[_i - 1] = arguments[_i];
402 | }
403 | var regexText = tmplObj.raw[0];
404 | var wsrgx = /^\s+|\s+\n|\s*#[\s\S]*?\n|\n/gm;
405 | var txt2 = regexText.replace(wsrgx, '');
406 | return new RegExp(txt2);
407 | }
408 | function rgxG(tmplObj) {
409 | var subst = [];
410 | for (var _i = 1; _i < arguments.length; _i++) {
411 | subst[_i - 1] = arguments[_i];
412 | }
413 | var regexText = tmplObj.raw[0];
414 | var wsrgx = /^\s+|\s+\n|\s*#[\s\S]*?\n|\n/gm;
415 | var txt2 = regexText.replace(wsrgx, '');
416 | return new RegExp(txt2, 'g');
417 | }
418 | //# sourceMappingURL=ansi_up.js.map
419 | Object.defineProperty(exports, "__esModule", { value: true });
420 | exports.default = AnsiUp;
421 | }));
--------------------------------------------------------------------------------