customize alert thresholds

This commit is contained in:
beckerinj
2022-05-12 10:55:18 -04:00
parent 98f254263e
commit c8dedb8980
8 changed files with 126 additions and 6 deletions
+4
View File
@@ -2,6 +2,7 @@ import { Server } from "@monitor/types";
import { FastifyInstance } from "fastify";
import fp from "fastify-plugin";
import { Schema } from "mongoose";
import { CPU_USAGE_NOTIFY_LIMIT, DISK_USAGE_NOTIFY_LIMIT, MEM_USAGE_NOTIFY_LIMIT } from "../../config";
import model from "../../util/model";
const servers = fp((app: FastifyInstance, _: {}, done: () => void) => {
@@ -11,6 +12,9 @@ const servers = fp((app: FastifyInstance, _: {}, done: () => void) => {
enabled: { type: Boolean, default: true },
isCore: Boolean,
owners: { type: [String], default: [] },
cpuAlert: { type: Number, default: CPU_USAGE_NOTIFY_LIMIT },
memAlert: { type: Number, default: MEM_USAGE_NOTIFY_LIMIT },
diskAlert: { type: Number, default: DISK_USAGE_NOTIFY_LIMIT },
});
app.decorate("servers", model(app, "Server", schema));
+9 -3
View File
@@ -46,19 +46,25 @@ const slackNotifier = fp((app: FastifyInstance, _: {}, done: () => void) => {
servers.forEach((server) => {
// check for out of bounds stats
const stats = server.stats!;
if (stats.cpu > CPU_USAGE_NOTIFY_LIMIT) {
if (stats.cpu > (server.cpuAlert || CPU_USAGE_NOTIFY_LIMIT)) {
// high cpu usage
notifySlack(
`WARNING | ${server.name} has high CPU usage.\n\nusage: ${stats.cpu}%`
);
}
if (stats.mem.usedMemPercentage > MEM_USAGE_NOTIFY_LIMIT) {
if (
stats.mem.usedMemPercentage >
(server.memAlert || MEM_USAGE_NOTIFY_LIMIT)
) {
// high memory usage
notifySlack(
`WARNING | ${server.name} has high memory usage.\n\nusing ${stats.mem.usedMemMb} MB of ${stats.mem.totalMemMb} MB (${stats.mem.usedMemPercentage}%)`
);
}
if (stats.disk.usedPercentage > DISK_USAGE_NOTIFY_LIMIT) {
if (
stats.disk.usedPercentage >
(server.diskAlert || DISK_USAGE_NOTIFY_LIMIT)
) {
// high disk usage
notifySlack(
`WARNING | ${server.name} has high disk usage.\n\nusing ${stats.disk.usedGb} GB of ${stats.disk.totalGb} GB (${stats.disk.usedPercentage}%)`
+18
View File
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 20 20" enable-background="new 0 0 20 20" xml:space="preserve">
<g id="cog_2_">
<g>
<path fill="#fceade" fill-rule="evenodd" clip-rule="evenodd" d="M19,8h-2.31c-0.14-0.46-0.33-0.89-0.56-1.3l1.7-1.7c0.39-0.39,0.39-1.02,0-1.41
l-1.41-1.41c-0.39-0.39-1.02-0.39-1.41,0l-1.7,1.7c-0.41-0.22-0.84-0.41-1.3-0.55V1c0-0.55-0.45-1-1-1H9C8.45,0,8,0.45,8,1v2.33
C7.52,3.47,7.06,3.67,6.63,3.91L5,2.28c-0.37-0.37-0.98-0.37-1.36,0L2.28,3.64C1.91,4.02,1.91,4.63,2.28,5l1.62,1.62
C3.66,7.06,3.46,7.51,3.31,8H1C0.45,8,0,8.45,0,9v2c0,0.55,0.45,1,1,1h2.31c0.14,0.46,0.33,0.89,0.56,1.3L2.17,15
c-0.39,0.39-0.39,1.02,0,1.41l1.41,1.41c0.39,0.39,1.02,0.39,1.41,0l1.7-1.7c0.41,0.22,0.84,0.41,1.3,0.55V19c0,0.55,0.45,1,1,1h2
c0.55,0,1-0.45,1-1v-2.33c0.48-0.14,0.94-0.35,1.37-0.59L15,17.72c0.37,0.37,0.98,0.37,1.36,0l1.36-1.36
c0.37-0.37,0.37-0.98,0-1.36l-1.62-1.62c0.24-0.43,0.45-0.89,0.6-1.38H19c0.55,0,1-0.45,1-1V9C20,8.45,19.55,8,19,8z M10,14
c-2.21,0-4-1.79-4-4c0-2.21,1.79-4,4-4s4,1.79,4,4C14,12.21,12.21,14,10,14z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

@@ -0,0 +1,79 @@
import { Component } from "solid-js";
import { createStore } from "solid-js/store";
import { useTheme } from "../../../../state/ThemeProvider";
import { combineClasses, validatePercentage } from "../../../../util/helpers";
import Input from "../../../util/Input";
import Flex from "../../../util/layout/Flex";
import Grid from "../../../util/layout/Grid";
import { useConfig } from "./Provider";
const Alerts: Component<{}> = (p) => {
const { server, setServer } = useConfig();
const { themeClass } = useTheme();
const [alerts, setAlerts] = createStore({
cpu: server.cpuAlert?.toString(),
mem: server.memAlert?.toString(),
disk: server.diskAlert?.toString(),
});
return (
<Grid class={combineClasses("config-item shadow", themeClass())}>
<h1>alerts</h1>
<Flex justifyContent="space-between">
<div>cpu</div>
<Flex alignItems="center">
<Input
placeholder="%"
value={alerts.cpu || server.cpuAlert?.toString()}
onEdit={(val) => setAlerts("cpu", val)}
onConfirm={(val) => {
if (validatePercentage(val)) {
setServer("cpuAlert", Number(val));
} else {
setAlerts("cpu", server.cpuAlert?.toString());
}
}}
/>
<div>%</div>
</Flex>
</Flex>
<Flex justifyContent="space-between">
<div>mem</div>
<Flex alignItems="center">
<Input
placeholder="%"
value={alerts.mem || server.memAlert?.toString()}
onEdit={(val) => setAlerts("mem", val)}
onConfirm={(val) => {
if (validatePercentage(val)) {
setServer("memAlert", Number(val));
} else {
setAlerts("mem", server.memAlert?.toString());
}
}}
/>
<div>%</div>
</Flex>
</Flex>
<Flex justifyContent="space-between">
<div>disk</div>
<Flex alignItems="center">
<Input
placeholder="%"
value={alerts.disk || server.diskAlert?.toString()}
onEdit={(val) => setAlerts("disk", val)}
onConfirm={(val) => {
if (validatePercentage(val)) {
setServer("diskAlert", Number(val));
} else {
setAlerts("disk", server.diskAlert?.toString());
}
}}
/>
<div>%</div>
</Flex>
</Flex>
</Grid>
);
};
export default Alerts;
@@ -4,6 +4,7 @@ import Icon from "../../../util/Icon";
import Flex from "../../../util/layout/Flex";
import Grid from "../../../util/layout/Grid";
import Address from "./Address";
import Alerts from "./Alerts";
import Enabled from "./Enabled";
import Networks from "./Networks";
import { useConfig } from "./Provider";
@@ -19,6 +20,7 @@ const Config: Component<{}> = (p) => {
<Enabled />
</Show>
<Networks />
<Alerts />
</Grid>
<Show when={server.updated}>
<Flex style={{ "place-self": "center", padding: "1rem" }}>
+2 -1
View File
@@ -40,7 +40,8 @@ export type IconType =
| "clipboard"
| "check"
| "caret-right"
| "search";
| "search"
| "cog";
const Icon: Component<{
type: IconType;
+8 -2
View File
@@ -99,7 +99,7 @@ export function copyToClipboard(text: string) {
export function applyDarkTheme(element: Element) {
element.classList.add("dark");
for (let i = 0; i < element.children.length; i++) {
applyDarkTheme(element.children[i])
applyDarkTheme(element.children[i]);
}
}
@@ -108,4 +108,10 @@ export function removeDarkTheme(element: Element) {
for (let i = 0; i < element.children.length; i++) {
removeDarkTheme(element.children[i]);
}
}
}
export function validatePercentage(perc: string) {
// validates that a string represents a percentage
const percNum = Number(perc);
return !isNaN(percNum) && percNum > 0 && percNum < 100;
}
+4
View File
@@ -51,6 +51,10 @@ export type Server = {
enabled: boolean;
isCore?: boolean;
owners: string[];
// usage stats threshold
cpuAlert?: number; // 0 - 100
memAlert?: number; // 0 - 100
diskAlert?: number; // 0 - 100
};
export type DockerBuildArgs = {