diff options
author | Oscar Najera <hi@oscarnajera.com> | 2025-04-27 22:33:44 +0200 |
---|---|---|
committer | Oscar Najera <hi@oscarnajera.com> | 2025-04-27 22:33:44 +0200 |
commit | b46f51a0b3e2e1eb4262c393ac9468802de86c67 (patch) | |
tree | e380b9eff0971b37ebf320b7c7ced9eb35388974 /webstats/plots.js | |
parent | bb83ef6079eef26fb82f8578564238297b7c0b91 (diff) | |
download | scratch-b46f51a0b3e2e1eb4262c393ac9468802de86c67.tar.gz scratch-b46f51a0b3e2e1eb4262c393ac9468802de86c67.tar.bz2 scratch-b46f51a0b3e2e1eb4262c393ac9468802de86c67.zip |
work for robots text
Diffstat (limited to 'webstats/plots.js')
-rw-r--r-- | webstats/plots.js | 317 |
1 files changed, 317 insertions, 0 deletions
diff --git a/webstats/plots.js b/webstats/plots.js new file mode 100644 index 0000000..d861450 --- /dev/null +++ b/webstats/plots.js @@ -0,0 +1,317 @@ +function isObject(value) { + return ( + value !== null && + typeof value === "object" && + !Array.isArray(value) && + !(value instanceof Element) + ); +} +function attrTrans(key) { + switch (key) { + case "class": + return "className"; + case "for": + return "htmlFor"; + default: + return key; + } +} +var tagRe = /([^\s.#]+)(?:#([^\s.#]+))?(?:.([^\s#]+))?/; +function domTag(infoTag) { + var _db1 = infoTag.match(tagRe); + var _ = _db1[0]; + var tag = _db1[1]; + var id = _db1[2]; + var className = _db1[3]; + var el = document.createElement(tag); + if (id) { + el.id = id; + } + if (className) { + el.className = className.replaceAll(".", " "); + } + __PS_MV_REG = []; + return el; +} +function fillAttrs(el, attrs) { + if (isObject(attrs)) { + for (var key in attrs) { + if (key.startsWith("data-")) { + el.setAttribute(key, attrs[key]); + } else if (key === "style") { + Object.assign(el[key], attrs[key]); + } else { + el[attrTrans(key)] = attrs[key]; + } + } + __PS_MV_REG = []; + return true; + } +} +function domEl() { + var params = Array.prototype.slice.call(arguments, 0); + if (Array.isArray(params[0])) { + __PS_MV_REG = []; + return domEl.apply(this, params[0]); + } else { + var el = domTag(params[0]); + var contents = params.slice(fillAttrs(el, params[1]) ? 2 : 1); + for (const arg of contents) { + if (Array.isArray(arg)) { + el.appendChild(domEl(arg)); + } else if (arg instanceof Element) { + el.appendChild(arg); + } else if (arg && typeof arg === "string") { + el.appendChild(document.createTextNode(arg)); + } + } + __PS_MV_REG = []; + return el; + } +} +function logger(level, obj) { + var objects = Array.prototype.slice.call(arguments, 2); + console[level].apply(console, [obj].concat(objects)); + __PS_MV_REG = []; + return obj; +} +function responseToJson(response) { + if (response.ok) { + __PS_MV_REG = []; + return response.json().then(function (value) { + if (value["error"]) { + throw new Error(value["error"]); + } else { + __PS_MV_REG = []; + return value; + } + }); + } else { + throw new Error("not 2XX resp"); + } +} +function csvFloat(data) { + let headers = data[0]; + let series = headers.map((_, idx) => + data.slice(1).map((row) => parseFloat(row[idx])), + ); + return [headers, series]; +} +function responseParseCSV(response) { + if (response.ok) + return response.text().then((data) => + data + .split(/\n/) + .filter((x) => x) + .map((row) => row.split(/,/)), + ); + throw new Error("not 2XX resp"); +} + +function withSuffix(val, suffix) { + return val.toFixed(1).replace(/.?0+$/, "").concat("", suffix); +} +function siScaling(value) { + var v = Math.abs(value); + return 0 === v + ? [0, ""] + : v >= 1000000000000000.0 + ? [value / 1000000000000000.0, "P"] + : v >= 1000000000000.0 + ? [value / 1000000000000.0, "T"] + : v >= 1000000000.0 + ? [value / 1000000000.0, "G"] + : v >= 1000000.0 + ? [value / 1000000.0, "M"] + : v >= 1000.0 + ? [value / 1000.0, "K"] + : v >= 0.6 + ? [value, ""] + : v >= 0.001 + ? [value / 0.001, "m"] + : v >= 0.000001 + ? [value / 0.000001, "μ"] + : v >= 0.000000001 + ? [value / 0.000000001, "n"] + : v >= 0.000000000001 + ? [value / 0.000000000001, "p"] + : null; +} +function scaling(val) { + return withSuffix.apply(this, siScaling(val)); +} + +function spacedColor(idx, alpha) { + if (alpha === undefined) { + alpha = "/ 1"; + } + return "hsl(" + 137.506 * idx + " 70% 55% " + alpha + ")"; +} + +function makeChart(data, container) { + const opts = { + title: "Server Events", + width: 920, + height: 600, + // ms: 1, + // cursor: { + // x: false, + // y: false, + // }, + series: [ + {}, + { + label: "hits", + stroke: "red", + // scale: "%", + value: (u, v) => scaling(v), + // width: 1 / devicePixelRatio, + }, + // { + // label: "visits", + // stroke: "blue", + // // scale: "%", + // // value: (u, v) => (v == null ? null : v.toFixed(1) + "%"), + // // width: 1 / devicePixelRatio, + // }, + { + label: "tx", + scale: "mb", + stroke: "green", + value: (u, v) => (v == null ? null : scaling(v) + "B"), + width: 1 / devicePixelRatio, + }, + ], + axes: [ + {}, + { + values: (u, vals, space) => vals.map(scaling), + }, + { + side: 1, + scale: "mb", + size: 60, + values: (u, vals, space) => vals.map((v) => scaling(v) + "B"), + grid: { show: false }, + stroke: "green", + }, + ], + }; + + let uplot = new uPlot(opts, data, container); + container["uobj"] = uplot; +} + +function agentChart(header, series, container) { + const opts = { + width: 920, + height: 600, + hooks: { + setSeries: [ + (u, seriesIdx, opts) => { + if (opts.focus != null) { + u.series.forEach((s, i) => { + s.width = i == seriesIdx ? 3 : 1; + }); + } + }, + ], + }, + focus: { alpha: 0.5 }, + cursor: { + focus: { + prox: 1e6, + bias: 0, + dist: (self, seriesIdx, dataIdx, valPos, curPos) => { + return valPos - curPos; + }, + }, + }, + + series: [ + {}, + { + label: header[1], + stroke: "black", + dash: [10, 5], + value: (u, v) => scaling(v), + scale: "hits", + }, + ].concat( + header.slice(2).map((name, idx) => ({ + label: name, + stroke: spacedColor(idx), + fill: spacedColor(idx, "/ 0.1"), + value: (u, v) => scaling(v) + "B", + })), + ), + axes: [ + {}, + { + values: (u, vals, space) => vals.map((v) => (v ? scaling(v) + "B" : v)), + size: 60, + label: "Bandwidth", + labelSize: 50, + }, + { + side: 1, + scale: "hits", + label: "Requests", + grid: { show: false }, + values: (u, vals, space) => vals.map((v) => (v ? scaling(v) : v)), + labelSize: 50, + }, + ], + }; + let uplot = new uPlot(opts, series, container); + container["uobj"] = uplot; +} +addEventListener("load", () => { + fetch("/top_agent_traffic.csv") + .then(responseParseCSV) + .then(csvFloat) + .then(([headers, series]) => { + let cont = document.querySelector("#agent-traffic").parentNode; + cont.innerHTML = ""; + agentChart(headers, series, cont); + }); + + fetch("/fails.csv") + .then(responseParseCSV) + .then((data) => { + let headers = data[0]; + return data + .slice(1) + .map((row) => [ + "tr", + ["td.org-right", scaling(parseFloat(row[0]))], + ["td.org-right", scaling(parseFloat(row[1])) + "B"], + ["td.org-left", decodeURI(row[2])], + ]); + }) + .then((series) => { + let table = [ + "table", + { + border: 2, + cellPadding: 6, + cellSpacing: 0, + rules: "groups", + frame: "hsides", + }, + [ + "thead", + [ + "tr", + ["th.org-right", "hits"], + ["th.org-right", "tx"], + ["th.org-left", "path"], + ], + ], + ]; + let tbody = ["tbody"].concat(series); + table.push(tbody); + console.log(table); + document.body.appendChild(domEl(table)); + }); +}); |