diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2014-10-26 12:33:50 +0400 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2014-10-26 12:33:50 +0400 |
commit | 47e6e7c84f008a53061e661f31ae96629bc694ef (patch) | |
tree | 648a07f3b5b9d67ce19b0fd72e8caa1175c98f1a /src/pmwebapi/jsdemos/blinkenlights | |
download | pcp-debian.tar.gz |
Debian 3.9.10debian/3.9.10debian
Diffstat (limited to 'src/pmwebapi/jsdemos/blinkenlights')
-rw-r--r-- | src/pmwebapi/jsdemos/blinkenlights/GNUmakefile | 33 | ||||
-rw-r--r-- | src/pmwebapi/jsdemos/blinkenlights/blinken_error.png | bin | 0 -> 7879 bytes | |||
-rw-r--r-- | src/pmwebapi/jsdemos/blinkenlights/blinken_off.png | bin | 0 -> 6324 bytes | |||
-rw-r--r-- | src/pmwebapi/jsdemos/blinkenlights/blinken_on.png | bin | 0 -> 6360 bytes | |||
-rw-r--r-- | src/pmwebapi/jsdemos/blinkenlights/blinkenlights.css | 19 | ||||
-rw-r--r-- | src/pmwebapi/jsdemos/blinkenlights/blinkenlights.js | 170 | ||||
-rw-r--r-- | src/pmwebapi/jsdemos/blinkenlights/index.html | 129 |
7 files changed, 351 insertions, 0 deletions
diff --git a/src/pmwebapi/jsdemos/blinkenlights/GNUmakefile b/src/pmwebapi/jsdemos/blinkenlights/GNUmakefile new file mode 100644 index 0000000..a2ba409 --- /dev/null +++ b/src/pmwebapi/jsdemos/blinkenlights/GNUmakefile @@ -0,0 +1,33 @@ +# +# Copyright (c) 2013 Red Hat. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# + +TOPDIR = ../../../.. +include $(TOPDIR)/src/include/builddefs + +IMAGES = blinken_error.png blinken_off.png blinken_on.png +JSFILES = blinkenlights.js +CSSFILES = blinkenlights.css +HTMLFILES = index.html + +LSRCFILES = $(IMAGES) $(JSFILES) $(CSSFILES) $(HTMLFILES) + +default: + +include $(BUILDRULES) + +install: + +default_pcp: default + +install_pcp: install diff --git a/src/pmwebapi/jsdemos/blinkenlights/blinken_error.png b/src/pmwebapi/jsdemos/blinkenlights/blinken_error.png Binary files differnew file mode 100644 index 0000000..556bd3a --- /dev/null +++ b/src/pmwebapi/jsdemos/blinkenlights/blinken_error.png diff --git a/src/pmwebapi/jsdemos/blinkenlights/blinken_off.png b/src/pmwebapi/jsdemos/blinkenlights/blinken_off.png Binary files differnew file mode 100644 index 0000000..abb5c1d --- /dev/null +++ b/src/pmwebapi/jsdemos/blinkenlights/blinken_off.png diff --git a/src/pmwebapi/jsdemos/blinkenlights/blinken_on.png b/src/pmwebapi/jsdemos/blinkenlights/blinken_on.png Binary files differnew file mode 100644 index 0000000..8d85f61 --- /dev/null +++ b/src/pmwebapi/jsdemos/blinkenlights/blinken_on.png diff --git a/src/pmwebapi/jsdemos/blinkenlights/blinkenlights.css b/src/pmwebapi/jsdemos/blinkenlights/blinkenlights.css new file mode 100644 index 0000000..c99ceff --- /dev/null +++ b/src/pmwebapi/jsdemos/blinkenlights/blinkenlights.css @@ -0,0 +1,19 @@ +#interval-slider-label { margin: 0px; } +#interval-slider { width: 300px; margin: 0px; display: inline-block; } + +#blinkenlights { font-family: monospace; font-size: 130%; } +#blinkenlights li { + list-style: none; line-height: 25px; + background-repeat: no-repeat; + background-size: 25px 25px; + padding-left: 32px; margin-top: 5px; +} + +/* public domain images courtesy of + - http://www.clker.com/clipart-led-off.html + - http://www.clker.com/clipart-6514.html + XXX and related images from the same site + */ +#blinkenlights li.on { background-image: url(blinken_on.png); } +#blinkenlights li.off { background-image: url(blinken_off.png); } +#blinkenlights li.error { background-image: url(blinken_error.png); } diff --git a/src/pmwebapi/jsdemos/blinkenlights/blinkenlights.js b/src/pmwebapi/jsdemos/blinkenlights/blinkenlights.js new file mode 100644 index 0000000..03bb315 --- /dev/null +++ b/src/pmwebapi/jsdemos/blinkenlights/blinkenlights.js @@ -0,0 +1,170 @@ +var pm_root = "http://" + location.hostname + ":" + location.port + "/pmapi"; +var pm_context = -1; + +// ---------------------------------------------------------------------- + +function Predicate(name,index,operator,threshold) { + this.name = name; + this.index = index; + this.operator = operator; + this.threshold = threshold; + this.inames = {}; +} + +Predicate.prototype.to_string = function() { + return this.name + "[" + this.index + "] " + + this.operator + " " + this.threshold; +}; + +Predicate.prototype.get_iname = function(iid) { + if (!(iid in this.inames)) { + var pm_url = pm_root + "/" + pm_context + "/_indom?name=" + this.name + "&instance=" + iid; + var predicate = this; + $.getJSON(pm_url, function(data, status) { + // TODOXXX error check: should return 1 instance + predicate.inames[iid] = data.instances[0].name; + }); + + return "..."; // will be reloaded next cycle + } + + return this.inames[iid]; +} + +Predicate.prototype.test = function(elt,data_dict,index) { + if (this.index == "*" && typeof(index) == "undefined") { + var predicate = this; + $.each(data_dict[this.name].instances, function(i,_instance) { + predicate.test(elt,data_dict,i); + }); + return; + } + + if (typeof(index) == "undefined") index = this.index; + + var metric = data_dict[this.name].instances[index].value; + var iid = data_dict[this.name].instances[index].instance; + var result = 0, error = ""; + if (this.operator == "<") result = metric < this.threshold; + else if (this.operator == ">") result = metric > this.threshold; + else if (this.operator == "<=") result = metric <= this.threshold; + else if (this.operator == ">=") result = metric >= this.threshold; + else if (this.operator == "==") result = metric == this.threshold; + else { error = "unknown operator '" + this.operator + "'"; result = -1; } + + // TODOXXX avoid $("#blinkenlights").empty() by using existing li's?? + var bclass = result < 0 ? "error" : result ? "on" : "off"; + + var source = "<strong>" + metric + "</strong> -- " + + this.name + " ( " + this.get_iname(iid) + " : " + iid + " ) " + + this.operator + " " + this.threshold; + var content = "<span>" + source + "</span>" + + (result < 0 ? " -- error: " + error : ""); + + elt.append("<li class=\"" + bclass + "\">" + content + "</li>"); +}; + +var predicates = []; + +function parsePredicate(src) { + var matches = /^([^[ ]+)\s*(\[\d+\]|\[\*\]|\[\]|)\s*(<=|>=|==|<|>)\s*(\S*)$/.exec(src); + if (matches == null) return null; + var name = matches[1]; + var index = matches[2]; index = index == "" ? "*" : index.substring(1,index.length-1); + var operator = matches[3]; + var threshold = parseFloat(matches[4]); // TODOXXX what about other types?; accepts 40foobar + if (isNaN(threshold)) return null; + + console.log ("create predicate " + name + " : " + index + " : " + operator + " : " + threshold) + + return new Predicate(name,index,operator,threshold); +} + +// ---------------------------------------------------------------------- + +var updateInterval = 10000; // milliseconds +var updateIntervalID = 1; + +function setUpdateInterval(i) { + if (updateIntervalID >= 0) { clearInterval(updateIntervalID); } + if (i > updateInterval) { pm_context = -1; } // will likely need a new context + updateInterval = i; + updateIntervalID = setInterval(updateBlinkenlights, updateInterval); +} + +// default mode +var pm_context_type = "hostspec"; +var pm_context_spec = "localhost"; + +function setPMContextType(k) { + pm_context_type = k; + pm_context = -1; + updateBlinkenlights(); +} +function setPMContextSpec(i) { + pm_context_spec = i; + pm_context = -1; + updateBlinkenlights(); +} + + +function updateBlinkenlights() { + var pm_url; + + if (pm_context < 0) { + pm_url = pm_root + + "/context?" + + pm_context_type + "=" + encodeURIComponent(pm_context_spec) + + "&polltimeout=" + Math.floor(5*updateInterval/1000); + $.getJSON(pm_url, function(data, status) { + pm_context = data.context; + setTimeout(updateBlinkenlights, 100); // retry soon + }).error(function() { pm_context = -1; }); + return; // will retry one cycle later + } + + if(predicates.length == 0) { + $("#blinkenlights").html("<b>No predicates requested...</b>"); + return; + } + + // ajax request for JSON data + pm_url = pm_root + "/" + pm_context + "/_fetch?names="; + $.each(predicates, function(i, predicate) { + if (i > 0) pm_url += ","; + pm_url += predicate.name; + }); + $.getJSON(pm_url, function(data, status) { + // update data_dict + var data_dict = {}; + $.each(data.values, function(i, value) { + data_dict[value.name] = value; + }); + // update status field + theDate = new Date(0); + theDate.setUTCSeconds(data.timestamp.s); + theDate.setUTCMilliseconds(data.timestamp.us/1000); + $("#status").html("Timestamp: " + theDate.toString()); + // update the view + $("#blinkenlights").empty(); + $.each(predicates, function(i, predicate) { + predicate.test($("#blinkenlights"), data_dict); + }); + }).error(function() { + $("#blinkenlights").html("<b>error accessing server, retrying...</b>"); + pm_context = -1; }); +} + +function loadBlinkenlights() { + $("#header").html("pcp blinkenlights demo"); + $("#content").html("<ul id=\"blinkenlights\"><li>loading...</li></ul>"); + + // start timer for updateBlinkenlights + updateBlinkenlights(); + setUpdateInterval(updateInterval); +} + +$(document).ready(function() { + loadBlinkenlights(); + // TODOXXX add support for editing mode +}); diff --git a/src/pmwebapi/jsdemos/blinkenlights/index.html b/src/pmwebapi/jsdemos/blinkenlights/index.html new file mode 100644 index 0000000..cf2e4fd --- /dev/null +++ b/src/pmwebapi/jsdemos/blinkenlights/index.html @@ -0,0 +1,129 @@ +<html> + <meta http-equiv="Content-type" content="text/html;charset=UTF-8"> + <head> + <link rel="stylesheet" href="../jquery-ui-themes-1.10.2/themes/humanity/jquery-ui.css"> + <script type="text/javascript" src="../jquery-1.7.2.js"></script> + <script type="text/javascript" src="../jquery-ui-1.10.2.js"></script> + <script type="text/javascript" src="blinkenlights.js"></script> + <script type="text/javascript"> + /* Query string handling */ + var qs = (function(a) { + if (a == "") return {}; + var b = {}; + for (var i = 0; i < a.length; ++i) + { + var p=a[i].split('='); + if (p.length != 2) continue; + b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " ")); + } + return b; + })(window.location.search.substr(1).split('&')); + + if ("predicates" in qs) { + raw_predicates = qs["predicates"].split('@'); + for (var i = 0; i < raw_predicates.length; i++) { + if (raw_predicates[i] == "") continue; + p = parsePredicate(raw_predicates[i]); + if (p == null) { alert("cannot parse " + predicates[i]); } + else { predicates.push(p); } + } + } else { + p = parsePredicate("kernel.all.load[*] > 0.2"); + if (p == null) { alert("cannot parse " + predicates[i]); } + else { predicates.push(p); } + } + + if ("contexttype" in qs) { + pm_context_type=qs["contexttype"]; + } + + if ("contextspec" in qs) { + pm_context_spec=qs["contextspec"]; + } + + if ("updateInterval" in qs) { + updateInterval = qs["updateInterval"]; + } + + function saveQueryString() { + raw_predicates = []; + for (var i = 0; i < predicates.length; i++) + raw_predicates.push(predicates[i].to_string()); + str = $.param({ + predicates: raw_predicates.join('@'), + updateInterval: updateInterval, + contexttype: pm_context_type, + contextspec: pm_context_spec + }); + str = location.protocol + "//" + location.hostname + ":" + location.port + location.pathname + "?" + str; // TODOXXX + $("#permalink_uri").html(str); + $("#permalink_uri").attr("href", str); + } + + /* Set up document */ + $(document).ready(function() { + $("#predicate_form").submit(function() { + pstr = $("#predicate_input").val(); + p = parsePredicate(pstr); + if (p == null) { alert("cannot parse " + pstr); } else { predicates.push(p); } + saveQueryString(); + return false; // stay on this page + }); + $("#predicate_clear_form").submit(function() { + predicates = []; + saveQueryString(); + return false; // stay on this page + }); + $("#interval").val(updateInterval); + $("#interval-slider").slider({ + value: updateInterval, min: 1000, max: 10000, + slide: function (event, ui) { + setUpdateInterval(ui.value); + saveQueryString(); + $("#interval").val(updateInterval); + } + }); + $("#contexttype").val(pm_context_type); + $("#contextspec").val(pm_context_spec); + $("#contextspec_form").submit(function() { + setPMContextType($("#contexttype").val()); + setPMContextSpec($("#contextspec").val()); + saveQueryString(); + return false; // stay on this page + }); + $("#predicate_input").val("kernel.all.load[*] > 0.2"); + saveQueryString(); // set up initial permalink + }); + </script> + <link rel="stylesheet" type="text/css" href="blinkenlights.css" /> + <title>pcp blinkenlights demo</title> + </head> + <body> + <h1 id="header"></h1> + <form id="contextspec_form"> + <select id="contexttype"> + <option>hostspec</option> + <option>archivefile</option> + <option>local</option> + </select> + <input type="text" size="50" id="contextspec" /> + <input value="Connect" type="submit" /> + </form> + <form id="predicate_form"> + <input id="predicate_input" size="50" type="text" /> + <input value="Add Predicate" type="submit" /> + </form> + <form id="predicate_clear_form"> + <input value="Clear Predicates" type="submit" /> + </form> + <span id="interval-slider-label"><label for="interval">Refresh interval (ms):</label><input type="text" size="5" id="interval" readonly /></span> + <div id="interval-slider"></div> + <p id="status"></p> + <div id="content"></div> + <p id="permalink">permalink: <a href="#" id="permalink_uri"></a></p> + <!--<footer> + <p id="permalink">permalink: <span></span> (<a>copy</a>)</p> + <p id="editlink"></p> + </footer>--> + </body> +</html> |