NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name Kibana JSON/Stacktrace Formatter
// @namespace http://tampermonkey.net/
// @version 0.2
// @description try to take over the world!
// @author Miguel De Anda
// @match */app/kibana*
// @match http://localhost:5601/*
// @grant none
// @license MIT
// @copyright 2019, mdeanda (https://openuserjs.org/users/mdeanda)
// @updateURL https://openuserjs.org/meta/mdeanda/Kibana_JSONStacktrace_Formatter.meta.js
// ==/UserScript==
(function() {
'use strict';
var jqueryUrl = 'https://code.jquery.com/jquery-2.2.4.min.js';
var timer = setInterval(function() {
if (window.jQuery) {
clearInterval(timer);
var $ = window.jQuery;
go($);
}
}, 500);
function go($) {
var sourceClasses = [".truncate-by-height", ".doc-viewer-value", ".kbnDocViewer__value"];
var newCss = ".doc-viewer-value { max-height: 30em; overflow: hidden; }";
var styleTag = document.createElement("style");
styleTag.textContent = newCss;
document.body.appendChild(styleTag);
window.addEventListener('dblclick', function(evt) {
var target = evt.target;
var el = $(target);
for (var i=0; i<sourceClasses.length; i++) {
var cls = sourceClasses[i];
if (el.is(cls)) {
clicked($, el);
break;
}
var p = el.parent(cls);
if (p.length > 0) {
clicked($, p);
break;
}
}
});
}
function clicked($, target) {
try {
var parsed = parse(target)
if (!parsed) {
parsed = parse($('span', target));
}
if (parsed) {
var stack = buildStackTrace(parsed);
if (!stack) return;
var fullHtml = popupHtml(parsed);
var win = window.open('about:blank', '', 'width=840,height=480');
var doc = win.document;
doc.write(fullHtml);
}
} catch(e){console.dir(e);}
}
function parse(el) {
var val = el.html();
try {
return JSON.parse(val);
} catch (e) {}
try {
return JSON.parse('[' + val + ']');
} catch(e) {}
return null;
}
function getPackagesForPackage(classname, separator, prefix) {
var output = [];
var pkg = [];
var parts = classname.split('.');
parts.pop(); //remove classname
parts.forEach(function(p) {
pkg.push(p);
var packageName = prefix + pkg.join(separator);
output.push(packageName);
});
return output;
}
function buildStackTrace(jsonArray) {
//assumes each entry has: class, method, file, line
var lines = [];
for (var i=0; i<jsonArray.length; i++) {
var line = jsonArray[i];
if (!line['class'] || !line.method || !line.line) {
return null;
}
var packageCss = getPackagesForPackage(line['class'], '_', '_cls_').join(' ');
var fl = (line.line > 0) ? line.file + ':' + line.line : '';
var str = '<div class="_cls__base ' + packageCss + '">'
+ '<span class="classname">' + line['class'] + '</span>'
+ '.'
+ '<span class="method">' + line.method + '</span>'
+ '<span class="file">' + '(' + fl + ')' + '</span>'
+ '</div>';
lines.push(str);
}
return lines.join('\n');
}
function getPackages(parsed) {
var map = {};
parsed.forEach(function(item) {
var packages = getPackagesForPackage(item['class'], '.', '');
packages.forEach(function(packageName) {
if (typeof map[packageName] == 'undefined') map[packageName] = 1;
else map[packageName] = map[packageName] + 1;
});
});
return map;
}
function buildPackageSelector(packages) {
var output = [];
output.push('<div>');
output.push('<select onchange="changed(this.value)" id="select">');
output.push('<option value="">[ View All ]</option>');
Object.keys(packages).sort().forEach(function(key) {
output.push('<option value="_cls_' + key.replace(/\./g, '_') + '">' + key + ' - ' + packages[key] + '</option>');
})
output.push('</select>');
output.push('</div>');
return output.join('\n');
}
function getPopupJs() {
var o = [];
o.push('function changed(value) {');
//o.push(' alert(value);');
//hide/show mode
o.push(' if (value == "") value = "_cls__base";');
o.push(' var items = document.querySelectorAll("._cls__base");');
o.push(' for (var i=0; i<items.length; i++) {');
o.push(' items[i].style.display = "none";');
o.push(' }');
o.push(' items = document.querySelectorAll("." + value);');
o.push(' for (var i=0; i<items.length; i++) {');
o.push(' items[i].style.display = "";');
o.push(' }');
o.push('}');
return o.join('\n');
}
function popupHtml(parsed) {
var output = [];
output.push('<' + 'style>');
output.push('.stacktrace { font-family: monospace; font-size: 12px }');
output.push('.classname { color: #222266; }');
output.push('.method { color: #226622; }');
output.push('.file { color: #444444; }');
output.push('<' + '/style>');
output.push('<' + 'script>' + getPopupJs() + '</' + 'script>');
output.push(buildPackageSelector(getPackages(parsed)));
output.push('<div class="stacktrace">');
output.push(buildStackTrace(parsed));
output.push('</div>');
return output.join('\n');
}
})();