# Larm

## Vad det är

Ett larm är en automatisk signal om att ett villkor som någon bevakar har gällt så länge att det är
värt att avbryta en människa för det. På engelska heter det alert eller alarm, och ett larm som är
allvarligt nog att väcka den som har jour kallas ofta en page.

Ordet täcker två olika saker, och Prometheus håller isär dem på ett sätt som gör skillnaden lätt att
se. En larmregel (alerting rule) i Prometheus skapar larm: ett för varje unik uppsättning etiketter
som uttrycket ger ett resultat för. Larmen går vidare till ett separat program, Alertmanager, som
gör om dem till aviseringar: ett mejl, ett chattmeddelande, ett anrop till en jourtjänst. Projektet
skriver rakt ut att larmregler ensamma inte är ett komplett system för aviseringar. Uppdelningen
spelar roll eftersom antalen går isär. Femtio larm kan komma fram som ett enda meddelande, ett larm
kan ge en påminnelse med några timmars mellanrum, och ett larm som har tystats når ingen alls fast
det fortfarande är utlöst.

Livscykeln är kort. Så länge uttrycket inte returnerar något är larmet inaktivt (inactive). När det
för första gången ger ett resultat blir larmet väntande (pending), och det förblir väntande så länge
regelns `for`-klausul kräver. Gäller villkoret fortfarande när väntan är över utlöses larmet
(firing) och lämnas vidare för leverans. När villkoret upphör att gälla återgår larmet (resolved).
En nyare klausul, `keep_firing_for`, håller ett utlöst larm öppet en stund efter att villkoret har
släppt, och dokumentationen beskriver den som ett skydd mot fladder och falska återgångar.
Prometheus sparar dessutom tillstånden väntande och utlöst som en tidsserie med namnet `ALERTS`, så
att själva larmen går att söka i och rita grafer över.

En regel som väntar tjugo minuter innan den utlöses, och tio minuter till innan den släpper, ser ut
så här:

```yaml
groups:
    - name: exports
      rules:
          - alert: ExportQueueStalled
            expr: exports_waiting > 0 and rate(exports_done_total[15m]) == 0
            for: 20m
            keep_firing_for: 10m
            labels:
                severity: page
                team: billing
            annotations:
                summary: "{{ $value }} exports queued and none finishing"
```

Etiketter (labels) och annoteringar (annotations) ser likadana ut men gör olika jobb. Etiketterna
är en del av det som gör ett larm till just det larmet och inget annat, och Alertmanager läser dem
för att avgöra vart det ska: `severity: page` kan nå en telefon medan `severity: ticket` hamnar i en
kö för ärenden. Annoteringarna bär orden som en människa behöver när meddelandet väl har kommit
fram: en sammanfattning på en rad, en längre beskrivning, en länk till runbooken som säger vad som
ska göras först. Annoteringar kan byggas med mallar av larmets etiketter och värdet som utlöste det,
och det är så sammanfattningen ovan kan citera en siffra.

Larm och incident är olika ord av ett skäl. Ett larm rapporterar att ett villkor gällde. Att avgöra
om villkoret utgör en incident är en människas beslut.

## Varför det spelar roll

Larmet är den enda delen av övervakningen som inte väntar på att någon ska titta. Systemmätvärden
ligger i lagring, en dashboard väntar på en skärm, en logg väntar på en sökning, och ett larm
tränger sig in i någons kväll. Det gör varje larmregel till ett litet stående anspråk på en
människas uppmärksamhet, och anspråket är skäligt bara om människan kan göra något åt saken.
Prometheus egna råd om larm uttrycker det som att undvika att väcka någon när det inte finns något
att göra, och att hålla larmen enkla.

Det andra skälet är ren aritmetik. En enda orsak utlöser oftast många regler på en gång. När en
nätverkspartition skär av hälften av en tjänsts instanser från deras databas kan varje instans
utlösa ett eget larm, och dokumentationen för Alertmanager använder just det fallet för att visa hur
hundratals larm blir en enda avisering. Alertmanager samlar larm som delar etiketterna i `group_by`
och väntar `group_wait` (30 sekunder som standard), så att det första meddelandet rymmer hela
omgången. Därefter skickar den uppdateringar för gruppen högst en gång per `group_interval` (5
minuter) och upprepar ett meddelande som fortfarande gäller efter `repeat_interval` (4 timmar).
Undertryckning (inhibition) går ett steg längre och håller tillbaka vissa larm medan ett annat är
utlöst, så att ett larm om att ett helt kluster är onåbart kan tysta larmen från varje tjänst
därinne. En silence stänger av larm som matchar en uppsättning etiketter under en bestämd tid,
oftast under planerat underhåll.

Det tredje skälet gäller slutet på historien. De flesta mottagare skickar ett meddelande om
återgång när larmet släpper, men e-postmottagarens inställning `send_resolved` är som standard
false. Ett team som larmar via e-post kan alltså se problemet annonseras och aldrig se det ta slut.

## Så ser det ut i praktiken

Larmen på företagets egen värd är byggda åt andra hållet. En värd med 464 MB minne kör en forge, en
databas och en webbserver, och den dör troligast av att minnet eller disken tar slut, två fel som
inte varnar i förväg. Ett larm som förutsätter att värden säger ifrån medan den går sönder är
oanvändbart där, eftersom det är den trasiga värden som skulle behöva säga något. I stället
[pingar en timer på värden en extern tjänst bara medan både minne och disk är friska](/sv/portfolio/built-dead-mans-switch-monitoring-115/),
var femtonde minut med slumpmässig förskjutning, och den externa tjänsten larmar när pingarna
upphör. Det är ett dödmansgrepp: tystnaden är larmet. Varje sätt som värden kan gå sönder på, ett
tappat nätverk och en start som stannar halvvägs inräknade, slutar i samma uteblivna ping, och det
är precis vad konstruktionen är till för. Sidan anger också dess gräns: kontrollen bevisar att
maskinen är frisk och säger ingenting om huruvida webbplatsen svarar.

Samma omvändning vaktar schemalagt arbete. Den krypterade säkerhetskopieringen till lagring utanför
värden körs på en timer och
[pingar sitt dödmansgrepp bara när en körning lyckas](/sv/portfolio/built-encrypted-backups-with-a-monthly-restore-drill-114/),
så en misslyckad körning ger tystnad. Tystnaden är det som blir ett larm, och det upptäcks av något
utanför maskinen i stället för att skrivas till en logg på den.

Omvända larm har ett eget felläge, och det visade sig när plattformen skulle växa från en värd till
två. Att låta båda värdarna dela ett grepp hade
[försvagat larmen som det var tänkt att utvidga](/sv/portfolio/split-every-operational-secret-per-host-125/):
så länge någon av värdarna fortsätter att pinga förblir kontrollen grön medan den andra är död.
Greppen delades upp med en post per värd, och den befintliga värdens poster lämnades tomma med
avsikt, så att konfigurationen säger att kopplingen finns och att värdet återstår att fylla i.

## Var det går fel

**Ett uppmätt värde hamnar i en etikett.** Eftersom etiketterna identifierar ett larm gör en etikett
som bär det aktuella talet varje ändring av talet till ett nytt larm, och det förra återgår.
Mottagaren ser en ström av par, utlöst och återgått, för ett och samma problem. Använd etiketter för
identitet och routning, och lägg siffror i annoteringar.

**Larmet fladdrar.** Ett villkor som pendlar kring sitt tröskelvärde utlöses, återgår och utlöses
igen med några minuters mellanrum, och varje meddelande om återgång säger något falskt till den som
läser. Förläng `for` så att en tillfällig topp hinner försvinna innan någon hör om den, och använd
`keep_firing_for` så att en kort dipp under tröskeln inte avslutar larmet.

**En silence lever längre än sitt skäl.** Någon tystar ett larm inför underhåll med en bred
matchning och en generös sluttid, och nästa veckas verkliga fel kommer fram tystat. Matcha silences
så snävt som arbetet tillåter, ge dem en sluttid nära den tidpunkt då arbetet borde vara klart, och
skriv vem som satte dem och varför i kommentarsfältet som Alertmanager erbjuder.

**En bred rutt sväljer de specifika.** Alertmanager går igenom routningsträdet i ordning och stannar
vid det första barnet som matchar, om inte en rutt sätter `continue: true`. En samlingsrutt som
ligger ovanför ett teams egen rutt tar med sig teamets larm. Lägg de snävaste rutterna först och
testa trädet med exempeletiketter innan ni förlitar er på det.

**Allt är bråttom.** Disk på 70 %, ett certifikat som går ut nästa månad och en betaltjänst som
returnerar fel går alla till samma telefon, och snart börjar telefonen ignoreras. Larma bara för
villkor som en människa måste agera på nu, skicka resten till en kö för ärenden eller en daglig
sammanfattning, och radera en regel som har utlösts i månader utan att någon har agerat på den.

## Läs mer

- [Alerting overview](https://prometheus.io/docs/alerting/latest/overview/) — hur larmregler i
  Prometheus och Alertmanager delar på arbetet, och stegen för att sätta upp båda.
- [Alerting rules](https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/) —
  syntaxen för regler, med `for`, `keep_firing_for`, etiketter, annoteringar och mallar.
- [Alertmanager](https://prometheus.io/docs/alerting/latest/alertmanager/) — gruppering,
  undertryckning, silences och hur fler än en Alertmanager körs för hög tillgänglighet.
- [Alertmanager configuration](https://prometheus.io/docs/alerting/latest/configuration/) —
  routningsträdet, grupperingens timers, regler för undertryckning och varje mottagares
  inställningar, bl.a. `send_resolved`.
- [Alerting practices](https://prometheus.io/docs/practices/alerting/) — projektets egna råd om vad
  som är värt att väcka någon för och vad som hör hemma någon annanstans.

<https://engineer.company/sv/glossary/alert/>
