Skip to content

Generic Alertmanager support with rich formatter#15

Open
ornariece wants to merge 6 commits into
moan0s:mainfrom
ornariece:alertmanager-support
Open

Generic Alertmanager support with rich formatter#15
ornariece wants to merge 6 commits into
moan0s:mainfrom
ornariece:alertmanager-support

Conversation

@ornariece
Copy link
Copy Markdown

@ornariece ornariece commented Apr 5, 2026

Problem

Webhook detection currently checks for labels.job to identify Prometheus alerts. But job is just a scrape-config label that Prometheus happens to add — it's not part of the Alertmanager webhook format. Alerts from custom recording rules, Thanos, Mimir, or any other source routed through Alertmanager don't necessarily have it, so they silently fall through to the raw "Data received" fallback.

The formatter is also minimal — it shows status, a title, and three hardcoded labels. Annotations, timestamps, and actionable links (silence, source) are not surfaced.

There are also a few bugs: hasattr(dict, 'key') is used for annotation lookup, which is always False on dicts (keys are accessed via __getitem__, not attributes), so the description annotation is never read. Webhook detection only catches KeyError, missing IndexError/TypeError from malformed payloads. The slack-webhook branch uses if instead of elif, causing fall-through.

Solution

Generic detection: Check labels.alertname instead of labels.job. alertname is mandatory in every Alertmanager webhook per the data model. Since Prometheus alerts are sent through Alertmanager, they always have alertname too — nothing is lost. Grafana alerts are unaffected (they match first on grafana_folder).

Rich formatter: New alertmanager_to_markdown() produces one structured message per alert:

🔥 **InstanceDown** · critical

webserver.example.com of job node_exporter has been down for more than 5 minutes.

• **Instance:** webserver.example.com
• **Job:** node_exporter
• **Since:** 2024-03-30 08:00 UTC

Source · Silence
  • Emoji status line with alert name + severity (doubles as push notification preview)
  • Description from annotations (description preferred, summary fallback)
  • All labels except alertname/severity as metadata
  • Duration calculation for resolved alerts
  • Pre-filled silence URL from externalURL
  • Source link from generatorURL

Bug fixes (separate commits):

  • hasattrin for dict key lookup on annotations
  • Catch IndexError and TypeError in addition to KeyError in webhook detection
  • Fix if/elif fall-through in the slack-webhook dispatch branch
  • e.with_traceback() (returns None) → str(e) in error messages
  • Unicode bullet instead of - list marker to avoid inconsistent <li> indentation on Element X iOS

Tests: Fixed the existing test (it called find_alert_type which doesn't exist — should be get_alert_type) and added coverage for the new formatter, helper functions, classification edge cases, and malformed payloads. 25 tests total.

Breaking changes

  • prometheus-alert / prometheus-resolved type strings → alertmanager-alert / alertmanager-resolved
  • prometheus_alert_to_markdown() removed (replaced by alertmanager_to_markdown())
  • send_alert() takes a Request object instead of pre-read text (internal method)

hasattr(dict, 'key') is always False — dicts expose keys via
__getitem__, not as attributes. This meant the description annotation
was never read, always falling back to summary.
- Catch IndexError and TypeError in addition to KeyError when probing
  webhook payloads, since malformed data may have wrong types or empty
  arrays rather than missing keys.
- Fix if/elif chain in get_alert_messages — the slack-webhook branch
  used 'if' instead of 'elif', causing unintended fall-through.
- Fix error message: e.with_traceback() returns None, use str(e).
The upstream Prometheus detection required a "job" label, which is
only present in Prometheus-originated alerts. Replace with "alertname"
detection, which matches ALL Alertmanager webhook payloads regardless
of the alert source (Prometheus, custom rules, Thanos, Mimir, etc.).

New alertmanager_to_markdown() produces structured messages optimized
for mobile notification clients:

- Emoji status line (firing/resolved) with alert name and severity
- Description from annotations (with correct dict key lookup)
- Label metadata as list items (all labels except alertname/severity)
- Duration calculation for resolved alerts
- Pre-filled silence URL from Alertmanager's externalURL
- Source link from generatorURL

Move request text reading into send_alert, reducing the webhook
handler to routing and error handling.
CommonMark converts '- ' prefixed lines into <ul><li> HTML. Element X
iOS renders the first <li> with indent but subsequent items without,
causing visual misalignment.

Replace the markdown list marker with a Unicode bullet character.
CommonMark now emits <p> + <br> instead, which renders consistently
across Matrix clients.
Fix upstream test that called non-existent find_alert_type (should be
get_alert_type). Update expected type for Prometheus payloads from
"prometheus-alert" to "alertmanager-alert" to match the generic
Alertmanager detection.

Add tests for:
- All alert type classification paths including edge cases
- Alertmanager-without-job-label detection
- Malformed payload resilience (empty arrays, wrong types, None)
- alertmanager_to_markdown: firing, resolved, duration, description
  vs summary fallback, label metadata, silence/source URLs, multi-
  alert groups, real Prometheus example payload
- _format_duration, _format_timestamp, _build_silence_url
Add a supported webhook types table showing detection logic for each
format. Expand the Alertmanager setup section with send_resolved,
example message output for firing and resolved alerts, and
generic example URLs. Fix the test alert curl example to reference
the correct filename. Add a dependencies section for python-dateutil.
@ornariece ornariece force-pushed the alertmanager-support branch from 28678dd to a7f6bdb Compare April 5, 2026 21:07
@ornariece ornariece changed the title feat: generic Alertmanager support with rich formatter Generic Alertmanager support with rich formatter Apr 5, 2026
@ornariece ornariece marked this pull request as ready for review April 5, 2026 21:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant