summaryrefslogtreecommitdiffstats
path: root/test/monitoring/monitor.js
diff options
context:
space:
mode:
Diffstat (limited to 'test/monitoring/monitor.js')
-rw-r--r--test/monitoring/monitor.js431
1 files changed, 431 insertions, 0 deletions
diff --git a/test/monitoring/monitor.js b/test/monitoring/monitor.js
new file mode 100644
index 00000000..c4f24a00
--- /dev/null
+++ b/test/monitoring/monitor.js
@@ -0,0 +1,431 @@
+
+var afb;
+var ws;
+
+var t_api;
+var t_verb;
+var t_logmsg;
+var t_traceevent;
+var t_verbosity;
+var t_trace;
+var apis = {};
+var events = [];
+var inhibit = false;
+var msgs = false;
+
+var root_node;
+var connected_node;
+var trace_events_node;
+var logmsgs_node;
+var apis_node;
+var all_node;
+
+/* flags */
+var show_perms = false;
+var show_monitor_events = false;
+
+_.templateSettings = { interpolate: /\{\{(.+?)\}\}/g };
+
+function untrace_all() {
+ do_call("monitor/trace", {drop: true});
+ for_all_nodes(null, ".trace-item input[type=radio]", function(n){n.checked = n.value == "no";});
+}
+
+function disconnect() {
+ untrace_all();
+ apis = {};
+ apis_node.innerHTML = "";
+ root_node.className = "off";
+ connected_node.innerHTML = "Connection Closed";
+ connected_node.className = "ok";
+ ws && ws.close();
+ afb = null;
+ ws = null;
+}
+
+function connect(args) {
+ drop_all_trace_events();
+ drop_all_logmsgs();
+ ws && ws.close();
+ afb = new AFB(args);
+ ws = new afb.ws(onopen, onabort);
+}
+
+function on_connect(evt) {
+ connect({
+ host: at("param-host").value + ":" + at("param-port").value,
+ token: at("param-token").value
+ });
+}
+
+function init() {
+ /* prepare the DOM templates */
+ t_api = at("t-api").content.firstElementChild;
+ t_verb = at("t-verb").content.firstElementChild;
+ t_logmsg = at("t-logmsg").content.firstElementChild;
+ t_traceevent = at("t-traceevent").content.firstElementChild;
+ t_verbosity = at("t-verbosity").content.firstElementChild;
+ t_trace = at("t-trace").content.firstElementChild;
+
+ root_node = at("root");
+ connected_node = at("connected");
+ trace_events_node = at("trace-events");
+ logmsgs_node = at("logmsgs");
+ apis_node = at("apis");
+ all_node = at("all");
+
+ plug(t_api, ".verbosity", t_verbosity);
+ plug(t_api, ".trace", t_trace);
+ plug(all_node, ".trace", t_trace);
+ plug(all_node, ".verbosity", t_verbosity);
+ plug(at("common"), ".verbosity", t_verbosity);
+ for_all_nodes(root_node, ".opclo", function(n){n.onclick = on_toggle_opclo});
+ for_all_nodes(root_node, ".opclo ~ :not(.closedoff)", function(n){n.onclick = on_toggle_opclo});
+ for_all_nodes(root_node, ".verbosity select", function(n){n.onchange = set_verbosity});
+ for_all_nodes(root_node, ".trace-item input", function(n){n.onchange = on_trace_change});
+ at("disconnect").onclick = disconnect;
+ at("connect").onclick = on_connect;
+ at("droptracevts").onclick = drop_all_trace_events;
+ at("dropmsgs").onclick = drop_all_logmsgs;
+ at("stopmsgs").onclick = toggle_logmsgs;
+ start_logmsgs(false);
+ trace_events_node.onclick = on_toggle_traceevent;
+
+ connect();
+}
+
+function for_all_nodes(root, sel, fun) {
+ (root ? root : document).querySelectorAll(sel).forEach(fun);
+}
+
+function get(sel,x) {
+ if (!x)
+ x = document;
+ var r = x.querySelector(sel);
+ return r;
+}
+function at(id) { return document.getElementById(id); }
+
+function plug(target, sel, node) {
+ var x = get(sel, target);
+ var n = target.ownerDocument.importNode(node, true);
+ x.parentNode.insertBefore(n, x);
+ x.parentNode.removeChild(x);
+}
+
+function onopen() {
+ root_node.className = "on";
+ connected_node.innerHTML = "Connected " + ws.url;
+ connected_node.className = "ok";
+ ws.onevent("*", gotevent);
+ ws.onclose = onabort;
+ do_call("monitor/get", {apis:true,verbosity:true}, on_got_apis, on_error_apis);
+}
+function onabort() {
+ root_node.className = "off";
+ connected_node.innerHTML = "Connection Closed";
+ connected_node.className = "error";
+}
+
+function start_logmsgs(val) {
+ at("stopmsgs").textContent = (msgs = val) ? "Stop logs" : "Get logs";
+}
+
+function toggle_logmsgs() {
+ start_logmsgs(!msgs);
+}
+
+function drop_all_logmsgs() {
+ logmsgs_node.innerHTML = "";
+}
+
+function drop_all_trace_events() {
+ trace_events_node.innerHTML = "";
+}
+
+function add_logmsg(tag, content, add) {
+ if (!msgs) return;
+ var x = document.importNode(t_logmsg, true);
+ get(".tag", x).textContent = tag;
+ get(".content", x).textContent = content;
+ get(".close", x).onclick = function(evt){x.remove();};
+ if (add)
+ x.className = x.className + " " + add;
+ logmsgs_node.prepend(x);
+}
+
+function add_error(tag, obj) {
+ add_logmsg(tag, JSON.stringify(obj, null, 1), "error");
+}
+
+function on_error_apis(obj) {
+ add_error("can't get apis", obj);
+}
+
+function do_call(api_verb, request, onsuccess, onerror) {
+ var call = api_verb + "(" + JSON.stringify(request, null, 1) + ")";
+ add_logmsg(call, "", "call");
+ ws.call(api_verb, request).then(
+ function(obj){
+ add_logmsg(call + " SUCCESS:", JSON.stringify(obj, null, 1), "retok");
+ if (onsuccess)
+ onsuccess(obj);
+ },
+ function(obj){
+ add_logmsg(call + " ERROR:", JSON.stringify(obj, null, 1), "reterr");
+ if (onerror)
+ onerror(obj);
+ });
+}
+
+/* show all verbosities */
+function on_got_verbosities(obj) {
+ inhibit = true;
+ _.each(obj.response.verbosity, function(verbosity, api_name){
+ if (api_name == "monitor") return;
+ var node = api_name ? apis[api_name].node : at("common");
+ if (node)
+ get(".verbosity option[value='"+verbosity+"']", node).selected = true;
+ });
+ inhibit = false;
+}
+
+function set_verbosity(evt) {
+ if (inhibit) return;
+ inhibit = true;
+ var obj = evt.target;
+ var req = {verbosity:{}};
+ var name = obj.API ? obj.API.name : obj === get(".select", all_node) ? "*" : "";
+ if (name != "*") {
+ req.verbosity[name] = obj.value;
+ } else {
+ req.verbosity = obj.value;
+ }
+ inhibit = false;
+ do_call("monitor/set", req);
+ do_call("monitor/get", {verbosity:true}, on_got_verbosities);
+}
+
+/* show all apis */
+function on_got_apis(obj) {
+ inhibit = true;
+ _.each(obj.response.apis, function(api_desc, api_name){
+ if (api_name == "monitor") return;
+ var api = apis[api_name];
+ if (!api) {
+ api = {
+ node: document.importNode(t_api, true),
+ verbs: {},
+ name: api_name
+ };
+ api.node.API = api;
+ api.node.dataset.api = api_name;
+ api.vnode = get(".verbs", api.node);
+ apis[api_name] = api;
+ get(".name", api.node).textContent = api_name;
+ get(".desc", api.node).textContent = api_desc.info.description || "";
+ for_all_nodes(api.node, ".opclo", function(n){n.onclick = on_toggle_opclo});
+ for_all_nodes(api.node, ".opclo ~ :not(.closedoff)", function(n){n.onclick = on_toggle_opclo});
+ for_all_nodes(api.node, ".trace-item input", function(n){n.onchange = on_trace_change});
+ apis_node.append(api.node);
+ _.each(api_desc.paths, function(verb_desc, path_name){
+ var verb_name = path_name.substring(1);
+ var verb = api.verbs[verb_name];
+ if (!verb) {
+ verb = {
+ node: document.importNode(t_verb, true),
+ name: verb_name,
+ api: api
+ };
+ verb.node.VERB = verb;
+ verb.node.dataset.verb = verb_name;
+ api.verbs[verb_name] = verb;
+ get(".name", verb.node).textContent = verb_name;
+ var g = verb_desc.get ||{};
+ var r = g["responses"] || {};
+ var t = r["200"] || {};
+ var d = t.description || "";
+ get(".desc", verb.node).textContent = d;
+ if (show_perms) {
+ var p = g["x-permissions"] || "";
+ get(".perm", verb.node).textContent = p ? JSON.stringify(p, null, 1) : "";
+ }
+ api.vnode.append(verb.node);
+ }
+ });
+ var s = get(".verbosity select", api.node);
+ s.API = api;
+ s.onchange = set_verbosity;
+ }
+ });
+ inhibit = false;
+ on_got_verbosities(obj);
+}
+
+function on_toggle_opclo(evt) {
+ toggle_opened_closed(evt.target.parentElement);
+}
+
+function on_trace_change(evt) {
+ var obj = evt.target;
+ var tra = obj.parentElement;
+ while (tra && !tra.dataset.trace)
+ tra = tra.parentElement;
+ var api = tra;
+ while (api && !api.dataset.api)
+ api = api.parentElement;
+ var tag = api.dataset.api + "/" + tra.dataset.trace;
+ if (tra) {
+ var drop = false;
+ for_all_nodes(tra, "input", function(n){
+ if (n.checked) {
+ n.checked = false;
+ if (n != obj && n.value != "no")
+ drop = true;
+ }
+ });
+ if (drop)
+ do_call("monitor/trace", {drop: {tag: tag}});
+ obj.checked = true;
+ if (obj.value != "no") {
+ var spec = {tag: tag, name: "trace"};
+ spec[tra.dataset.trace] = obj.value;
+ if (api.dataset.api != "*")
+ spec.api = api.dataset.api;
+ do_call("monitor/trace", {add: spec});
+ }
+ }
+}
+
+function makecontent(node, deep, val) {
+ if (--deep > 0) {
+ if (_.isObject(val)) {
+ node.append(makeobj(val, deep));
+ return;
+ }
+ if (_.isArray(val)) {
+ node.append(makearr(val, deep));
+ return;
+ }
+ }
+ node.innerHTML = obj2html(val);
+}
+
+function makearritem(tbl, deep, val) {
+ var tr = document.createElement("tr");
+ var td = document.createElement("td");
+ tr.append(td);
+ tbl.append(tr);
+ makecontent(td, deep, val);
+}
+
+function makearr(arr, deep) {
+ var node = document.createElement("table");
+ node.className = "array";
+ _.each(arr, function(v) { makearritem(node, deep, v);});
+ return node;
+}
+
+function makeobjitem(tbl, deep, key, val) {
+ var tr = document.createElement("tr");
+ var td1 = document.createElement("td");
+ var td2 = document.createElement("td");
+ tr.className = key;
+ tr.append(td1);
+ td1.textContent = key;
+ tr.append(td2);
+ tbl.append(tr);
+ makecontent(td2, deep, val);
+}
+
+function makeobj(obj, deep, ekey, eobj) {
+ var node = document.createElement("table");
+ node.className = "object";
+ _.each(_.keys(obj).sort(), function(k) { makeobjitem(node, deep, k, obj[k]);});
+ if (ekey)
+ makeobjitem(node, deep, ekey, eobj);
+ return node;
+}
+
+function gotevent(obj) {
+ if (obj.event != "monitor/trace")
+ add_logmsg("unexpected event!", JSON.stringify(obj, null, 1), "event");
+ else {
+ add_logmsg("trace event", JSON.stringify(obj, null, 1), "trace");
+ gottraceevent(obj);
+ }
+}
+
+function gottraceevent(obj) {
+ var data = obj.data;
+ var type = _.find(["request", "service", "daemon", "event"],function(x){return x in data;});
+ var desc = data[type];
+ if (!show_monitor_events) {
+ if (type == "event" ? desc.name.startsWith("monitor/") : desc.api == "monitor")
+ return;
+ }
+ var x = document.importNode(t_traceevent, true);
+ x.dataset.event = obj;
+ get(".close", x).onclick = function(evt){x.remove();};
+ x.className = x.className + " " + type;
+ get(".time", x).textContent = data.time;
+ get(".tag", x).textContent = ({
+ request: function(r) { return r.api + "/" + r.verb + " [" + r.index + "] " + r.action; },
+ service: function(r) { return r.api + "@" + r.action; },
+ daemon: function(r) { return r.api + ":" + r.action; },
+ event: function(r) { return r.name + "!" + r.action; },
+ })[type](desc);
+ var tab = makeobj(desc, 4);
+ if ("data" in data)
+ makeobjitem(tab, 1, "data", data.data);
+ get(".content", x).append(tab);
+ trace_events_node.append(x);
+}
+
+function toggle_opened_closed(node, defval) {
+ var matched = false;
+ var cs = node.className.split(" ").map(
+ function(x){
+ if (!matched) {
+ switch(x) {
+ case "closed": matched = true; return "opened";
+ case "opened": matched = true; return "closed";
+ }
+ }
+ return x;
+ }).join(" ");
+ if (!matched)
+ cs = cs + " " + (defval || "closed");
+ node.className = cs;
+}
+
+function on_toggle_traceevent(evt) {
+ if (getSelection() != "") return;
+ var node = evt.target;
+ while(node && node.parentElement != trace_events_node)
+ node = node.parentElement;
+ node && toggle_opened_closed(node);
+}
+
+function obj2html(json) {
+ json = JSON.stringify(json, undefined, 2);
+ json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
+ return json.replace(
+ /("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g,
+ function (match) {
+ var cls = 'number';
+ if (/^"/.test(match)) {
+ if (/:$/.test(match)) {
+ cls = 'key';
+ } else {
+ cls = 'string';
+ }
+ } else if (/true|false/.test(match)) {
+ cls = 'boolean';
+ } else if (/null/.test(match)) {
+ cls = 'null';
+ }
+ return '<span class="json ' + cls + '">' + match + '</span>';
+ });
+}
+