view 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 source

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();