From 57e7a84e63390d946a7bc047052b3a623de5b22c Mon Sep 17 00:00:00 2001 From: Kim Brose <2803622+HarHarLinks@users.noreply.github.com> Date: Wed, 16 Aug 2023 19:06:15 +0200 Subject: [PATCH] Create alertmanager.js (#808) * Create alertmanager.js * Add changelog * Rename contrib/alertmanager.js to contrib/jsTransformationFunctions/alertmanager.js * Add docs to alertmanager.js * Update alertmanager.js * Update alertmanager.js with paragraphs * Update alertmanager.js convert `\n` line breaks to html `
` so the upstream formatting is applied --------- Co-authored-by: Will Hunt --- changelog.d/808.feature | 1 + .../jsTransformationFunctions/alertmanager.js | 68 +++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 changelog.d/808.feature create mode 100644 contrib/jsTransformationFunctions/alertmanager.js diff --git a/changelog.d/808.feature b/changelog.d/808.feature new file mode 100644 index 00000000..8ab64a6f --- /dev/null +++ b/changelog.d/808.feature @@ -0,0 +1 @@ +Add generic webhook transformation JS snippet for Prometheus Alertmanager. diff --git a/contrib/jsTransformationFunctions/alertmanager.js b/contrib/jsTransformationFunctions/alertmanager.js new file mode 100644 index 00000000..11ec18aa --- /dev/null +++ b/contrib/jsTransformationFunctions/alertmanager.js @@ -0,0 +1,68 @@ +/** + * This is a transformation function for Prometheus Alertmanager webhooks. + * https://prometheus.io/docs/alerting/latest/configuration/#webhook_config + * + * Creates a formatted `m.text` message with plaintext fallback, containing: + * - alert status and severity + * - alert name and description + * - URL to the entity that caused the alert + * The formatted message also contains a clickable link that silences the alert. + */ + +/** + * @param status resolved or firing + * @param severity from the labels of the alert + * @returns colored text rendering of the status and severity + */ +function statusBadge(status, severity) { + let statusColor; + if (status === "resolved") { + return `[RESOLVED]`; + } + + switch(severity) { + case 'resolved': + case 'critical': + return `[FIRING - CRITICAL]`; + case 'warning': + return `[FIRING - WARNING]`; + default: + return `[${status.toUpperCase()}]`; + } +} + +/** + * @param alert object from the webhook payload + * @param externalURL from the webhook payload + * @returns a formatted link that will silence the alert when clicked + */ +function silenceLink(alert, externalURL) { + filters = [] + for (const [label, val] of Object.entries(alert.labels)) { + filters.push(encodeURIComponent(`${label}="${val}"`)); + } + return `silence`; +} + +if (!data.alerts) { + result = { + version: 'v2', + empty: true, + }; + return; +} + +const plainErrors = []; +const htmlErrors = []; +const { externalURL, alerts } = data; + +for (const alert of data.alerts) { + plainErrors.push(`**[${alert.status.toUpperCase()} - ${alert.labels.severity}]** - ${alert.labels.alertname}: ${alert.annotations.description} [source](${alert.generatorURL})`); + htmlErrors.push(`

${statusBadge(alert.status, alert.labels.severity)}

${alert.labels.alertname}: ${alert.annotations.description.replaceAll("\n","")}

source | ${silenceLink(alert, externalURL)}

`) + result = { + version: 'v2', + plain: plainErrors.join(`\n\n`), + html: htmlErrors.join(`

`), + msgtype: 'm.text' + }; +}