Skip to content

Commit

Permalink
Add flame graph renderer and probe
Browse files Browse the repository at this point in the history
  • Loading branch information
lwindolf committed Jul 5, 2021
1 parent 83e5041 commit 43a7664
Show file tree
Hide file tree
Showing 11 changed files with 1,867 additions and 57 deletions.
134 changes: 134 additions & 0 deletions LICENSE.CDDL

Large diffs are not rendered by default.

18 changes: 11 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
# WurmTerm 🐛

Linux Terminal helper with Service Auto-Discovery + Rendering Capabilities.
Linux Terminal companion app discovering services and issues on your servers.

![Screenshot WurmTerm](https://user-images.githubusercontent.com/3315368/118046621-dde32e00-b379-11eb-8400-7942eb401e86.png)

WurmTerm watches over the state of servers you are connected to via SSH sessions
and alerts you of issues detected and provides you with an overview of detected
services (web servers, databases, RAID ...).
WurmTerm
- watches over the state of servers you are connected to via SSH sessions
- alerts you of issues detected
- provides you with an overview of detected services (web servers, databases, RAID ...)
- allows you to create CPU flame graphs

This allows you to keep WurmTerm open as a browser tab alongside you terminal and
it will notify you about issues on hosts you "travel" to faster than you could debug
issues yourself. It will often uncover problem you do not notice at all.
By using the same password-less SSH connect commands you use WurmTerm can be open
as a browser tab alongside you multiple terminal (tabs) and it will visually notify
you about issues on hosts you "travel" to faster and more comprehensive than you
could debug issues yourself. It will often uncover problem you do not notice at all.

Probing does not happen via brute-force, but depending on services detected via
a `netstat`/`ss` listing.
Expand Down Expand Up @@ -46,3 +49,4 @@ Wurmterm assumes
- that it can connect to all those nodes without credentials
- that you use `ssh <node|ip>` only and handle all private key switching in your SSH config
- that it is always allowed to sudo (but won't complain if it does not succeed)

45 changes: 26 additions & 19 deletions assets/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,22 @@
var renderers = {};
</script>
<script type="text/javascript" src="js/renderer/netmap.js"></script>
<script type="text/javascript" src="js/renderer/perf-flamegraph.js"></script>
<title>WurmTerm</title>
</head>
<body>
<div class='main'>
<h1>WurmTerm 🐛</h1>
<div id='visual'>
<div id='visualContainer'>
Visualization
<select id='renderer'>
<option value='netmap'>netmap</option>
<option value='perfFlameGraph'>perf flamegraph</option>
</select>
Host
<span id='visualizedHost'></span>
<div id='visual'>
</div>
</div>
<div id='nodes'>
</div>
Expand Down Expand Up @@ -135,24 +145,18 @@ <h1>WurmTerm 🐛</h1>
.map(node=>list.appendChild(node))
}

function visualizeHost(host) {
// For now we only support netstat rendering
$('#visual').show();
$('#visual').height(600);
$('#visual').html('<i>Loading connections...</i>');

function visualizeHost(host, renderer) {
$('#visualContainer').show();
$('#visualizedHost').html(host);
$('#renderer').val(renderer);
$('#visual').empty().height(600);
console.log("rend="+renderer);
try {
pAPI.probe(host, 'netstat-a', function(probe, h, d) {
console.log(`netmap result ${d} `);
var r = new renderers.netmap();
r.render('#visual', d.stdout);
}, function(e, probe, h) {
$('#visual').html('ERROR: Fetching data failed!');
console.error(`probe Error: host=${h} probe=${probe} ${e}`);
});
var r = new renderers[renderer]();
r.render(pAPI, '#visual', host);
} catch(e) {
$('#visual').html('ERROR: Rendering failed!');
console.error(`render Error: host=${h} ${e}`);
console.error(`render Error: host=${host} ${e}`);
}
}

Expand All @@ -170,7 +174,7 @@ <h1>WurmTerm 🐛</h1>
$(`#${hId}.node`).removeClass('disconnected');

$('.node .name').on('click', function() {
visualizeHost($(this).parent().data('host'));
visualizeHost($(this).parent().data('host'), 'netmap');
});
}

Expand Down Expand Up @@ -285,7 +289,7 @@ <h1>WurmTerm 🐛</h1>
});
})
.fail(function(data) {
console.error("failed fetching /api/hosts! "+d);
console.error("failed fetching /api/hosts! "+data);
})

setTimeout(function () {
Expand Down Expand Up @@ -318,12 +322,15 @@ <h1>WurmTerm 🐛</h1>
event.preventDefault();
return true;
});

}

(function() {
updateHosts();
addHistory();

$('#renderer').on('change', function() {
visualizeHost($('#visualizedHost').text(), $(this).val());
});
})();
</script>
</body>
Expand Down
43 changes: 25 additions & 18 deletions assets/js/renderer/netmap.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// vim: set ts=4 sw=4:
// vim: set ts=4 sw=4:
/* IPv4 only netmap renderer
A view showing per-service connections for a single host in a
Expand Down Expand Up @@ -130,7 +130,7 @@ renderers.netmap.prototype.updateGraph = function() {
g.setEdge(l.source, l.target, props);
});

try {
try {TypeError
var render = new dagreD3.render();
render(nodeArea, g);
} catch(e) {
Expand Down Expand Up @@ -261,20 +261,27 @@ renderers.netmap.prototype.addHost = function(data) {
}
}

renderers.netmap.prototype.render = function(id, input) {
var data = this.parse(input);

if(0 === data.results.length) {
$(id).html(`<h3>There are currently no connections on this host!</h3><p>Connection data:</p><pre>${
input.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;")
}</pre>`);
return;
}

$(id).html('<svg id="netmap"/>');
this.addHost(data);
renderers.netmap.prototype.render = function(pAPI, id, host) {
var r = this;

$(id).html('<i>Loading connections...</i>');

pAPI.probe(host, 'netstat-a', function(probe, h, input) {
var data = r.parse(input.stdout);
if(0 === data.results.length) {
$(id).html(`<h3>There are currently no connections on this host!</h3><p>Connection data:</p><pre>${
input.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;")
}</pre>`);
return;
}
$(id).html('<svg id="netmap"/>');
r.addHost(data);
}, function(e, probe, h) {
$(id).html('ERROR: Fetching connection data failed!');
console.error(`probe Error: host=${h} probe=${probe} ${e}`);
});
};
34 changes: 34 additions & 0 deletions assets/js/renderer/perf-flamegraph.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// vim: set ts=4 sw=4:
/* perf based flamegraphs
A view allowing you to start a remote perf tool run and process
the result into a SVG to be displayed by the renderer. */

renderers.perfFlameGraph = function perfFlameGraphRenderer() {
};

renderers.perfFlameGraph.prototype.render = function(pAPI, id, host) {
var r = this;

$(id).html(`
<div class='rendererForm'>
Duration <input readonly type='text' id='perfFlameGraphDuration' value='15' size='3'/> seconds
<input type='button' id='perfFlameGraphSubmit' value='Start Sampling'/>
</div>
<div class='perfFlameGraph' style='overflow:auto'>
</div>
`);

$('#perfFlameGraphSubmit').on('click', function() {
$(id + " .perfFlameGraph").html(`Sampling ${host}...`);

pAPI.probe(host, 'perf', function(probe, h, input) {
$(id + " .perfFlameGraph")
.height($(id).height() - $(id + " .rendererForm").outerHeight())
.html(input.stdout)
.scrollTop($(id + ' .perfFlameGraph')[0].scrollHeight);
}, function(e, probe, h) {
$(id+ " .perfFlameGraph").html('ERROR: Fetching perf data failed!');
console.error(`probe Error: host=${h} probe=${probe} ${e}`);
});
});
}
17 changes: 15 additions & 2 deletions assets/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,19 @@ img.emojione {
height: auto;
}

#visual {
#visualizedHost {
font-weight: bold;
color: white;
}
#visualContainer {
display: none;
}
#visual {
height: 33%;
border: 1px solid silver;
background: white;
margin-bottom:12px;
margin-bottom: 12px;
margin-top: 6px;
}

#visual .label {
Expand Down Expand Up @@ -61,6 +68,12 @@ img.emojione {
text-decoration:none;
}

.rendererForm {
padding:12px;
background: #eee;
color: black;
}

#nodes {
display: flex;
flex-direction: row;
Expand Down
5 changes: 5 additions & 0 deletions probes/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
}
}
},
"perf": {
"name" : "perf",
"command" : "(sudo perf record -F 99 -g -a -o /tmp/perf.wurmterm -- sleep 15 && sudo perf script -i /tmp/perf.wurmterm); sudo rm /tmp/perf.wurmterm",
"localFilter": "scripts/stackcollapse-perf.pl | scripts/flamegraph.pl"
},
"netstat-a": {
"name" : "All Connections",
"command": "(sudo -n netstat -tulpan --numeric-hosts 2>/dev/null || netstat -tulan 2>/dev/null || sudo -n ss -etupn 2>/dev/null || ss -etunp 2>/dev/null) | egrep -v '^(Active Internet|Proto)'",
Expand Down
Loading

0 comments on commit 43a7664

Please sign in to comment.