pre compute 90day data

This commit is contained in:
Raj Nandan Sharma
2024-02-19 11:26:51 +05:30
parent 5e5ab9439b
commit 72d979abe3
5 changed files with 164 additions and 120 deletions

135
scripts/ninety.js Normal file
View File

@@ -0,0 +1,135 @@
import fs from "fs-extra";
import { GetMinuteStartNowTimestampUTC, BeginingOfDay } from "./tool.js";
import { StatusObj, ParseUptime } from "../src/lib/helpers.js";
function getDayMessage(type, numOfMinute){
if(numOfMinute > 59){
let hour = Math.floor(numOfMinute / 60);
let minute = numOfMinute % 60;
return `${type} for ${hour}h:${minute}m`;
} else {
return `${type} for ${numOfMinute} minute${numOfMinute > 1 ? "s" : ""}`;
}
}
function getDayData(day0, startTime, endTime) {
let dayData = {
UP: 0,
DEGRADED: 0,
DOWN: 0,
timestamp: startTime,
cssClass: StatusObj.NO_DATA,
message: "No Data",
};
//loop thorugh the ts range
for (let i = startTime; i <= endTime; i += 60) {
//if the ts is in the day0 then add up, down degraded data, if not initialize it
if (day0[i] === undefined) {
continue;
}
if (day0[i].status == "UP") {
dayData.UP++;
} else if (day0[i].status == "DEGRADED") {
dayData.DEGRADED++;
} else if (day0[i].status == "DOWN") {
dayData.DOWN++;
}
}
let cssClass = StatusObj.UP;
let message = "Status OK";
if (dayData.DEGRADED > 0) {
cssClass = StatusObj.DEGRADED;
message = getDayMessage("Degraded", dayData.DEGRADED);
}
if (dayData.DOWN > 0) {
cssClass = StatusObj.DOWN;
message = getDayMessage("Down", dayData.DOWN);
}
if (dayData.DEGRADED + dayData.DOWN + dayData.UP > 0) {
dayData.message = message;
dayData.cssClass = cssClass;
}
return dayData;
}
const Ninety = async (monitor) => {
let _0Day = {};
let _90Day = {};
let uptime0Day = "0";
let dailyUps = 0;
let dailyDown = 0;
let dailyDegraded = 0;
let completeUps = 0;
let completeDown = 0;
let completeDegraded = 0;
const secondsInDay = 24 * 60 * 60;
const now = GetMinuteStartNowTimestampUTC();
const midnight = BeginingOfDay({ timeZone: "GMT" });
const midnight90DaysAgo = midnight - 90 * 24 * 60 * 60;
const midnightTomorrow = midnight + secondsInDay;
for (let i = midnight; i <= now; i += 60) {
_0Day[i] = {
timestamp: i,
status: "NO_DATA",
cssClass: StatusObj.NO_DATA,
index: (i - midnight) / 60,
};
}
let day0 = JSON.parse(fs.readFileSync(monitor.path0Day, "utf8"));
for (const timestamp in day0) {
const element = day0[timestamp];
let status = element.status;
if (status == "UP") {
completeUps++;
} else if (status == "DEGRADED") {
completeDegraded++;
} else if (status == "DOWN") {
completeDown++;
}
//0 Day data
if (_0Day[timestamp] !== undefined) {
_0Day[timestamp].status = status;
_0Day[timestamp].cssClass = StatusObj[status];
dailyUps = status == "UP" ? dailyUps + 1 : dailyUps;
dailyDown = status == "DOWN" ? dailyDown + 1 : dailyDown;
dailyDegraded = status == "DEGRADED" ? dailyDegraded + 1 : dailyDegraded;
}
}
for (let i = midnight90DaysAgo; i < midnightTomorrow; i += secondsInDay) {
_90Day[i] = getDayData(day0, i, i + secondsInDay - 1);
}
for (const key in _90Day) {
const element = _90Day[key];
delete _90Day[key].UP;
delete _90Day[key].DEGRADED;
delete _90Day[key].DOWN;
if (element.message == "No Data") continue;
}
uptime0Day = ParseUptime(dailyUps + dailyDegraded, dailyUps + dailyDown + dailyDegraded);
const dataToWrite = {
_90Day: _90Day,
uptime0Day,
uptime90Day: ParseUptime(completeUps + completeDegraded, completeUps + completeDegraded + completeDown),
dailyUps,
dailyDown,
dailyDegraded,
};
await fs.writeJson(monitor.path90Day, dataToWrite);
return true;
};
export { Ninety };

View File

@@ -13,6 +13,7 @@ import { IsValidURL, IsValidHTTPMethod, LoadMonitorsPath, LoadSitePath } from ".
import { GetAllGHLabels, CreateGHLabel } from "./github.js";
import { Minuter } from "./cron-minute.js";
import axios from "axios";
import { Ninety } from "./ninety.js";
let monitors = [];
let site = {};
const envSecrets = [];
@@ -167,6 +168,7 @@ const Startup = async () => {
}
monitors[i].path0Day = `${FOLDER}/${folderName}.0day.utc.json`;
monitors[i].path90Day = `${FOLDER}/${folderName}.90day.utc.json`;
monitors[i].hasAPI = hasAPI;
//secrets can be in url/body/headers
@@ -254,9 +256,14 @@ const Startup = async () => {
fs.ensureFileSync(monitor.path0Day);
fs.writeFileSync(monitor.path0Day, JSON.stringify({}));
}
if (!fs.existsSync(monitor.path90Day)) {
fs.ensureFileSync(monitor.path90Day);
fs.writeFileSync(monitor.path90Day, JSON.stringify({}));
}
console.log("Staring One Minute Cron for ", monitor.path0Day);
console.log("Initial Fetch for ", monitor.name);
await Minuter(envSecrets, monitor, site.github);
await Ninety(monitor);
}
//trigger minute cron
@@ -273,6 +280,21 @@ const Startup = async () => {
await Minuter(envSecrets, monitor, site.github);
});
}
//pre compute 90 day data at 1 minute interval
Cron(
"* * * * *",
async () => {
for (let i = 0; i < monitors.length; i++) {
const monitor = monitors[i];
Ninety(monitor);
}
},
{
protect: true,
}
);
};
export { Startup };

View File

@@ -264,7 +264,7 @@
</div>
<div class="{monitor.embed === undefined ? 'col-span-12': 'col-span-4'} md:col-span-4 text-right h-[32px]">
{#if _90Day[todayDD]}
<div class="text-api-up {monitor.embed === undefined ? 'md:pr-6': ''} text-sm font-semibold mt-[4px] text-{_90Day[todayDD].cssClass}">{_90Day[todayDD].message}</div>
<div class="text-api-up {monitor.embed === undefined ? 'md:pr-6': ''} text-sm truncate font-semibold mt-[4px] text-{_90Day[todayDD].cssClass}">{_90Day[todayDD].message}</div>
{/if}
</div>
</div>

View File

@@ -1,122 +1,8 @@
// @ts-nocheck
// @ts-ignore
import fs from "fs-extra";
import { GetMinuteStartNowTimestampUTC, BeginingOfDay } from "../../../scripts/tool.js";
import { StatusObj, ParseUptime, ParsePercentage } from "$lib/helpers.js";
const secondsInDay = 24 * 60 * 60;
function getDayData(day0, startTime, endTime) {
let dayData = {
UP: 0,
DEGRADED: 0,
DOWN: 0,
timestamp: startTime,
cssClass: StatusObj.NO_DATA,
message: "No Data",
};
//loop thorugh the ts range
for (let i = startTime; i <= endTime; i += 60) {
//if the ts is in the day0 then add up, down degraded data, if not initialize it
if (day0[i] === undefined) {
continue;
}
if (day0[i].status == "UP") {
dayData.UP++;
} else if (day0[i].status == "DEGRADED") {
dayData.DEGRADED++;
} else if (day0[i].status == "DOWN") {
dayData.DOWN++;
}
}
let cssClass = StatusObj.UP;
let message = "Status OK";
if (dayData.DEGRADED > 0) {
cssClass = StatusObj.DEGRADED;
message = "Degraded for " + dayData.DEGRADED + " minute" + (dayData.DEGRADED > 1 ? "s" : "");
}
if (dayData.DOWN > 0) {
cssClass = StatusObj.DOWN;
message = "Down for " + dayData.DOWN + " minute" + (dayData.DOWN > 1 ? "s" : "");
}
if(dayData.DEGRADED + dayData.DOWN + dayData.UP > 0){
dayData.message = message;
dayData.cssClass = cssClass;
}
return dayData;
}
const FetchData = async function (monitor, localTz) {
let _0Day = {};
let _90Day = {};
let uptime0Day = "0";
let dailyUps = 0;
let dailyDown = 0;
let dailyDegraded = 0;
let completeUps = 0;
let completeDown = 0;
let completeDegraded = 0;
const now = GetMinuteStartNowTimestampUTC();
const midnight = BeginingOfDay({ timeZone: localTz });
const midnight90DaysAgo = midnight - 90 * 24 * 60 * 60;
const midnightTomorrow = midnight + secondsInDay;
for (let i = midnight; i <= now; i += 60) {
_0Day[i] = {
timestamp: i,
status: "NO_DATA",
cssClass: StatusObj.NO_DATA,
index: (i - midnight) / 60,
};
}
let day0 = JSON.parse(fs.readFileSync(monitor.path0Day, "utf8"));
for (const timestamp in day0) {
const element = day0[timestamp];
let status = element.status;
if (status == "UP") {
completeUps++;
} else if (status == "DEGRADED") {
completeDegraded++;
} else if (status == "DOWN") {
completeDown++;
}
//0 Day data
if (_0Day[timestamp] !== undefined) {
_0Day[timestamp].status = status;
_0Day[timestamp].cssClass = StatusObj[status];
dailyUps = status == "UP" ? dailyUps + 1 : dailyUps;
dailyDown = status == "DOWN" ? dailyDown + 1 : dailyDown;
dailyDegraded = status == "DEGRADED" ? dailyDegraded + 1 : dailyDegraded;
}
}
for (let i = midnight90DaysAgo; i < midnightTomorrow; i += secondsInDay) {
_90Day[i] = getDayData(day0, i, i + secondsInDay - 1);
}
for (const key in _90Day) {
const element = _90Day[key];
delete _90Day[key].UP;
delete _90Day[key].DEGRADED;
delete _90Day[key].DOWN;
if (element.message == "No Data") continue;
}
uptime0Day = ParseUptime(dailyUps + dailyDegraded, dailyUps + dailyDown + dailyDegraded);
return {
_90Day: _90Day,
uptime0Day,
uptime90Day: ParseUptime(completeUps + completeDegraded, completeUps + completeDegraded + completeDown),
dailyUps,
dailyDown,
dailyDegraded,
};
const FetchData = async function (monitor) {
return fs.readJsonSync(monitor.path90Day);
};
export { FetchData };

View File

@@ -8,6 +8,7 @@
import { Badge } from "$lib/components/ui/badge";
import { ArrowDown, ArrowUp, ChevronUp, BadgeCheck, ChevronDown } from "lucide-svelte";
import * as Collapsible from "$lib/components/ui/collapsible";
</script>
<svelte:head>
<title>
@@ -26,7 +27,7 @@
<section class="mx-auto flex-1 mt-8 flex-col mb-4 flex w-full" >
<div class="container">
<h1 class="mb-4 text-2xl font-bold leading-none">
<Badge variant="outline"> Active Incidents </Badge>
<Badge variant="outline"> Active Incidents</Badge>
</h1>
{#if data.activeIncidents.length > 0}
@@ -45,7 +46,7 @@
<section class="mx-auto flex-1 mt-8 flex-col mb-4 flex w-full" >
<div class="container">
<h1 class="mb-4 text-2xl font-bold leading-none">
<Badge variant="outline"> Recent Incidents </Badge>
<Badge variant="outline"> Recent Incidents - Last {data.site.github.incidentSince} Hours </Badge>
</h1>
{#if data.pastIncidents.length > 0}