inject settings service, extract client host
This commit is contained in:
1 parent
412a3b7cc9
commit
a8ecd44abf
9 files changed
+73
-28
No files matched your search
@@ -182,6 +182,7 @@ export const initializeServices = async ({
|
||||
discordProvider,
|
||||
pagerDutyProvider,
|
||||
matrixProvider,
|
||||
settingsService,
|
||||
logger
|
||||
);
|
||||
|
||||
|
||||
@@ -6,7 +6,8 @@ export interface INotificationProvider {
|
||||
notification: Notification,
|
||||
monitor: Monitor,
|
||||
monitorStatusResponse: MonitorStatusResponse,
|
||||
decision: MonitorActionDecision
|
||||
decision: MonitorActionDecision,
|
||||
clientHost: string
|
||||
) => Promise<boolean>;
|
||||
sendTestAlert(notification: Notification): Promise<boolean>;
|
||||
}
|
||||
@@ -11,20 +11,31 @@ export class DiscordProvider implements INotificationProvider {
|
||||
constructor(logger: any) {
|
||||
this.logger = logger;
|
||||
}
|
||||
private getHardwareContent = (monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, decision: MonitorActionDecision) => {
|
||||
private getHardwareContent = (
|
||||
clientHost: string,
|
||||
monitor: Monitor,
|
||||
monitorStatusResponse: MonitorStatusResponse,
|
||||
decision: MonitorActionDecision
|
||||
) => {
|
||||
// For status changes (recovery), use standard format
|
||||
if (decision.notificationReason === "status_change") {
|
||||
return buildDiscordBody(monitor, monitorStatusResponse);
|
||||
}
|
||||
// For threshold breaches, use hardware alert format
|
||||
const { discordPayload } = buildHardwareAlerts("HOST_PLACEHOLDER", monitor, monitorStatusResponse);
|
||||
const { discordPayload } = buildHardwareAlerts(clientHost, monitor, monitorStatusResponse);
|
||||
return discordPayload;
|
||||
};
|
||||
|
||||
sendAlert = async (notification: Notification, monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, decision: MonitorActionDecision) => {
|
||||
sendAlert = async (
|
||||
notification: Notification,
|
||||
monitor: Monitor,
|
||||
monitorStatusResponse: MonitorStatusResponse,
|
||||
decision: MonitorActionDecision,
|
||||
clientHost: string
|
||||
) => {
|
||||
let body;
|
||||
if (monitor.type === "hardware") {
|
||||
body = this.getHardwareContent(monitor, monitorStatusResponse, decision);
|
||||
body = this.getHardwareContent(clientHost, monitor, monitorStatusResponse, decision);
|
||||
} else {
|
||||
body = buildDiscordBody(monitor, monitorStatusResponse);
|
||||
}
|
||||
|
||||
@@ -13,13 +13,18 @@ export class EmailProvider implements INotificationProvider {
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
private buildHardwareEmail = async (monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, decision: MonitorActionDecision) => {
|
||||
private buildHardwareEmail = async (
|
||||
clientHost: string,
|
||||
monitor: Monitor,
|
||||
monitorStatusResponse: MonitorStatusResponse,
|
||||
decision: MonitorActionDecision
|
||||
) => {
|
||||
// For status changes (recovery), use standard email format
|
||||
if (decision.notificationReason === "status_change") {
|
||||
return await buildEmail(this.emailService, monitor);
|
||||
}
|
||||
// For threshold breaches, use hardware alert format
|
||||
const { alertsToSend } = buildHardwareAlerts("HOST_PLACEHOLDER", monitor, monitorStatusResponse);
|
||||
const { alertsToSend } = buildHardwareAlerts(clientHost, monitor, monitorStatusResponse);
|
||||
const html = buildHardwareEmail(this.emailService, monitor, alertsToSend);
|
||||
return html;
|
||||
};
|
||||
@@ -28,7 +33,8 @@ export class EmailProvider implements INotificationProvider {
|
||||
notification: Notification,
|
||||
monitor: Monitor,
|
||||
monitorStatusResponse: MonitorStatusResponse,
|
||||
decision: MonitorActionDecision
|
||||
decision: MonitorActionDecision,
|
||||
clientHost: string
|
||||
): Promise<boolean> {
|
||||
// For grouped notifications (identified by ":" in name), customize subject to indicate multiple services.
|
||||
// Example: "2 services: Service A, Service B" becomes "Alert: 2 services are down"
|
||||
@@ -48,7 +54,7 @@ export class EmailProvider implements INotificationProvider {
|
||||
|
||||
let html;
|
||||
if (monitor.type === "hardware") {
|
||||
html = await this.buildHardwareEmail(monitor, monitorStatusResponse, decision);
|
||||
html = await this.buildHardwareEmail(clientHost, monitor, monitorStatusResponse, decision);
|
||||
} else {
|
||||
html = await buildEmail(this.emailService, monitor);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ export class MatrixProvider implements INotificationProvider {
|
||||
return buildWebhookBody(monitor, monitorStatusResponse);
|
||||
}
|
||||
// For threshold breaches, use hardware alert format
|
||||
const { alertsToSend } = buildHardwareAlerts("HOST_PLACEHOLDER", monitor, monitorStatusResponse);
|
||||
const { alertsToSend } = buildHardwareAlerts(clientHost, monitor, monitorStatusResponse);
|
||||
const body = buildHardwareNotificationMessage(clientHost, alertsToSend, monitor);
|
||||
return body;
|
||||
};
|
||||
@@ -37,12 +37,18 @@ export class MatrixProvider implements INotificationProvider {
|
||||
return body;
|
||||
};
|
||||
|
||||
sendAlert = async (notification: Notification, monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, decision: MonitorActionDecision) => {
|
||||
sendAlert = async (
|
||||
notification: Notification,
|
||||
monitor: Monitor,
|
||||
monitorStatusResponse: MonitorStatusResponse,
|
||||
decision: MonitorActionDecision,
|
||||
clientHost: string
|
||||
) => {
|
||||
const { homeserverUrl, accessToken, roomId } = notification;
|
||||
|
||||
let content;
|
||||
if (monitor.type === "hardware") {
|
||||
content = this.getHardwareContent("HOST_PLACEHOLDER", monitor, monitorStatusResponse, decision);
|
||||
content = this.getHardwareContent(clientHost, monitor, monitorStatusResponse, decision);
|
||||
} else {
|
||||
content = this.getContent(monitor, monitorStatusResponse);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ export class PagerDutyProvider implements INotificationProvider {
|
||||
return buildWebhookBody(monitor, monitorStatusResponse);
|
||||
}
|
||||
// For threshold breaches, use hardware alert format
|
||||
const { alertsToSend } = buildHardwareAlerts("HOST_PLACEHOLDER", monitor, monitorStatusResponse);
|
||||
const { alertsToSend } = buildHardwareAlerts(clientHost, monitor, monitorStatusResponse);
|
||||
const body = buildHardwareNotificationMessage(clientHost, alertsToSend, monitor);
|
||||
return body;
|
||||
};
|
||||
@@ -41,11 +41,12 @@ export class PagerDutyProvider implements INotificationProvider {
|
||||
notification: Notification,
|
||||
monitor: Monitor,
|
||||
monitorStatusResponse: MonitorStatusResponse,
|
||||
decision: MonitorActionDecision
|
||||
decision: MonitorActionDecision,
|
||||
clientHost: string
|
||||
): Promise<boolean> {
|
||||
let body;
|
||||
if (monitor.type === "hardware") {
|
||||
body = this.getHardwareContent("HOST_PLACEHOLDER", monitor, monitorStatusResponse, decision);
|
||||
body = this.getHardwareContent(clientHost, monitor, monitorStatusResponse, decision);
|
||||
} else {
|
||||
body = this.getContent(monitor, monitorStatusResponse);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ export class SlackProvider implements INotificationProvider {
|
||||
return buildWebhookBody(monitor, monitorStatusResponse);
|
||||
}
|
||||
// For threshold breaches, use hardware alert format
|
||||
const { alertsToSend } = buildHardwareAlerts("HOST_PLACEHOLDER", monitor, monitorStatusResponse);
|
||||
const { alertsToSend } = buildHardwareAlerts(clientHost, monitor, monitorStatusResponse);
|
||||
const body = buildHardwareNotificationMessage(clientHost, alertsToSend, monitor);
|
||||
return body;
|
||||
};
|
||||
@@ -41,11 +41,12 @@ export class SlackProvider implements INotificationProvider {
|
||||
notification: Notification,
|
||||
monitor: Monitor,
|
||||
monitorStatusResponse: MonitorStatusResponse,
|
||||
decision: MonitorActionDecision
|
||||
decision: MonitorActionDecision,
|
||||
clientHost: string
|
||||
): Promise<boolean> {
|
||||
let body;
|
||||
if (monitor.type === "hardware") {
|
||||
body = this.getHardwareContent("HOST_PLACEHOLDER", monitor, monitorStatusResponse, decision);
|
||||
body = this.getHardwareContent(clientHost, monitor, monitorStatusResponse, decision);
|
||||
} else {
|
||||
body = this.getContent(monitor, monitorStatusResponse);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ export class WebhookProvider implements INotificationProvider {
|
||||
return buildWebhookBody(monitor, monitorStatusResponse);
|
||||
}
|
||||
// For threshold breaches, use hardware alert format
|
||||
const { alertsToSend } = buildHardwareAlerts("HOST_PLACEHOLDER", monitor, monitorStatusResponse);
|
||||
const { alertsToSend } = buildHardwareAlerts(clientHost, monitor, monitorStatusResponse);
|
||||
const body = buildHardwareNotificationMessage(clientHost, alertsToSend, monitor);
|
||||
return body;
|
||||
};
|
||||
@@ -37,10 +37,16 @@ export class WebhookProvider implements INotificationProvider {
|
||||
return body;
|
||||
};
|
||||
|
||||
sendAlert = async (notification: Notification, monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, decision: MonitorActionDecision) => {
|
||||
sendAlert = async (
|
||||
notification: Notification,
|
||||
monitor: Monitor,
|
||||
monitorStatusResponse: MonitorStatusResponse,
|
||||
decision: MonitorActionDecision,
|
||||
clientHost: string
|
||||
) => {
|
||||
let body;
|
||||
if (monitor.type === "hardware") {
|
||||
body = this.getHardwareContent("HOST_PLACEHOLDER", monitor, monitorStatusResponse, decision);
|
||||
body = this.getHardwareContent(clientHost, monitor, monitorStatusResponse, decision);
|
||||
} else {
|
||||
body = this.getContent(monitor, monitorStatusResponse);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { HardwareStatusPayload, Monitor, MonitorStatusResponse, Notificatio
|
||||
import { IMonitorsRepository, INotificationsRepository } from "@/repositories/index.js";
|
||||
import { INotificationProvider } from "./notificationProviders/INotificationProvider.js";
|
||||
import type { MonitorActionDecision } from "@/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js";
|
||||
import type { ISettingsService } from "@/service/system/settingsService.js";
|
||||
|
||||
export interface INotificationsService {
|
||||
createNotification: (notificationData: Partial<Notification>) => Promise<Notification>;
|
||||
@@ -29,6 +30,7 @@ export class NotificationsService implements INotificationsService {
|
||||
private pagerDutyProvider: INotificationProvider;
|
||||
private matrixProvider: INotificationProvider;
|
||||
private logger: any;
|
||||
private settingsService: ISettingsService;
|
||||
|
||||
// Email grouping (batching) configuration
|
||||
private emailGroupingWindowMs: number;
|
||||
@@ -52,6 +54,7 @@ export class NotificationsService implements INotificationsService {
|
||||
discordProvider: INotificationProvider,
|
||||
pagerDutyProvider: INotificationProvider,
|
||||
matrixProvider: INotificationProvider,
|
||||
settingsService: ISettingsService,
|
||||
logger: any
|
||||
) {
|
||||
this.notificationsRepository = notificationsRepository;
|
||||
@@ -62,6 +65,7 @@ export class NotificationsService implements INotificationsService {
|
||||
this.discordProvider = discordProvider;
|
||||
this.pagerDutyProvider = pagerDutyProvider;
|
||||
this.matrixProvider = matrixProvider;
|
||||
this.settingsService = settingsService;
|
||||
this.logger = logger;
|
||||
|
||||
// Configure email grouping window (in milliseconds).
|
||||
@@ -82,19 +86,21 @@ export class NotificationsService implements INotificationsService {
|
||||
}
|
||||
|
||||
private send = async (notification: Notification, monitor: Monitor, monitorStatusResponse: MonitorStatusResponse): Promise<boolean> => {
|
||||
const settings = this.settingsService.getSettings();
|
||||
const clientHost = settings.clientHost || "Host not defined";
|
||||
switch (notification.type) {
|
||||
case "email":
|
||||
return await this.emailProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!);
|
||||
return await this.emailProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!, clientHost);
|
||||
case "slack":
|
||||
return await this.slackProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!);
|
||||
return await this.slackProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!, clientHost);
|
||||
case "discord":
|
||||
return await this.discordProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!);
|
||||
return await this.discordProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!, clientHost);
|
||||
case "pager_duty":
|
||||
return await this.pagerDutyProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!);
|
||||
return await this.pagerDutyProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!, clientHost);
|
||||
case "matrix":
|
||||
return await this.matrixProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!);
|
||||
return await this.matrixProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!, clientHost);
|
||||
case "webhook":
|
||||
return await this.webhookProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!);
|
||||
return await this.webhookProvider.sendAlert(notification, monitor, monitorStatusResponse, this.currentDecision!, clientHost);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -215,6 +221,12 @@ export class NotificationsService implements INotificationsService {
|
||||
return false;
|
||||
}
|
||||
|
||||
const { clientHost } = this.settingsService.getSettings();
|
||||
if (!clientHost) {
|
||||
this.logger.warn({ message: "CLIENT_HOST not configured", service: SERVICE_NAME, method: "flushEmailGroup" });
|
||||
return false;
|
||||
}
|
||||
|
||||
// Build a combined monitor name listing all affected services.
|
||||
// Example: "Service A, Service B" (2 services) or "Service A" (1 service)
|
||||
const uniqueNames = Array.from(new Set(monitors.map((m) => m.name)));
|
||||
@@ -235,7 +247,7 @@ export class NotificationsService implements INotificationsService {
|
||||
};
|
||||
|
||||
// Reuse existing email provider to send grouped notification.
|
||||
return await this.emailProvider.sendAlert(notification, syntheticMonitor, baseStatus, decision);
|
||||
return await this.emailProvider.sendAlert(notification, syntheticMonitor, baseStatus, decision, clientHost);
|
||||
};
|
||||
|
||||
handleNotifications = async (monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, decision: MonitorActionDecision) => {
|
||||
|
||||
Reference in new issue
Block a user