|
| 1 | +/** |
| 2 | + * This is a transformation function for Prometheus Alertmanager webhooks. |
| 3 | + * https://prometheus.io/docs/alerting/latest/configuration/#webhook_config |
| 4 | + * |
| 5 | + * Creates a formatted `m.text` message with plaintext fallback, containing: |
| 6 | + * - alert status and severity |
| 7 | + * - alert name and description |
| 8 | + * - URL to the entity that caused the alert |
| 9 | + * The formatted message also contains a clickable link that silences the alert. |
| 10 | + */ |
| 11 | + |
| 12 | +/** |
| 13 | + * @param status resolved or firing |
| 14 | + * @param severity from the labels of the alert |
| 15 | + * @returns colored text rendering of the status and severity |
| 16 | + */ |
| 17 | +function statusBadge(status, severity) { |
| 18 | + let statusColor; |
| 19 | + if (status === "resolved") { |
| 20 | + return `<font color='green'><b>[RESOLVED]</b></font>`; |
| 21 | + } |
| 22 | + |
| 23 | + switch(severity) { |
| 24 | + case 'resolved': |
| 25 | + case 'critical': |
| 26 | + return `<font color='red'><b>[FIRING - CRITICAL]</b></font>`; |
| 27 | + case 'warning': |
| 28 | + return `<font color='orange'><b>[FIRING - WARNING]</b></font>`; |
| 29 | + default: |
| 30 | + return `<b>[${status.toUpperCase()}]</b>`; |
| 31 | + } |
| 32 | +} |
| 33 | + |
| 34 | +/** |
| 35 | + * @param alert object from the webhook payload |
| 36 | + * @param externalURL from the webhook payload |
| 37 | + * @returns a formatted link that will silence the alert when clicked |
| 38 | + */ |
| 39 | +function silenceLink(alert, externalURL) { |
| 40 | + filters = [] |
| 41 | + for (const [label, val] of Object.entries(alert.labels)) { |
| 42 | + filters.push(encodeURIComponent(`${label}="${val}"`)); |
| 43 | + } |
| 44 | + return `<a href="${externalURL}#silences/new?filter={${filters.join(",")}}">silence</a>`; |
| 45 | +} |
| 46 | + |
| 47 | +if (!data.alerts) { |
| 48 | + result = { |
| 49 | + version: 'v2', |
| 50 | + empty: true, |
| 51 | + }; |
| 52 | + return; |
| 53 | +} |
| 54 | + |
| 55 | +const plainErrors = []; |
| 56 | +const htmlErrors = []; |
| 57 | +const { externalURL, alerts } = data; |
| 58 | + |
| 59 | +for (const alert of data.alerts) { |
| 60 | + plainErrors.push(`**[${alert.status.toUpperCase()} - ${alert.labels.severity}]** - ${alert.labels.alertname}: ${alert.annotations.description} [source](${alert.generatorURL})`); |
| 61 | + htmlErrors.push(`<p>${statusBadge(alert.status, alert.labels.severity)}</p><p><b>${alert.labels.alertname}</b>: ${alert.annotations.description.replaceAll("\n","<br\>")}</p><p><a href="${alert.generatorURL}">source</a> | ${silenceLink(alert, externalURL)}</p>`) |
| 62 | + result = { |
| 63 | + version: 'v2', |
| 64 | + plain: plainErrors.join(`\n\n`), |
| 65 | + html: htmlErrors.join(`<br/><br/>`), |
| 66 | + msgtype: 'm.text' |
| 67 | + }; |
| 68 | +} |
0 commit comments