Last active
October 3, 2022 02:11
-
-
Save chaoyangnz/62e7e107425f6bcaa23ab21846b1166c to your computer and use it in GitHub Desktop.
This file contains hidden or 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 graylog-eyecandy | |
// @namespace http://tampermonkey.net/ | |
// @version 0.1 | |
// @description Graylog EyeCandy script for siteminder | |
// @author Chao Yang | |
// @icon https://pics.freeicons.io/uploads/icons/png/1000492771548141155-512.png | |
// @grant GM_addStyle | |
// @grant GM_addElement | |
// @match *://graylog.siteminder.systems/* | |
// @match *://graylog.dev.siteminderlabs.com/* | |
// ==/UserScript== | |
(function() { | |
'use strict'; | |
window.addEventListener('load', function() { | |
console.log('loaded') | |
GM_addStyle('table.messages th, table.messages td { left: 0; }') | |
live('#main-content-sidebar', (container) => { | |
const style = (c, left) => `background-color: ${c || '#666'};border-radius: 2px;border-style: none;box-sizing: border-box;color: #FFFFFF;cursor: pointer;display: inline-block;height: 30px;line-height: 20px;margin: auto 5px;outline: none;padding: 5px 16px;${left ? '' :'float: right;'}` | |
const buttonGroup = GM_addElement('div', { | |
class: 'content-col', | |
}) | |
container.insertBefore(buttonGroup, container.children[4]) | |
const buttons = [ | |
createButton('Eye Candy', style('#EA4C89', true), () => {dedupe(); toggleFields(); linkTraceToken(); colorize();}), | |
createButton('Dedupe', style(), dedupe), | |
createButton('Fields', style(), toggleFields), | |
createButton('Link TraceToken', style(), linkTraceToken), | |
createButton('Colorize', style(), colorize), | |
createButton('Pretty JSON message', style(), prettyJsonMessage) | |
]; | |
buttons.forEach(button => buttonGroup.appendChild(button)) | |
}) | |
}, false); | |
})(); | |
function createButton(text, style, fn) { | |
const button = GM_addElement('button', { | |
textContent: text, | |
style | |
}) | |
button.addEventListener('click', fn) | |
return button | |
} | |
function dedupe() { | |
console.log('dedupe') | |
const entries = Array.from(document.querySelectorAll('.message-group')) | |
const entriesContent = [] | |
const entriesIndex = [] | |
entries.map(group => group.querySelector('.fields-row time').textContent + '@' + group.querySelector('.message-row .message-wrapper').textContent).forEach((text, index) => { | |
if (!entriesContent.includes(text)) { | |
entriesContent.push(text) | |
entriesIndex.push(index) | |
} | |
}) | |
entries.forEach((entry, index) => { | |
if(!entriesIndex.includes(index)) { | |
entry.closest('.message-group').remove(); | |
console.log(`remove ${index}`); | |
} | |
}) | |
} | |
// toggle commonly used fields | |
function toggleFields() { | |
['source'].forEach(field => live(`input[label=${field}]`, (input) => { | |
if(input.checked) { | |
input.click() | |
} | |
})); | |
['name', 'traceToken', 'subject'].forEach(field => live(`input[label=${field}]`, (input) => { | |
if(!input.checked) { | |
input.click() | |
} | |
})) | |
} | |
function __findFieldColumnIndex(field) { | |
const headers = Array.from(document.querySelectorAll('table.messages thead th')) | |
let index | |
headers.forEach((header, i) => { | |
if(header.textContent.trim() == field) { | |
index = i | |
console.log(`found ${field} at ${i}`) | |
} | |
}) | |
return index | |
} | |
function __forEachRow(field, fn) { | |
const index = __findFieldColumnIndex(field) | |
if (index !== undefined) { | |
const rows = Array.from(document.querySelectorAll('table.messages tbody.message-group')) | |
rows.forEach(group => { | |
const fieldsRow = group.querySelector('tr.fields-row') | |
const messageRow = group.querySelector('tr.message-row') | |
const col = fieldsRow.children[index] | |
const value = col.textContent.trim() | |
fn(group, fieldsRow, messageRow, col, value) | |
}) | |
} | |
} | |
// link traceToken | |
function linkTraceToken() { | |
__forEachRow('traceToken', (group, fieldsRow, messageRow, col, value) => { | |
if (value) { | |
const url = `https://${window.location.hostname}/search?rangetype=relative&relative=2592000&width=1440&highlightMessage=&fields=message,name,subject,traceToken&q=traceToken:${value}` | |
col.innerHTML = `<a href="${url}">${value}</a>` | |
} | |
}) | |
} | |
function prettyJsonMessage() { | |
Array.from(document.querySelectorAll('.message-details .message-field .field-value')).forEach(row => { | |
try{ | |
const value = row.textContent.trim() | |
const json = JSON.parse(value) | |
Object.keys(json).forEach(key => { | |
try { | |
const v = JSON.parse(json[key]) | |
json[key] = v | |
} catch(er) {} | |
}) | |
row.textContent = JSON.stringify(json, undefined, 2) | |
} catch(e) {} | |
}) | |
} | |
function __randomColor(key, colors) { | |
let color | |
if(Object.keys(colors).includes(key)) { | |
color = colors[key] | |
} else { | |
color = Math.floor(Math.random()*16777215).toString(16) | |
colors[key] = color | |
console.log(`generate color ${color} for ${key}`) | |
} | |
return color | |
} | |
// colorize different systems/components and traces | |
function colorize() { | |
const nameColors = {} | |
__forEachRow('name', (group, fieldsRow, messageRow, col, value) => { | |
if (value) { | |
const color = __randomColor(value, nameColors) | |
group.style.borderLeft = `solid 3px #${color}` | |
} | |
}) | |
const traceColors = {} | |
__forEachRow('traceToken', (group, fieldsRow, messageRow, col, value) => { | |
if (value) { | |
const color = __randomColor(value, traceColors) | |
group.style.borderRight = `solid 3px #${color}` | |
} | |
}) | |
} | |
function live(selector, fn) { | |
const elem = document.querySelector(selector) | |
if (elem) { | |
console.log(`found ${selector}`) | |
fn(elem) | |
} else { | |
setTimeout(() => live(selector, fn), 500) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment