diff options
Diffstat (limited to 'test/monitoring/monitor.js')
-rw-r--r-- | test/monitoring/monitor.js | 431 |
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, '&').replace(/</g, '<').replace(/>/g, '>'); + 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>'; + }); +} + |