Hi folks,
I'm working on a HTML dashboard to watch systems in a Data Center. The basic idea is pretty straight forward: A scripted input checks the system-health service-health and writes that into an index. Works fine, however, I want to be able to put that dashboard onto a big monitor on the wall so everybody in the office can see the overall health of the most important systems. My problem is the auto refresh, but I'll start from the bottom
I'm using a JS Object structure to "inject" the datacenters and systems dynamically (e.g. from a REST api). The result looks like this:
var dcs = {
datacenters: [{
name: "dc1",
nodes: [
{id: "system01", name: "System 01", ip: "1.2.3.4"},
{id: "system02", name: "System 02", ip: "2.3.4.5"},
... ]
},
...
In the dashboard I got an `into that the datacenters are rendered as a graphical overview (with jQuery). Works all nice and smooth. After that, I create the
SearchManager`:
var healthSearch = new SearchManager({
id: "health_search",
search: "index=health-index earliest=-60m | table status target _time | dedup target sortby -_time",
autostart: false,
cancelOnUnload: true
});
Basically I get all my machines with the last contact and the status (like healthy, online, unreachable, offline, ...). That index is filled by the scripted input. Works smoothly and just fine. Next step is to hang into the search:done event, like that:
// Get search:done event
healthSearch.on('search:done', function(properties){
var results = healthSearch.data('results');
// [Check if there are results etc]
// Get data event (**is this the right way to do it?**)
results.on('data', function(){
// Now I update the status of every system by iterate them with jquery and settings some css
// classes to make offline system blink, healthy system green, ...
$('#inject_dcs_here .node-container').each(function(){
// Iterate over result set. Not really efficient (n²), but with about 25 systems just fine
for(i in results.data().rows) {
if( [ip of container] == [ip of result]) {
// set status to whatever it is, remove and add css classes, ...
}
}
}
});
});
But now to my problem: The Auto-Refresh of that complete ui. I can't get it working. My approach was to just re-search:
setInterval(function() {
healthSearch.startSearch();
}, 120000); // Refresh every 2 minutes
Basically it works. The problem is, that with every iteration (every two minutes) a new results.data('on'
-databinding is placed. The when the data is loaded the first time, its processed once, the second time twice, ... (and only the last iteration actually contains results!). I tried something like do the results databinding only the first time
but that broke the ui completely (nothing loaded).
Do you have any ideas or tips how to auto-refresh the search results when the ui should be re-rendered after the results are ready to go? The life-cycle of the health monitor may reach weeks of months. so a new iteration every few minutes would kill the browser (some when). As I guess I'm doing something wrong but couldn't find something similiar to this problem.
This is working as intended, you're just not using it as intended.
With this line:
healthSearch.on('search:done', function(properties){
you are adding all the following code to what is already done on search:done. Among them is
results.on('data', function(){
So what you're doing is adding a listener to an event to another listener, which results in what you're seeing.
Do it like this and you should be fine:
var results = healthSearch.data('results');
results.on('data', function(){
// Now I update the status of every system by iterate them with jquery and settings some css
// classes to make offline system blink, healthy system green, ...
$('#inject_dcs_here .node-container').each(function(){
// Iterate over result set. Not really efficient (n²), but with about 25 systems just fine
for(i in results.data().rows) {
if( [ip of container] == [ip of result]) {
// set status to whatever it is, remove and add css classes, ...
}
}
You only need to listen to search:done events if you want to catch the case of a search returning zero events.
This is working as intended, you're just not using it as intended.
With this line:
healthSearch.on('search:done', function(properties){
you are adding all the following code to what is already done on search:done. Among them is
results.on('data', function(){
So what you're doing is adding a listener to an event to another listener, which results in what you're seeing.
Do it like this and you should be fine:
var results = healthSearch.data('results');
results.on('data', function(){
// Now I update the status of every system by iterate them with jquery and settings some css
// classes to make offline system blink, healthy system green, ...
$('#inject_dcs_here .node-container').each(function(){
// Iterate over result set. Not really efficient (n²), but with about 25 systems just fine
for(i in results.data().rows) {
if( [ip of container] == [ip of result]) {
// set status to whatever it is, remove and add css classes, ...
}
}
You only need to listen to search:done events if you want to catch the case of a search returning zero events.
Awesome! I was wondering "why do I have to listen to two events for one result set" - it had to be somethink like that (brain blocked). Thanks for the very quick answer, works like a charm now