feat(notifications): add rich alert fields
This commit is contained in:
1 parent
2c780b8101
commit
865fa7cce6
2 files changed
+98
-7
No files matched your search
@@ -84,6 +84,39 @@ export class RocketChatProvider extends NotificationProvider {
|
||||
}
|
||||
|
||||
private buildPayload(message: NotificationMessage): RocketChatPayload {
|
||||
const fields: RocketChatField[] = [
|
||||
{ title: "Monitor", value: message.monitor.name, short: true },
|
||||
{ title: "Type", value: message.monitor.type, short: true },
|
||||
{ title: "Status", value: message.monitor.status, short: true },
|
||||
{ title: "URL", value: message.monitor.url, short: false },
|
||||
];
|
||||
|
||||
if (message.content.thresholds?.length) {
|
||||
fields.push(
|
||||
...message.content.thresholds.map((breach) => ({
|
||||
title: breach.metric.toUpperCase(),
|
||||
value: `${breach.formattedValue} (threshold: ${breach.threshold}${breach.unit})`,
|
||||
short: true,
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
if (message.content.details?.length) {
|
||||
fields.push({
|
||||
title: "Details",
|
||||
value: message.content.details.map((detail) => `- ${detail}`).join("\n"),
|
||||
short: false,
|
||||
});
|
||||
}
|
||||
|
||||
if (message.content.incident) {
|
||||
fields.push({
|
||||
title: "Incident",
|
||||
value: message.content.incident.url,
|
||||
short: false,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
text: message.content.summary,
|
||||
attachments: [
|
||||
@@ -91,12 +124,7 @@ export class RocketChatProvider extends NotificationProvider {
|
||||
color: this.severityColor(message.severity),
|
||||
title: message.content.title,
|
||||
title_link: `${message.clientHost}/infrastructure/${message.monitor.id}`,
|
||||
fields: [
|
||||
{ title: "Monitor", value: message.monitor.name, short: true },
|
||||
{ title: "Type", value: message.monitor.type, short: true },
|
||||
{ title: "Status", value: message.monitor.status, short: true },
|
||||
{ title: "URL", value: message.monitor.url, short: false },
|
||||
],
|
||||
fields,
|
||||
ts: message.content.timestamp.toISOString(),
|
||||
},
|
||||
],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { describe, expect, it, jest } from "@jest/globals";
|
||||
import type { NotificationSeverity } from "../../../../src/domain/notifications/notification.type.ts";
|
||||
import { createMockLogger } from "../../../helpers/createMockLogger.ts";
|
||||
import { makeMessage, makeNotification } from "../../../helpers/notificationMessage.ts";
|
||||
import { makeMessage, makeMessageWithIncident, makeMessageWithThresholds, makeNotification } from "../../../helpers/notificationMessage.ts";
|
||||
import { testNotificationProviderContract } from "../../../helpers/notificationProviderContract.ts";
|
||||
|
||||
const mockGotPost = jest.fn().mockResolvedValue({});
|
||||
@@ -108,6 +108,11 @@ describe("RocketChatProvider", () => {
|
||||
{ title: "Type", value: "http", short: true },
|
||||
{ title: "Status", value: "down", short: true },
|
||||
{ title: "URL", value: "https://example.com", short: false },
|
||||
{
|
||||
title: "Details",
|
||||
value: "- URL: https://example.com\n- Status: Down",
|
||||
short: false,
|
||||
},
|
||||
],
|
||||
ts: "2025-01-01T00:00:00.000Z",
|
||||
},
|
||||
@@ -138,6 +143,64 @@ describe("RocketChatProvider", () => {
|
||||
expect(payload.attachments[0].color).toBe(color);
|
||||
});
|
||||
|
||||
it("appends threshold fields before details", async () => {
|
||||
const { provider } = createProvider();
|
||||
|
||||
await provider.sendMessage(makeNotification({ type: "rocket_chat" }), makeMessageWithThresholds());
|
||||
|
||||
const fields = mockGotPost.mock.calls[0][1].json.attachments[0].fields;
|
||||
expect(fields).toEqual([
|
||||
{ title: "Monitor", value: "Infra Server", short: true },
|
||||
{ title: "Type", value: "hardware", short: true },
|
||||
{ title: "Status", value: "up", short: true },
|
||||
{ title: "URL", value: "https://infra.example.com", short: false },
|
||||
{ title: "CPU", value: "90.0% (threshold: 80%)", short: true },
|
||||
{ title: "MEMORY", value: "85.0% (threshold: 70%)", short: true },
|
||||
{ title: "Details", value: "- URL: https://infra.example.com", short: false },
|
||||
]);
|
||||
});
|
||||
|
||||
it("appends the incident URL after details", async () => {
|
||||
const { provider } = createProvider();
|
||||
|
||||
await provider.sendMessage(makeNotification({ type: "rocket_chat" }), makeMessageWithIncident());
|
||||
|
||||
const fields = mockGotPost.mock.calls[0][1].json.attachments[0].fields;
|
||||
expect(fields).toEqual([
|
||||
{ title: "Monitor", value: "Test Monitor", short: true },
|
||||
{ title: "Type", value: "http", short: true },
|
||||
{ title: "Status", value: "down", short: true },
|
||||
{ title: "URL", value: "https://example.com", short: false },
|
||||
{ title: "Details", value: "- URL: https://example.com\n- Status: Down", short: false },
|
||||
{ title: "Incident", value: "https://app.example.com/incidents/inc-1", short: false },
|
||||
]);
|
||||
});
|
||||
|
||||
it("omits empty optional fields", async () => {
|
||||
const { provider } = createProvider();
|
||||
const message = makeMessage();
|
||||
|
||||
await provider.sendMessage(
|
||||
makeNotification({ type: "rocket_chat" }),
|
||||
makeMessage({
|
||||
content: {
|
||||
...message.content,
|
||||
details: [],
|
||||
thresholds: [],
|
||||
incident: undefined,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
const fields = mockGotPost.mock.calls[0][1].json.attachments[0].fields;
|
||||
expect(fields).toEqual([
|
||||
{ title: "Monitor", value: "Test Monitor", short: true },
|
||||
{ title: "Type", value: "http", short: true },
|
||||
{ title: "Status", value: "down", short: true },
|
||||
{ title: "URL", value: "https://example.com", short: false },
|
||||
]);
|
||||
});
|
||||
|
||||
it("returns false when the message webhook URL is missing", async () => {
|
||||
const { provider } = createProvider();
|
||||
|
||||
|
||||
Reference in new issue
Block a user