forked from viossat/alertmanager-discord
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathhandlers_alternative.js
136 lines (129 loc) · 5.95 KB
/
handlers_alternative.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
const axios = require("axios");
const colors = { firing: 0xd50000, resolved: 0x00c853 };
const maxEmbedsLength = 10;
const maxFieldsLength = 25;
const groupBy = (array, func) => {
return array.reduce((group, item) => {
const groupName = func(item);
group[groupName] = group[groupName] ?? [];
group[groupName].push(item);
return group;
}, {});
};
const getMentions = (alerts) => {
return [...alerts].reduce((mentions, alert) => {
if (alert.labels["mentions"]) {
alert.labels["mentions"]
.replace(/ /g, "")
.split(",")
.forEach((m) => mentions.push(`<@${m}>`));
}
return mentions;
}, []);
};
async function handleHook(ctx) {
let hook = ctx.routes[ctx.params.slug];
if (ctx.request.body && Array.isArray(ctx.request.body.alerts)) {
const raws = [];
const groupByStatus = groupBy(ctx.request.body.alerts, (alert) => alert.status);
for (const byStatus of Object.values(groupByStatus)) {
const [first] = byStatus;
if (first.annotations && (first.annotations.summary || first.annotations.description)) {
const statusColor = first.status === "resolved" ? colors.resolved : colors.firing;
const title = (a) =>
a.status === "resolved"
? a.annotations["resolved_summary"] ?? a.annotations.summary
: a.annotations.summary;
const desc = (a) =>
a.status === "resolved"
? a.annotations["resolved_description"] ?? a.annotations.description
: a.annotations.description;
if (first.annotations["field_name"] && first.annotations["field_value"]) {
let chunk = [];
while ((chunk = byStatus.splice(0, maxFieldsLength)) && chunk.length) {
raws.push({
mentions: getMentions(chunk),
embed: {
title: `${first.annotations["emoji"] ? first.annotations.emoji + " " : ""}${
chunk.length
} ${title(first)}`,
url: statusColor === colors.firing ? first.annotations["url"] ?? "" : "",
description: desc(first),
color: statusColor,
fields: chunk.map((a) => ({
name: a.annotations.field_name,
value: a.annotations.field_value,
inline: true,
})),
footer: {
text: first.annotations.footer_text ?? "",
icon_url: first.annotations.footer_icon_url ?? "",
},
},
});
}
} else {
byStatus.forEach((a) => {
raws.push({
mentions: getMentions([a]),
embed: {
title: `${first.annotations["emoji"] ? first.annotations.emoji + " " : ""}${title(
a
)}`,
url: statusColor === colors.firing ? first.annotations["url"] ?? "" : "",
description: desc(a),
color: statusColor,
footer: {
text: first.annotations.footer_text ?? "",
icon_url: first.annotations.footer_icon_url ?? "",
},
},
});
});
}
}
}
raws.sort((a) => (a.embed.color === colors.resolved ? -1 : 1));
if (!raws.length) {
ctx.status = 400;
ctx.logger.warn("No data to write to embeds");
return;
}
let chunk = [];
while ((chunk = raws.splice(0, maxEmbedsLength)) && chunk.length) {
// Discord displays only one embed if several embeds have the same url in one message.
// Then only one (last fired) embed will have URL in each chunk
chunk.forEach((e) =>
chunk.filter((a) => a.embed.url === e.embed.url).length > 1 ? (e.embed.url = "") : undefined
);
const mentions = [...new Set(chunk.map((c) => c.mentions).flat())].join(" ");
const payload = { embeds: chunk.map((c) => c.embed) };
if (mentions.length !== 0) {
payload.content = mentions;
payload.allowed_mentions = { parse: ["users", "roles"] };
}
await axios
.post(hook, payload)
.then(() => {
ctx.status = 200;
ctx.logger.info(chunk.length + " embeds sent");
})
.catch((err) => {
ctx.status = 500;
const errorConfig = err.config || {};
const errorMessage = err.message
+ (errorConfig.method != null ? `; Method: ${errorConfig.method}` : '')
+ (errorConfig.data != null ? `; Request data length: ${
errorConfig.data.length
}; Request data: ${JSON.stringify(errorConfig.data)}` : '');
ctx.logger.error(`Axios error in "handlers_alternative.js": ${errorMessage}`);
});
}
} else {
ctx.status = 400;
ctx.logger.error(`Unexpected request from Alertmanager: ${JSON.stringify(ctx.request.body)}`);
}
}
module.exports = {
handleHook,
};