fix: rename "breached" status to "exceeded" for clarity
The word "breached" in infrastructure monitoring was confusing users as it implied a security breach. Renamed to "exceeded" which better describes threshold violations (e.g. "threshold exceeded"). ## Changes - Renamed monitor status value from "breached" to "exceeded" across server types, status service, queue helper, notification builder, email subject lines, and MongoDB aggregation queries - Renamed client types, status box/label components, translation key, and infrastructure page props to match - Added DB migration (0005) to update existing monitors with the old status value
This commit is contained in:
1 parent
eac470cb68
commit
943ef92053
15 files changed
+63
-36
No files matched your search
@@ -0,0 +1,25 @@
|
||||
import { MonitorModel } from "../models/Monitor.js";
|
||||
import { logger } from "@/utils/logger.js";
|
||||
|
||||
/**
|
||||
* Rename monitor status "breached" to "exceeded" for clarity.
|
||||
* The word "breached" was confusing users as it implied a security breach.
|
||||
*/
|
||||
export async function renameBreachedToExceeded(): Promise<void> {
|
||||
const SERVICE_NAME = "Migration:RenameBreachedToExceeded";
|
||||
|
||||
try {
|
||||
logger.info({ service: SERVICE_NAME, message: "Starting status rename: breached -> exceeded" });
|
||||
|
||||
const result = await MonitorModel.updateMany({ status: "breached" }, { $set: { status: "exceeded" } });
|
||||
|
||||
logger.info({
|
||||
service: SERVICE_NAME,
|
||||
message: `Updated ${result.modifiedCount} monitors from 'breached' to 'exceeded'`,
|
||||
});
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
logger.error({ service: SERVICE_NAME, message: `Error renaming status: ${errorMessage}` });
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import { migrateStatusWindowThreshold } from "./0001_migrateStatusWindowThreshol
|
||||
import { convertChecksToTimeSeries } from "./0002_convertChecksToTimeSeries.js";
|
||||
import { cleanupDuplicateMonitorStats } from "./0003_cleanupDuplicateMonitorStats.js";
|
||||
import { fixInfrastructureThresholds } from "./0004_fixInfrastructureThresholds.js";
|
||||
import { renameBreachedToExceeded } from "./0005_renameBreachedToExceeded.js";
|
||||
import MigrationModel from "../models/Migration.js";
|
||||
|
||||
type MigrationEntry = {
|
||||
@@ -14,6 +15,7 @@ const migrations: MigrationEntry[] = [
|
||||
{ name: "0002_convertChecksToTimeSeries", execute: convertChecksToTimeSeries },
|
||||
{ name: "0003_cleanupDuplicateMonitorStats", execute: cleanupDuplicateMonitorStats },
|
||||
{ name: "0004_fixInfrastructureThresholds", execute: fixInfrastructureThresholds },
|
||||
{ name: "0005_renameBreachedToExceeded", execute: renameBreachedToExceeded },
|
||||
];
|
||||
|
||||
const runMigrations = async (logger?: { info: Function; error: Function }) => {
|
||||
|
||||
@@ -262,9 +262,9 @@ class MongoMonitorsRepository implements IMonitorsRepository {
|
||||
$cond: [{ $eq: ["$status", "maintenance"] }, 1, 0],
|
||||
},
|
||||
},
|
||||
breachedMonitors: {
|
||||
exceededMonitors: {
|
||||
$sum: {
|
||||
$cond: [{ $eq: ["$status", "breached"] }, 1, 0],
|
||||
$cond: [{ $eq: ["$status", "exceeded"] }, 1, 0],
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -281,7 +281,7 @@ class MongoMonitorsRepository implements IMonitorsRepository {
|
||||
pausedMonitors: 0,
|
||||
initializingMonitors: 0,
|
||||
maintenanceMonitors: 0,
|
||||
breachedMonitors: 0,
|
||||
exceededMonitors: 0,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
@@ -440,14 +440,14 @@ export class SuperSimpleQueueHelper implements ISuperSimpleQueueHelper {
|
||||
decision.shouldSendNotification = true;
|
||||
decision.incidentReason = "status_down";
|
||||
decision.notificationReason = "status_change";
|
||||
} else if (monitor.status === "breached") {
|
||||
} else if (monitor.status === "exceeded") {
|
||||
// Hardware monitor exceeded thresholds
|
||||
decision.shouldCreateIncident = true;
|
||||
decision.shouldSendNotification = true;
|
||||
decision.incidentReason = "threshold_breach";
|
||||
decision.notificationReason = "threshold_breach";
|
||||
} else if (monitor.status === "up" && (prevStatus === "down" || prevStatus === "breached")) {
|
||||
// Monitor recovered from down or breached state
|
||||
} else if (monitor.status === "up" && (prevStatus === "down" || prevStatus === "exceeded")) {
|
||||
// Monitor recovered from down or exceeded state
|
||||
decision.shouldResolveIncident = true;
|
||||
decision.shouldSendNotification = true;
|
||||
decision.notificationReason = "status_change";
|
||||
|
||||
@@ -145,9 +145,9 @@ export class NotificationMessageBuilder implements INotificationMessageBuilder {
|
||||
}
|
||||
|
||||
private buildThresholdBreachContent(monitor: Monitor, monitorStatusResponse: MonitorStatusResponse<HardwareStatusPayload>): NotificationContent {
|
||||
const title = `Threshold Breach: ${monitor.name}`;
|
||||
const summary = `Monitor "${monitor.name}" has breached one or more thresholds.`;
|
||||
const details = [`URL: ${monitor.url}`, `Status: Breached`, `Type: ${monitor.type}`];
|
||||
const title = `Threshold Exceeded: ${monitor.name}`;
|
||||
const summary = `Monitor "${monitor.name}" has exceeded one or more thresholds.`;
|
||||
const details = [`URL: ${monitor.url}`, `Status: Threshold exceeded`, `Type: ${monitor.type}`];
|
||||
|
||||
const thresholds = this.extractThresholdBreaches(monitor, monitorStatusResponse);
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ export class EmailProvider implements INotificationProvider {
|
||||
case "monitor_up":
|
||||
return `Monitor ${message.monitor.name} is back up`;
|
||||
case "threshold_breach":
|
||||
return `Monitor ${message.monitor.name} threshold breached`;
|
||||
return `Monitor ${message.monitor.name} threshold exceeded`;
|
||||
case "threshold_resolved":
|
||||
return `Monitor ${message.monitor.name} thresholds resolved`;
|
||||
default:
|
||||
|
||||
@@ -292,7 +292,7 @@ export class StatusService implements IStatusService {
|
||||
temp: tempBreach,
|
||||
};
|
||||
|
||||
// Update counters: decrement if breached, reset to 5 if not breached
|
||||
// Update counters: decrement if exceeded, reset to 5 if not exceeded
|
||||
if (cpuBreach) {
|
||||
monitor.cpuAlertCounter = Math.max(0, monitor.cpuAlertCounter - 1);
|
||||
} else {
|
||||
@@ -321,23 +321,23 @@ export class StatusService implements IStatusService {
|
||||
const anyCounterZero =
|
||||
monitor.cpuAlertCounter === 0 || monitor.memoryAlertCounter === 0 || monitor.diskAlertCounter === 0 || monitor.tempAlertCounter === 0;
|
||||
|
||||
const anyThresholdBreached = cpuBreach || memoryBreach || diskBreach || tempBreach;
|
||||
const anyThresholdExceeded = cpuBreach || memoryBreach || diskBreach || tempBreach;
|
||||
const allThresholdsNormal = !cpuBreach && !memoryBreach && !diskBreach && !tempBreach;
|
||||
|
||||
// Update monitor status based on threshold breach state
|
||||
// Update monitor status based on threshold exceeded state
|
||||
if (newStatus !== "down") {
|
||||
// Don't override "down" status - service unreachable takes precedence
|
||||
// Check current monitor status, not newStatus for comparison
|
||||
if (anyCounterZero && anyThresholdBreached && monitor.status !== "breached") {
|
||||
// Initial breach: counter hit zero, change status to breached
|
||||
newStatus = "breached";
|
||||
if (anyCounterZero && anyThresholdExceeded && monitor.status !== "exceeded") {
|
||||
// Threshold exceeded: counter hit zero, change status to exceeded
|
||||
newStatus = "exceeded";
|
||||
statusChanged = true;
|
||||
} else if (anyCounterZero && anyThresholdBreached && monitor.status === "breached") {
|
||||
// Already breached, keep status but don't mark as changed
|
||||
newStatus = "breached";
|
||||
} else if (anyCounterZero && anyThresholdExceeded && monitor.status === "exceeded") {
|
||||
// Already exceeded, keep status but don't mark as changed
|
||||
newStatus = "exceeded";
|
||||
// statusChanged remains false
|
||||
} else if (allThresholdsNormal && monitor.status === "breached") {
|
||||
// All thresholds returned to normal, recover from breached state
|
||||
} else if (allThresholdsNormal && monitor.status === "exceeded") {
|
||||
// All thresholds returned to normal, recover from exceeded state
|
||||
newStatus = "up";
|
||||
statusChanged = true;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ export type MonitorType = (typeof MonitorTypes)[number];
|
||||
export const GeoCheckSupportedTypes: readonly MonitorType[] = ["http", "ping"] as const;
|
||||
export const supportsGeoCheck = (type: MonitorType): boolean => GeoCheckSupportedTypes.includes(type);
|
||||
|
||||
export const MonitorStatuses = ["up", "down", "paused", "initializing", "maintenance", "breached"] as const;
|
||||
export const MonitorStatuses = ["up", "down", "paused", "initializing", "maintenance", "exceeded"] as const;
|
||||
export type MonitorStatus = (typeof MonitorStatuses)[number];
|
||||
|
||||
export type MonitorMatchMethod = "equal" | "include" | "regex" | "";
|
||||
@@ -64,7 +64,7 @@ export interface MonitorsSummary {
|
||||
pausedMonitors: number;
|
||||
initializingMonitors: number;
|
||||
maintenanceMonitors: number;
|
||||
breachedMonitors: number;
|
||||
exceededMonitors: number;
|
||||
}
|
||||
|
||||
export interface MonitorsWithChecksByTeamIdResult {
|
||||
|
||||
Reference in new issue
Block a user