From 72d979abe3357787fe262d89ffaec401e3e28485 Mon Sep 17 00:00:00 2001 From: Raj Nandan Sharma Date: Mon, 19 Feb 2024 11:26:51 +0530 Subject: [PATCH] pre compute 90day data --- scripts/ninety.js | 135 ++++++++++++++++++++++++++ scripts/startup.js | 24 ++++- src/lib/components/monitor.svelte | 2 +- src/lib/server/page.js | 118 +--------------------- src/routes/incident/[id]/+page.svelte | 5 +- 5 files changed, 164 insertions(+), 120 deletions(-) create mode 100644 scripts/ninety.js diff --git a/scripts/ninety.js b/scripts/ninety.js new file mode 100644 index 0000000..235e4fe --- /dev/null +++ b/scripts/ninety.js @@ -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 }; \ No newline at end of file diff --git a/scripts/startup.js b/scripts/startup.js index d034f6f..81e1cb6 100644 --- a/scripts/startup.js +++ b/scripts/startup.js @@ -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 }; diff --git a/src/lib/components/monitor.svelte b/src/lib/components/monitor.svelte index 2e39604..db8f8a1 100644 --- a/src/lib/components/monitor.svelte +++ b/src/lib/components/monitor.svelte @@ -264,7 +264,7 @@
{#if _90Day[todayDD]} -
{_90Day[todayDD].message}
+
{_90Day[todayDD].message}
{/if}
diff --git a/src/lib/server/page.js b/src/lib/server/page.js index 66e2718..aba1653 100644 --- a/src/lib/server/page.js +++ b/src/lib/server/page.js @@ -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 }; diff --git a/src/routes/incident/[id]/+page.svelte b/src/routes/incident/[id]/+page.svelte index 808834e..dc008bf 100644 --- a/src/routes/incident/[id]/+page.svelte +++ b/src/routes/incident/[id]/+page.svelte @@ -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"; + @@ -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}