feat(notification): error monitoring

if there are more than 10 errors in a 15min window sends email to alert someone
This commit is contained in:
2025-12-30 10:54:09 -06:00
parent 09f16f4e62
commit 6cbffa4ac5
7 changed files with 408 additions and 169 deletions

View File

@@ -3,175 +3,186 @@ import { notifications } from "../../../../database/schema/notifications.js";
import { createLog } from "../../logger/logger.js";
export const note: any = [
{
name: "reprintLabels",
description:
"Monitors the labels that are printed and returns a value if one falls withing the time frame defined below.",
checkInterval: 1,
timeType: "min",
emails: "",
active: false,
notifiySettings: { prodID: 1 },
},
{
name: "downTimeCheck",
description:
"Checks for specific downtimes that are greater than 105 min.",
checkInterval: 30,
timeType: "min",
emails: "",
active: false,
notifiySettings: { prodID: 1, daysInPast: 5, duration: 105 },
},
{
name: "qualityBlocking",
description:
"Checks for new blocking orders that have been entered, recommened to get the most recent order in here before activating.",
checkInterval: 30,
timeType: "min",
emails: "",
active: false,
notifiySettings: {
prodID: 1,
sentBlockingOrders: [{ timeStamp: "0", blockingOrder: 1 }],
},
},
{
name: "productionCheck",
description: "Checks ppoo",
checkInterval: 2,
timeType: "hour",
emails: "",
active: false,
notifiySettings: {
prodID: 1,
count: 0,
weekend: false,
locations: "0",
},
},
{
name: "stagingCheck",
description:
"Checks staging based on locations, locations need to be seperated by a ,",
checkInterval: 2,
timeType: "hour",
emails: "",
active: false,
notifiySettings: {
prodID: 1,
count: 0,
weekend: false,
locations: "0",
},
},
{
name: "tiIntergration",
description: "Checks for new releases to be put into ti",
checkInterval: 60,
timeType: "min",
emails: "",
active: false,
notifiySettings: {
prodID: 1,
start: 36,
end: 36,
releases: [{ timeStamp: "0", releaseNumber: 1 }],
},
},
{
name: "exampleNotification",
description: "Checks for new releases to be put into ti",
checkInterval: 2,
timeType: "min",
emails: "",
active: true,
notifiySettings: {
prodID: 1,
start: 36,
end: 36,
releases: [1, 2, 3],
},
},
{
name: "fifoIndex",
description: "Checks for pallets that were shipped out of fifo",
checkInterval: 1,
timeType: "hour",
emails: "blake.matthes@alpla.com",
active: false,
notifiySettings: {
prodID: 1,
start: 36,
end: 36,
releases: [1, 2, 3],
},
},
{
name: "bow2henkelincoming",
description:
"Checks for new incoming goods orders to be completed and sends an email for what truck and carrier it was",
checkInterval: 15,
timeType: "min",
emails: "blake.matthes@alpla.com",
active: false,
notifiySettings: { processTime: 15 },
},
{
name: "palletsRemovedAsWaste",
description:
"Validates stock to make sure, there are no pallets released that have been removed as waste already ",
checkInterval: 15,
timeType: "min",
emails: "blake.matthes@alpla.com",
active: false,
notifiySettings: { prodID: 1 },
},
{
name: "shortageBookings",
description:
"Checks for material shortage bookings by single av type or all types ",
checkInterval: 15,
timeType: "min",
emails: "blake.matthes@alpla.com",
active: false,
notifiySettings: {
time: 15,
type: "all", // change this to something else or leave blank to use the av type
avType: 1,
},
},
{
name: "reprintLabels",
description:
"Monitors the labels that are printed and returns a value if one falls withing the time frame defined below.",
checkInterval: 1,
timeType: "min",
emails: "",
active: false,
notifiySettings: { prodID: 1 },
},
{
name: "downTimeCheck",
description: "Checks for specific downtimes that are greater than 105 min.",
checkInterval: 30,
timeType: "min",
emails: "",
active: false,
notifiySettings: { prodID: 1, daysInPast: 5, duration: 105 },
},
{
name: "qualityBlocking",
description:
"Checks for new blocking orders that have been entered, recommened to get the most recent order in here before activating.",
checkInterval: 30,
timeType: "min",
emails: "",
active: false,
notifiySettings: {
prodID: 1,
sentBlockingOrders: [{ timeStamp: "0", blockingOrder: 1 }],
},
},
{
name: "productionCheck",
description: "Checks ppoo",
checkInterval: 2,
timeType: "hour",
emails: "",
active: false,
notifiySettings: {
prodID: 1,
count: 0,
weekend: false,
locations: "0",
},
},
{
name: "stagingCheck",
description:
"Checks staging based on locations, locations need to be seperated by a ,",
checkInterval: 2,
timeType: "hour",
emails: "",
active: false,
notifiySettings: {
prodID: 1,
count: 0,
weekend: false,
locations: "0",
},
},
{
name: "tiIntergration",
description: "Checks for new releases to be put into ti",
checkInterval: 60,
timeType: "min",
emails: "",
active: false,
notifiySettings: {
prodID: 1,
start: 36,
end: 36,
releases: [{ timeStamp: "0", releaseNumber: 1 }],
},
},
{
name: "exampleNotification",
description: "Checks for new releases to be put into ti",
checkInterval: 2,
timeType: "min",
emails: "",
active: true,
notifiySettings: {
prodID: 1,
start: 36,
end: 36,
releases: [1, 2, 3],
},
},
{
name: "fifoIndex",
description: "Checks for pallets that were shipped out of fifo",
checkInterval: 1,
timeType: "hour",
emails: "blake.matthes@alpla.com",
active: false,
notifiySettings: {
prodID: 1,
start: 36,
end: 36,
releases: [1, 2, 3],
},
},
{
name: "bow2henkelincoming",
description:
"Checks for new incoming goods orders to be completed and sends an email for what truck and carrier it was",
checkInterval: 15,
timeType: "min",
emails: "blake.matthes@alpla.com",
active: false,
notifiySettings: { processTime: 15 },
},
{
name: "palletsRemovedAsWaste",
description:
"Validates stock to make sure, there are no pallets released that have been removed as waste already ",
checkInterval: 15,
timeType: "min",
emails: "blake.matthes@alpla.com",
active: false,
notifiySettings: { prodID: 1 },
},
{
name: "shortageBookings",
description:
"Checks for material shortage bookings by single av type or all types ",
checkInterval: 15,
timeType: "min",
emails: "blake.matthes@alpla.com",
active: false,
notifiySettings: {
time: 15,
type: "all", // change this to something else or leave blank to use the av type
avType: 1,
},
},
{
name: "tooManyErrors",
description:
"Checks to see how many errors in the last x time and sends an email based on this.",
checkInterval: 15,
timeType: "min",
emails: "blake.matthes@alpla.com",
active: true,
notifiySettings: {
errorCount: 10, // change this to something else or leave blank to use the av type
},
},
];
export const notificationCreate = async () => {
for (let i = 0; i < note.length; i++) {
try {
const notify = await db
.insert(notifications)
.values(note[i])
.onConflictDoUpdate({
target: notifications.name,
set: {
name: note[i].name,
description: note[i].description,
//notifiySettings: note[i].notifiySettings,
},
});
} catch (error) {
createLog(
"error",
"notify",
"notify",
`There was an error getting the notifications: ${JSON.stringify(
error
)}`
);
}
}
createLog(
"info",
"lst",
"nofity",
"notifications were just added/updated due to server startup"
);
for (let i = 0; i < note.length; i++) {
try {
const notify = await db
.insert(notifications)
.values(note[i])
.onConflictDoUpdate({
target: notifications.name,
set: {
name: note[i].name,
description: note[i].description,
//notifiySettings: note[i].notifiySettings,
},
});
} catch (error) {
createLog(
"error",
"notify",
"notify",
`There was an error getting the notifications: ${JSON.stringify(
error,
)}`,
);
}
}
createLog(
"info",
"lst",
"nofity",
"notifications were just added/updated due to server startup",
);
};

View File

@@ -0,0 +1,42 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{{!-- <link rel="stylesheet" href="styles/styles.css" /> --}}
{{> styles}}
</head>
<body>
<p>All,</p>
<p>The plant has encountered more than {{count}} errors in the last {{time}} mins, please see below errors and address as needed. </p>
<table >
<thead>
<tr>
<th>Username</th>
<th>Service</th>
<th>Message</th>
<th>Checked</th>
<th>LogTime</th>
{{!-- <th>Downtime finish</th> --}}
</tr>
</thead>
<tbody>
{{#each data}}
<tr>
<td>{{username}}</td>
<td>{{service}}</td>
<td>{{message}}</td>
<td>{{checked}}</td>
<td>{{add_Date}}</td>
{{!-- <td>{{dtEnd}}</td> --}}
</tr>
{{/each}}
</tbody>
</table>
<div>
<p>Thank you,</p>
<p>LST Team</p>
</div>
</body>
</html>