Skip to content

Instantly share code, notes, and snippets.

@chaoyangnz
Last active October 3, 2022 02:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chaoyangnz/62e7e107425f6bcaa23ab21846b1166c to your computer and use it in GitHub Desktop.
Save chaoyangnz/62e7e107425f6bcaa23ab21846b1166c to your computer and use it in GitHub Desktop.
// ==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