6
|
1 import { startOfDay, subDays, differenceInMinutes, getUnixTime, addDays, format, min, formatISO } from "date-fns";
|
|
2 import * as echarts from "echarts";
|
|
3 import { TabulatorFull as Tabulator } from "tabulator-tables";
|
|
4
|
|
5 const QUERY_RANGE = "https://bigasterisk.com/m/prometheus/api/v1/query_range";
|
|
6 const MAC = new Map([
|
|
7 ]);
|
|
8
|
|
9 function progQueryUrl(prog: string, s: Date, e: Date): URL {
|
|
10 const rangeMins = differenceInMinutes(e, s);
|
|
11 const out = new URL(QUERY_RANGE);
|
|
12
|
|
13 const host = "Kelsis-iMac";
|
|
14 const isRunningQl = `racc_running{prog="${prog}",host="${host}"}`;
|
|
15 const isNonIdleQl = `max(racc_idle{host="${host}"}) < 100`;
|
|
16 const countedTimeQl = `(${isRunningQl}) if (${isNonIdleQl})`;
|
|
17 const integralQl = `integrate((${countedTimeQl})[${rangeMins}m])`;
|
|
18 const hoursQl = `${integralQl}/1h`;
|
|
19
|
|
20 out.searchParams.append("query", hoursQl);
|
|
21 out.searchParams.append("start", "" + getUnixTime(s));
|
|
22 out.searchParams.append("end", "" + getUnixTime(e));
|
|
23 out.searchParams.append("step", "1m");
|
|
24 return out;
|
|
25 }
|
|
26
|
|
27 async function queryLastRow(queryUrl: URL): Promise<string> {
|
|
28 const response = await fetch(queryUrl);
|
|
29 const body = await response.json();
|
|
30 if (!body?.data?.result) {
|
|
31 return "0";
|
|
32 }
|
|
33 const m = body.data.result[0];
|
|
34 if (m?.values?.length) {
|
|
35 const lastRow = m.values[m.values.length - 1];
|
|
36 return parseFloat(lastRow[1]).toFixed(2);
|
|
37 }
|
|
38 return "0";
|
|
39 }
|
|
40
|
|
41 async function makeSeries(now: Date, meas: string, prog: string, numDays: number): Promise<echarts.BarSeriesOption> {
|
|
42 const rows = [];
|
|
43 const sod = startOfDay(now);
|
|
44
|
|
45 for (let i = numDays-1 ; i >= 0; i--) {
|
|
46 const s = subDays(sod, i);
|
|
47 const e = min([now, addDays(s, 1)]);
|
|
48 console.log(i, formatISO(s), formatISO(e));
|
|
49 rows.push(queryLastRow(progQueryUrl(prog, s, e)));
|
|
50 }
|
|
51 const mc = await Promise.all(rows);
|
|
52
|
|
53 return {
|
|
54 name: meas,
|
|
55 type: "bar",
|
|
56 animation: false,
|
|
57 data: mc,
|
|
58 emphasis: { focus: "series" },
|
|
59 label: { show: true },
|
|
60 stack: "total",
|
|
61
|
|
62 };
|
|
63 }
|
|
64
|
|
65 function dateRowLabels(now: Date, days: number) {
|
|
66 const rowNames = [];
|
|
67 for (let d = subDays(now, days - 1); d < now; d = addDays(d, 1)) {
|
|
68 rowNames.push(format(d, "MM/dd EEE"));
|
|
69 }
|
|
70 rowNames.push(format(now, "MM/dd EEE") + " (today)");
|
|
71 return rowNames;
|
|
72 }
|
|
73
|
|
74 function fillDebugTable(el: HTMLElement) {
|
|
75 var rows = [];
|
|
76
|
|
77 const vmui = (expr: string, range: string): string =>
|
|
78 "https://bigasterisk.com/m/vmui/?" +
|
|
79 "g0.expr=" +
|
|
80 encodeURIComponent(expr) + //
|
|
81 "&g0.range_input=" +
|
|
82 encodeURIComponent(range);
|
|
83 const view = (url: string): string => `<a href="${url}">view</a>`;
|
|
84 for (let host of ["Kelsis-iMac", "dash", "dot", "plus"]) {
|
|
85 rows.push({
|
|
86 id: rows.length,
|
|
87 host: host,
|
|
88 metrics: view(`http://${host}:5150/metrics`),
|
|
89 uptime: view(vmui(`python_info{job="racc",instance="${host}:5150"}`, "14d")),
|
|
90 traffic: view(vmui(`rate(lan_bytes_sent_from_total{mac="${MAC.get(host)}"})`, "6h")),
|
|
91 });
|
|
92 }
|
|
93 var table = new Tabulator(el, {
|
|
94 data: rows,
|
|
95 columns: [
|
|
96 { title: "Host", field: "host" },
|
|
97 { title: "current /metrics", field: "metrics", formatter: "html" },
|
|
98 { title: "racc uptime history", field: "uptime", formatter: "html" },
|
|
99 { title: "outgoing net traffic", field: "traffic", formatter: "html" },
|
|
100 ],
|
|
101 });
|
|
102 }
|
|
103
|
|
104 async function main() {
|
|
105 fillDebugTable(document.getElementById("debug1")!);
|
|
106
|
|
107 const now = new Date();
|
|
108
|
|
109 const chartDom = document.getElementById("chart1")!;
|
|
110 const chart = echarts.init(chartDom);
|
|
111
|
|
112 const nDays = 8;
|
|
113 const rowNames = dateRowLabels(now, nDays);
|
|
114
|
|
115 const option: echarts.EChartsOption = {
|
|
116 tooltip: {
|
|
117 trigger: "axis",
|
|
118 axisPointer: {
|
|
119 type: "shadow",
|
|
120 },
|
|
121 },
|
|
122 legend: {},
|
|
123 grid: {
|
|
124 left: "0%",
|
|
125 containLabel: true,
|
|
126 },
|
|
127 xAxis: {
|
|
128 type: "value",
|
|
129 max: 10,
|
|
130 },
|
|
131 yAxis: {
|
|
132 type: "category",
|
|
133 data: rowNames,
|
|
134 },
|
|
135 series: await Promise.all([
|
|
136 makeSeries(now, "Minecraft hours", "minecraft", nDays), //
|
|
137 makeSeries(now, "Roblox hours", "roblox", nDays),
|
|
138 ]),
|
|
139 };
|
|
140 console.log(option);
|
|
141 chart.setOption(option);
|
|
142 }
|
|
143 main();
|