diff console/src/main.ts @ 6:b1043d39e493

start web console
author drewp@bigasterisk.com
date Mon, 13 Mar 2023 18:53:45 -0700
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/console/src/main.ts	Mon Mar 13 18:53:45 2023 -0700
@@ -0,0 +1,143 @@
+import { startOfDay, subDays, differenceInMinutes, getUnixTime, addDays, format, min, formatISO } from "date-fns";
+import * as echarts from "echarts";
+import { TabulatorFull as Tabulator } from "tabulator-tables";
+
+const QUERY_RANGE = "https://bigasterisk.com/m/prometheus/api/v1/query_range";
+const MAC = new Map([
+]);
+
+function progQueryUrl(prog: string, s: Date, e: Date): URL {
+  const rangeMins = differenceInMinutes(e, s);
+  const out = new URL(QUERY_RANGE);
+
+  const host = "Kelsis-iMac";
+  const isRunningQl = `racc_running{prog="${prog}",host="${host}"}`;
+  const isNonIdleQl = `max(racc_idle{host="${host}"}) < 100`;
+  const countedTimeQl = `(${isRunningQl}) if (${isNonIdleQl})`;
+  const integralQl = `integrate((${countedTimeQl})[${rangeMins}m])`;
+  const hoursQl = `${integralQl}/1h`;
+
+  out.searchParams.append("query", hoursQl);
+  out.searchParams.append("start", "" + getUnixTime(s));
+  out.searchParams.append("end", "" + getUnixTime(e));
+  out.searchParams.append("step", "1m");
+  return out;
+}
+
+async function queryLastRow(queryUrl: URL): Promise<string> {
+  const response = await fetch(queryUrl);
+  const body = await response.json();
+  if (!body?.data?.result) {
+    return "0";
+  }
+  const m = body.data.result[0];
+  if (m?.values?.length) {
+    const lastRow = m.values[m.values.length - 1];
+    return parseFloat(lastRow[1]).toFixed(2);
+  }
+  return "0";
+}
+
+async function makeSeries(now: Date, meas: string, prog: string, numDays: number): Promise<echarts.BarSeriesOption> {
+  const rows = [];
+  const sod = startOfDay(now);
+
+  for (let i = numDays-1 ; i >= 0; i--) {
+    const s = subDays(sod, i);
+    const e = min([now, addDays(s, 1)]);
+    console.log(i, formatISO(s), formatISO(e));
+    rows.push(queryLastRow(progQueryUrl(prog, s, e)));
+  }
+  const mc = await Promise.all(rows);
+
+  return {
+    name: meas,
+    type: "bar",
+    animation: false,
+    data: mc,
+    emphasis: { focus: "series" },
+    label: { show: true },
+    stack: "total",
+    
+  };
+}
+
+function dateRowLabels(now: Date, days: number) {
+  const rowNames = [];
+  for (let d = subDays(now, days - 1); d < now; d = addDays(d, 1)) {
+    rowNames.push(format(d, "MM/dd EEE"));
+  }
+  rowNames.push(format(now, "MM/dd EEE") + " (today)");
+  return rowNames;
+}
+
+function fillDebugTable(el: HTMLElement) {
+  var rows = [];
+
+  const vmui = (expr: string, range: string): string =>
+    "https://bigasterisk.com/m/vmui/?" +
+    "g0.expr=" +
+    encodeURIComponent(expr) + //
+    "&g0.range_input=" +
+    encodeURIComponent(range);
+  const view = (url: string): string => `<a href="${url}">view</a>`;
+  for (let host of ["Kelsis-iMac", "dash", "dot", "plus"]) {
+    rows.push({
+      id: rows.length,
+      host: host,
+      metrics: view(`http://${host}:5150/metrics`),
+      uptime: view(vmui(`python_info{job="racc",instance="${host}:5150"}`, "14d")),
+      traffic: view(vmui(`rate(lan_bytes_sent_from_total{mac="${MAC.get(host)}"})`, "6h")),
+    });
+  }
+  var table = new Tabulator(el, {
+    data: rows,
+    columns: [
+      { title: "Host", field: "host" },
+      { title: "current /metrics", field: "metrics", formatter: "html" },
+      { title: "racc uptime history", field: "uptime", formatter: "html" },
+      { title: "outgoing net traffic", field: "traffic", formatter: "html" },
+    ],
+  });
+}
+
+async function main() {
+  fillDebugTable(document.getElementById("debug1")!);
+
+  const now = new Date();
+
+  const chartDom = document.getElementById("chart1")!;
+  const chart = echarts.init(chartDom);
+
+  const nDays = 8;
+  const rowNames = dateRowLabels(now, nDays);
+
+  const option: echarts.EChartsOption = {
+    tooltip: {
+      trigger: "axis",
+      axisPointer: {
+        type: "shadow",
+      },
+    },
+    legend: {},
+    grid: {
+      left: "0%",
+      containLabel: true,
+    },
+    xAxis: {
+      type: "value",
+      max: 10,
+    },
+    yAxis: {
+      type: "category",
+      data: rowNames,
+    },
+    series: await Promise.all([
+      makeSeries(now, "Minecraft hours", "minecraft", nDays), //
+      makeSeries(now, "Roblox hours", "roblox", nDays),
+    ]),
+  };
+console.log(option);
+  chart.setOption(option);
+}
+main();