Last active
March 28, 2023 08:43
-
-
Save ErgEnn/b3d49e15182e391d03b3464248a82f63 to your computer and use it in GitHub Desktop.
Colorizes CloudWatch log insights
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name ColorizeCloudwatch | |
// @namespace ColorizeCloudwatch | |
// @version 0.2 | |
// @description Colorize CloudWatch log insight rows based on request ID | |
// @author Ergo Enn | |
// @match https://*.console.aws.amazon.com/cloudwatch/* | |
// @icon https://s3.amazonaws.com/cloudwatch-console-static-content-s3/1.0/images/cloudwatch-favicon.ico | |
// @downloadURL https://gist.github.com/ErgEnn/b3d49e15182e391d03b3464248a82f63 | |
// @updateURL https://gist.github.com/ErgEnn/b3d49e15182e391d03b3464248a82f63 | |
// ==/UserScript== | |
//Based on: https://github.com/ErgEnn/colorize_cloudwatch_logs/blob/master/colorize.js | |
const colors = ["#F9DBBD", "#CDC7E5", "#F6A5A2", "#FFF399", "#C4F4C7", "#E8E1EF", "#D9FFF8", "#ADFFE5", "#E6DBD0", "#C7FFDA", "#FCA17D", "#FCD0A1", "#FAFFD8", "#A3F7B5", "#D8B4E2"] | |
function insertStylesheet () { | |
// dont know why, but all "spans" that are insterted in cwdb-ellipsis are blinking | |
// this class prevents that from happening | |
const style = document.createElement('style') | |
style.textContent = ` | |
.ansiColorized span { | |
-webkit-animation-name: unset !important; | |
-moz-animation-name: unset !important; | |
-ms-animation-name: unset !important; | |
animation-name: unset !important; | |
} | |
/* The container */ | |
.container-checkbox { | |
display: block; | |
position: relative; | |
padding-left: 20px; | |
cursor: pointer; | |
font-size: 13px; | |
-webkit-user-select: none; | |
-moz-user-select: none; | |
-ms-user-select: none; | |
user-select: none; | |
} | |
/* Hide the browser's default checkbox */ | |
.container-checkbox input { | |
position: absolute; | |
opacity: 0; | |
cursor: pointer; | |
} | |
/* Create a custom checkbox */ | |
.container-checkbox .checkmark { | |
position: absolute; | |
top: 0; | |
left: 0; | |
height: 16px; | |
width: 16px; | |
background-color: #eee; | |
} | |
/* On mouse-over, add a grey background color */ | |
.container-checkbox:hover input ~ .checkmark { | |
background-color: #ccc; | |
} | |
/* When the checkbox is checked, add a blue background */ | |
.container-checkbox input:checked ~ .checkmark { | |
background-color: #2196F3; | |
} | |
/* Create the checkmark/indicator (hidden when not checked) */ | |
.container-checkbox .checkmark:after { | |
content: ""; | |
position: absolute; | |
display: none; | |
} | |
/* Show the checkmark when checked */ | |
.container-checkbox input:checked ~ .checkmark:after { | |
display: block; | |
} | |
/* Style the checkmark/indicator */ | |
.container-checkbox .checkmark:after { | |
left: 4px; | |
top: 0px; | |
width: 5px; | |
height: 10px; | |
border: solid white; | |
border-width: 0 3px 3px 0; | |
-webkit-transform: rotate(45deg); | |
-ms-transform: rotate(45deg); | |
transform: rotate(45deg); | |
} | |
#logs-tweaker-panel { | |
position: fixed; | |
z-index: 1000000; | |
bottom: 30px; | |
right: 20px; | |
background: white; | |
border-radius: 4px; | |
box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23); | |
padding: 5px; | |
} | |
.cwdb-log-viewer-table-container.fullscreen .cwdb-log-viewer-table-body { | |
position: fixed; | |
background: white; | |
margin-top: 0; | |
top: 40px; | |
left: 0; | |
bottom: 0; | |
right: 0; | |
height: unset; | |
} | |
.logs__log-events-table__cell { | |
font-family: "Helvetica Neue", Roboto, Arial, sans-serif; | |
font-size: 14px; | |
} | |
.logs__log-events-table__cursor-text { | |
font-family: "Helvetica Neue", Roboto, Arial, sans-serif; | |
font-size: 14px; | |
} | |
.logs__log-events-table__timestamp-cell { | |
font-family: "Helvetica Neue", Roboto, Arial, sans-serif; | |
font-size: 14px; | |
} | |
` | |
document.head.appendChild(style) | |
} | |
// add "auto refresh" & "fullscreen" | |
setInterval(() => { | |
if (window.location.hash.includes('#logEventViewer') || isNewDesign()) { | |
if (!isNewDesign()) { | |
refreshOldDesign() | |
} else { | |
refreshNewDesign() | |
} | |
if (document.getElementById('logs-tweaker-panel')) { | |
return | |
} | |
insertStylesheet() | |
} | |
}, 1000) | |
function refreshOldDesign () { | |
refreshAutoRefresh() | |
refreshFullscreen() | |
} | |
function refreshNewDesign () { | |
refreshAutoRefresh() | |
refreshFullscreen() | |
} | |
function refreshTail () { | |
const refresh = document.getElementsByClassName('cwdb-log-viewer-table-infinite-loader-bottom')[0] | |
if (!refresh) { | |
return | |
} | |
let a = refresh.firstElementChild | |
while (a && a.tagName !== 'A') { | |
a = a.nextElementSibling | |
} | |
if (a) { | |
a.click() | |
// scroll to bottom | |
const div = document.getElementsByClassName('cwdb-log-viewer-table-body')[0] | |
if (div) { | |
div.scrollTop = div.scrollHeight | |
} | |
} | |
} | |
function isCheckedForDecorated (element) { | |
return element.dataset.checkedForDecorated !== 'yes' | |
} | |
function setCheckedForDecorated (element) { | |
element.dataset.checkedForDecorated = 'yes' | |
return element | |
} | |
function isCheckedForBold (element) { | |
return element.dataset.checkedForBold !== 'yes' | |
} | |
function setCheckedForBold (element) { | |
element.dataset.checkedForBold = 'yes' | |
return element | |
} | |
function isRequestIdLine(element){ | |
return element.innerHTML.includes('requestId') | |
} | |
function isStartLine (element) { | |
return element.innerHTML.includes('START RequestId:') | |
} | |
function isEndLine (element) { | |
return element.innerHTML.includes('REPORT RequestId:') | |
} | |
function isErrorLine (element) { | |
const text = element.innerHTML.toLowerCase() | |
return text.includes('error') | |
} | |
function isErrorOrEndLine (element) { | |
return isErrorLine(element) || isEndLine(element) | |
} | |
function isStartOrEndOrRequestId (element) { | |
return isStartLine(element) || isEndLine(element) || isRequestIdLine(element) | |
} | |
function hasId (element, id) { | |
return element.innerHTML.includes(id) | |
} | |
function colorizeElement (element, color) { | |
element.style.backgroundColor = color | |
let subElements = element.getElementsByClassName("logs-table__body-cell") | |
for(let e of subElements){ | |
colorizeElement(e,color) | |
} | |
return element | |
} | |
function changeFontElement (element, action) { | |
if (element.dataset.isFontHandled !== 'yes' || action) { | |
element.dataset.isFontHandled = 'yes' | |
element.height = '20px' | |
element.lineHeight = '20px' | |
let subElements = element.getElementsByClassName('logs__log-events-table__cell') | |
for (let e of subElements) { | |
if (action === 'clear') { | |
e.style.fontFamily = null; | |
e.style.fontSize = null; | |
e.style.paddingLeft = null; | |
} else { | |
e.style.fontFamily = '"Helvetica Neue", Roboto, Arial, sans-serif' | |
e.style.fontSize = '0.9em' | |
e.style.paddingLeft = '5px' | |
} | |
} | |
} | |
return element | |
} | |
function makeBoldElement (element) { | |
element.style.fontWeight = 600 | |
return element | |
} | |
function makeBold (elements) { | |
elements | |
.filter(isCheckedForBold) | |
.map(setCheckedForBold) | |
.filter(isErrorOrEndLine) | |
.forEach(makeBoldElement) | |
} | |
function getEventId (element) { | |
return element | |
.innerHTML | |
.replace(/\n/g, ' ') | |
.match(/(?<=[Rr]equestId"?:"?)\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/g)[0] | |
} | |
function getUniqueEventIds (elements) { | |
return Array.from( | |
new Set( | |
elements | |
.filter(isCheckedForDecorated) | |
.map(setCheckedForDecorated) | |
.filter(isStartOrEndOrRequestId) | |
.map(getEventId))) | |
} | |
function changeFontOnGroup (elements) { | |
elements.forEach(changeFontElement) | |
} | |
function colorizeGroup (elements) { | |
let color = colors[Math.floor((Math.random() * 10000)) % colors.length] | |
elements.forEach(element => colorizeElement(element, color)) | |
} | |
function decorateGroups (elements) { | |
let eventIds = getUniqueEventIds(elements) | |
let newDesign = isNewDesign() | |
if (eventIds) { | |
eventIds.forEach( | |
id => { | |
colorizeGroup(elements.filter(element => hasId(element, id))) | |
if (newDesign && fontsOn()) changeFontOnGroup(elements) | |
}) | |
} | |
} | |
function applyAnsiTransform (e) { | |
if (e) { | |
const txt = e.childNodes[0] | |
const textValue = txt.textContent || '' | |
if (/(^|\x1b)\[(\d+)m/.test(textValue)) { | |
e.classList.add('ansiColorized') | |
e.innerHTML = ansiTransform.ansi_to_html(textValue) | |
} | |
} | |
} | |
function colorizeAnsi (elements) { | |
for (let e of elements) { | |
if (e.dataset.isAnsiColorizedHandled !== 'yes') { | |
e.dataset.isAnsiColorizedHandled = 'yes' | |
applyAnsiTransform(e.getElementsByClassName("logs__log-events-table__cell")[1]) | |
} | |
} | |
} | |
function getElements () { | |
let elements | |
const newDesignElements = document.querySelectorAll('iframe#microConsole-Logs')[0] | |
if (newDesignElements) { | |
elements = newDesignElements.contentDocument.getElementsByClassName('awsui-table-row') | |
if(!elements.length){ //logs insights | |
elements = newDesignElements.contentDocument.getElementsByClassName('logs-table__body-row') | |
} | |
} else { | |
elements = document.getElementsByClassName('cwdb-ellipsis') | |
} | |
return [].slice.call(elements) | |
} | |
function isNewDesign () { | |
return window.location.hash.includes('#logsV2:log-groups/log-group') && window.location.hash.includes('/log-events') | |
} | |
function colorizeAll () { | |
// console.time('cost-of-colorize') | |
// console.time('cost-of-getting-elements') | |
const elements = getElements() | |
// console.timeEnd('cost-of-getting-elements') | |
// console.time('cost-of-colorize-groups') | |
decorateGroups(elements) | |
// console.timeEnd('cost-of-colorize-groups') | |
// console.time('cost-of-colorize-ansi') | |
colorizeAnsi(elements) | |
// console.timeEnd('cost-of-colorize-ansi') | |
// console.time('cost-of-bold') | |
makeBold(elements) | |
// console.timeEnd('cost-of-bold') | |
// console.timeEnd('cost-of-colorize') | |
} | |
setInterval(colorizeAll, 1000) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment