Intensiv DevOps-uddannelse · Lektion

Forespørgsler til journald med journalctl i scripts

Filtrér systemd-journalposter efter unit, prioritet og tidspunkt til automatiseret triage af hændelser.

Lektion 3 af 413 trin

Forespørgsler til journald med journalctl i scripts er en gratis Intensiv DevOps-uddannelse-lektion på CoddyKit. Dette er lektion 3 af 4. Du kan læse alle 3 lektioner i dette læringsspor gratis i deres fulde længde — derefter låser CoddyKit PRO alle lektioner op samt praktiske øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Den er en del af læringsforløbet i Intensiv DevOps-uddannelse, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Intensiv DevOps-uddannelse-kurset indeholder 4 lektioner i alt.

Hvorfor journald til indledende hændelsesanalyse

Moderne Linux-systemer, der kører systemd, samler alt logoutput centralt i journalen — et struktureret, binært loglager, der administreres af systemd-journald. I modsætning til almindelige tekstfiler i /var/log indeholder hver journalpost omfattende metadata: enhedsnavn, prioritetsniveau, PID, UID, tidsstempel med mere.

I automatiserede scripts til indledende hændelsesanalyse lader disse metadata dig:

  • Filtrere logge til én enkelt tjeneste uden kæder af grep-kommandoer
  • Afgrænse forespørgsler til præcise tidsvinduer (de seneste 15 minutter, siden en udrulning)
  • Udsende kun kritiske meddelelser og fejlmeddelelser, mens støj ignoreres
  • Sende struktureret output direkte ind i alarmpipelines

Værktøjet, der giver adgang til alt dette, er journalctl. I denne lektion lærer du at styre det programmatisk i Bash-scripts.

Grundlæggende journalctl-kald

Den enkleste form af journalctl dumper hele journalen. I scripts ønsker du næsten aldrig dette — tilføj altid mindst ét filter. Her er de mest almindelige flag, som du kan kæde sammen:

  • -u <unit> — filtrer efter systemd-enhed (f.eks. nginx.service)
  • -p <priority> — filtrer efter syslog-prioritet (0=emerg … 7=debug)
  • --since / --until — tidsvindue
  • -n <N> — de seneste N linjer
  • --no-pager — deaktiver interaktiv sidevisning (vigtigt i scripts)
  • -o <format> — outputformat (short, json, cat osv.)

Angiv altid --no-pager i ikke-interaktive scripts, så journalctl ikke forsøger at starte less og går i stå.

#!/usr/bin/env bash
# Print the last 20 lines of the nginx service journal
journalctl --no-pager -u nginx.service -n 20

Filtrering efter systemd-enhed

Flaget -u accepterer ethvert gyldigt enhedsnavn. Du kan angive det flere gange for at kombinere enheder, hvilket er nyttigt, når en enkelt applikation strækker sig over flere tjenester (f.eks. en API-tjeneste og dens ledsagende databasetjeneste).

Enhedsnavne følger mønsteret <name>.service, <name>.socket, <name>.timer osv. Jokertegn understøttes: -u 'myapp*' matcher myapp-api.service, myapp-worker.service og så videre.

I et script til indledende hændelsesanalyse modtager du typisk enhedsnavnet som et argument, så filteret bliver dynamisk.

#!/usr/bin/env bash
# Usage: ./unit_logs.sh nginx.service
UNIT="${1:?Usage: $0 <unit>}"

echo "=== Journal for ${UNIT} (last 50 lines) ==="
journalctl --no-pager -u "${UNIT}" -n 50

# Combine two related units
echo "=== Combined: api + worker ==="
journalctl --no-pager -u myapp-api.service -u myapp-worker.service -n 30

Prioritetsniveauer og flaget -p

Flaget -p svarer til standardprioritetsniveauerne i syslog:

  • 0 — emerg
  • 1 — alert
  • 2 — crit
  • 3 — err
  • 4 — warning
  • 5 — notice
  • 6 — info
  • 7 — debug

Du kan angive ét niveau (-p err) for kun at se dette niveau eller et interval (-p emerg..err) for at medtage alt fra nødsituationer til fejl — det mest almindelige valg til automatiseret alarmering.

Navngivne aliaser (err, warning, crit) accepteres sammen med numeriske værdier.

#!/usr/bin/env bash
# Extract only error-level and above entries for sshd
journalctl --no-pager \
  -u sshd.service \
  -p emerg..err \
  --since "1 hour ago"

# Exit non-zero if any errors were found (useful in CI health checks)
ERROR_COUNT=$(journalctl --no-pager -u sshd.service -p emerg..err \
  --since "1 hour ago" --output=cat | wc -l)

if [[ "${ERROR_COUNT}" -gt 0 ]]; then
  echo "[ALERT] ${ERROR_COUNT} error(s) detected in sshd" >&2
  exit 1
fi

Filtrering efter tidsinterval med --since og --until

Tidsfiltre er grundlaget for forespørgsler på hændelsesintervaller. journalctl accepterer fleksible, menneskeligt læsbare tidsstempler:

  • Relative: "10 minutes ago", "2 hours ago", "yesterday"
  • Absolutte: "2026-06-11 14:00:00"
  • Særlige nøgleord: today, yesterday, -1h (kort notation)

I deployscripts er et almindeligt mønster at gemme tidsstemplet lige før en deploy og derefter forespørge i journalen fra dette tidspunkt for at finde regressioner, som versionen har introduceret.

#!/usr/bin/env bash
# Record deploy start time, then check logs afterwards
DEPLOY_START=$(date +"%Y-%m-%d %H:%M:%S")

echo "Deploying at ${DEPLOY_START}..."
# ... your deploy steps here ...
sleep 2  # simulate deploy

echo "=== Journal since deploy start ==="
journalctl --no-pager \
  -u myapp.service \
  --since "${DEPLOY_START}" \
  -p emerg..warning

Struktureret output i JSON-format

Til maskinlæsbare datapipelines skal du angive -o json (ét JSON-objekt pr. linje, NDJSON) eller -o json-pretty (formatteret). Hvert objekt indeholder alle journalfelter:

  • MESSAGE — logteksten
  • PRIORITY — numerisk prioritet (0–7)
  • _SYSTEMD_UNIT — den enhed, som posten stammer fra
  • __REALTIME_TIMESTAMP — mikrosekunder siden epoken
  • _PID, _UID, _HOSTNAME — procesmetadata

Du kan pipe denne NDJSON-strøm ind i jq for at udtrække, filtrere eller omformatere felter til efterfølgende alarmeringssystemer som PagerDuty, Slack-webhooks eller SIEM-indlæsere.

#!/usr/bin/env bash
# Extract error messages as a clean list for a Slack notification
MESSAGES=$(journalctl --no-pager \
  -u nginx.service \
  -p emerg..err \
  --since "30 minutes ago" \
  -o json \
  | jq -r '.MESSAGE' \
  | sort -u)

if [[ -n "${MESSAGES}" ]]; then
  echo "Errors detected:"
  echo "${MESSAGES}"
fi

Følg journalen i realtid

Flaget -f får journalctl til at følge journalen live — på samme måde som tail -f på en logfil. Kombineret med filtre for enhed og prioritet bliver dette en målrettet realtidsovervågning.

I scriptbaserede datapipelines er det mere nyttige mønster cursorbaseret polling: Gem den aktuelle journalcursor, og angiv derefter --after-cursor=<cursor> ved hver polling for kun at læse nye poster siden den seneste kontrol. Det forhindrer, at gamle linjer behandles igen.

Hent den nyeste cursor med --show-cursor -n 0, og fortolk linjen -- cursor: fra outputtet.

#!/usr/bin/env bash
# Cursor-based polling: read only new journal entries each run
CURSOR_FILE="/tmp/triage_cursor"

if [[ -f "${CURSOR_FILE}" ]]; then
  CURSOR=$(cat "${CURSOR_FILE}")
  NEW_ENTRIES=$(journalctl --no-pager \
    -u myapp.service \
    -p emerg..err \
    --after-cursor="${CURSOR}" \
    -o json)
else
  # First run: look back 5 minutes
  NEW_ENTRIES=$(journalctl --no-pager \
    -u myapp.service \
    -p emerg..err \
    --since "5 minutes ago" \
    -o json)
fi

# Save updated cursor for next poll
journalctl --no-pager -n 0 --show-cursor 2>&1 \
  | grep '^-- cursor:' \
  | sed 's/-- cursor: //' \
  > "${CURSOR_FILE}"

echo "${NEW_ENTRIES}" | jq -r '.MESSAGE // empty'

Forespørgsler begrænset til en opstart med -b

Flaget -b begrænser en forespørgsel til en bestemt opstartssession. Det er afgørende efter et nedbrud eller en uventet genstart, hvis du vil hente logfiler fra den forrige opstart i stedet for den aktuelle.

  • -b 0 — aktuel opstart (standard)
  • -b -1 — forrige opstart
  • -b -2 — opstarten før den forrige
  • --list-boots — vis alle registrerede opstartssessioner med tidsstempler

Efterbehandlingsscripts dumper ofte kritiske logfiler fra den forrige opstart (-b -1) for at diagnosticere, hvorfor systemet brød sammen, eller hvorfor en tjeneste mislykkedes under opstart.

#!/usr/bin/env bash
# Post-mortem: collect critical logs from the previous boot
echo "=== Previous boot sessions ==="
journalctl --list-boots

echo ""
echo "=== Critical entries from previous boot ==="
journalctl --no-pager \
  -b -1 \
  -p emerg..crit \
  -o short-iso

Grep i journalctl sammenlignet med indbyggede match

Du kan angive et råt grep-mønster efter alle flag, men journalctl understøtter også indbyggede feltmatch med syntaksen FIELD=value. Indbyggede match evalueres mod strukturerede metadata — langt hurtigere end efterbehandling af tekst med grep.

Almindelige nyttige match:

  • _PID=1234 — logposter fra en bestemt proces
  • _COMM=python3 — logposter fra enhver proces med navnet python3
  • SYSLOG_IDENTIFIER=myapp — logposter med en brugerdefineret identifikator

Flere argumenter af typen FIELD=value kombineres med OG; et + mellem dem opretter et ELLER. Brug -g <regex> til fuldtekstsøgning med grep, når strukturerede metadata ikke er tilstrækkelige.

#!/usr/bin/env bash
# Native field match: errors from the postgres process only
journalctl --no-pager \
  _COMM=postgres \
  -p emerg..err \
  --since "1 hour ago"

# Full-text grep for a specific error string
journalctl --no-pager \
  -u postgresql.service \
  --since "1 hour ago" \
  -g "FATAL|PANIC" \
  --output=cat

Opbygning af en genbrugelig triagefunktion

Når du har lært de enkelte flag, kan du kombinere dem i en genbrugelig Bash-funktion, som holder dine triagescripts rene og ensartede. En veldesignet funktion bør:

  • Acceptere enhed, prioritetsinterval og tidsinterval som parametre
  • Bruge sikre værdier med lavt støjniveau som standard, når argumenter udelades
  • Returnere en afslutningskode forskellig fra nul, når der findes fejl (integreres med CI-datapipelines)
  • Skrive resultater til både stdout og en tidsstemplet logfil til revisionsspor
#!/usr/bin/env bash
# triage.sh — reusable journal triage function

triage_unit() {
  local unit="${1:?unit required}"
  local priority="${2:-emerg..err}"
  local since="${3:-1 hour ago}"
  local logfile="/tmp/triage_${unit//[^a-zA-Z0-9]/_}_$(date +%s).log"

  echo "[$(date -Iseconds)] Triaging ${unit} | prio=${priority} | since='${since}'" | tee "${logfile}"

  journalctl --no-pager \
    -u "${unit}" \
    -p "${priority}" \
    --since "${since}" \
    -o short-iso \
    | tee -a "${logfile}"

  local count
  count=$(wc -l < "${logfile}")
  # Subtract 1 for the header line
  (( count-- ))

  if [[ "${count}" -gt 0 ]]; then
    echo "[ALERT] ${count} line(s) logged to ${logfile}" >&2
    return 1
  fi
  return 0
}

# Example: triage nginx errors in the last 30 minutes
triage_unit nginx.service "emerg..err" "30 minutes ago"

Automatiseret script til hændelsestriage

Det følgende komplette script samler alle begreberne i et praktisk, automatiseret triageværktøj. Det læser en liste over kritiske tjenester, forespørger i journalen for hver af dem over et konfigurerbart tilbageblik, samler resultaterne og afslutter med en fejlkode, hvis der blev fundet fejl — hvilket gør det velegnet som cronjob eller trin i et CI-sundhedstjek.

#!/usr/bin/env bash
# incident_triage.sh — automated multi-service journal triage
set -euo pipefail

LOOKBACK="${1:-15 minutes ago}"
PRIORITY="emerg..err"
SERVICES=(nginx.service postgresql.service myapp-api.service myapp-worker.service)
REPORT="/tmp/incident_report_$(date +%Y%m%d_%H%M%S).txt"
FAILED=0

{
  echo "Incident Triage Report"
  echo "Generated : $(date -Iseconds)"
  echo "Lookback  : ${LOOKBACK}"
  echo "Priority  : ${PRIORITY}"
  echo "-----------------------------------"
} > "${REPORT}"

for svc in "${SERVICES[@]}"; do
  ENTRIES=$(journalctl --no-pager \
    -u "${svc}" \
    -p "${PRIORITY}" \
    --since "${LOOKBACK}" \
    --output=cat 2>/dev/null || true)

  COUNT=$(echo "${ENTRIES}" | grep -c . || true)

  if [[ "${COUNT}" -gt 0 ]]; then
    echo "[FAIL] ${svc}: ${COUNT} error(s)" | tee -a "${REPORT}"
    echo "${ENTRIES}" >> "${REPORT}"
    echo "-----------------------------------" >> "${REPORT}"
    FAILED=1
  else
    echo "[OK]   ${svc}"
  fi
done

echo ""
echo "Full report: ${REPORT}"
exit "${FAILED}"

Videnstjek: Filtrering efter prioritetsinterval

Du skriver et script, der kun skal alarmere vagthavende teknikere, når en tjeneste logger med fejlniveau eller værre (det vil sige fejl, kritisk, alarm eller nødsituation). Hvilken kombination af journalctl-flag medtager præcis dette interval?

Opsummering af lektionen: journalctl i scripts

I denne lektion har du lært, hvordan du programmatisk forespørger i systemd-journalen til automatiseret hændelsestriage:

  • Angiv altid --no-pager i scripts for at forhindre interaktiv blokering.
  • Filtrering efter enhed (-u) begrænser forespørgsler til én eller flere tjenester; jokertegn og flere -u-flag understøttes.
  • Prioritetsfiltrering (-p emerg..err) medtager kun de fejlniveauer, du har brug for — husk, at lavere tal angiver større alvor.
  • Tidsintervaller (--since / --until) begrænser logoutputtet til et deployinterval eller en tilbagebliksperiode ved hjælp af menneskeligt læsbare tidsstempler.
  • Begrænsning til opstart (-b -1) gør det muligt for efterbehandlingsscripts at læse logfiler fra en tidligere nedbrudt session.
  • JSON-output (-o json) og jq muliggør strukturerede datapipelines til alarmerings- eller SIEM-systemer.
  • Cursorbaseret polling med --after-cursor forhindrer, at gamle poster behandles igen ved gentagne kørsler.
  • Indbyggede feltmatch (_COMM=, SYSLOG_IDENTIFIER=) er hurtigere end at pipe til grep.

Hvis du kombinerer disse flag i en genbrugelig Bash-funktion, får du et triageværktøj i produktionskvalitet, som integreres problemfrit med cron, CI-datapipelines og alarmeringsarbejdsgange for vagthavende teknikere.

Gratis at komme i gang

Lær Intensiv DevOps-uddannelse med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
142
Lektioner
568

Ofte stillede spørgsmål

Er lektionen “Forespørgsler til journald med journalctl i scripts” gratis?

Ja — alle 3 lektioner i læringssporet Intensiv DevOps-uddannelse, inklusive “Forespørgsler til journald med journalctl i scripts”, kan læses gratis i deres fulde længde her på webstedet. Derefter låser CoddyKit PRO alle lektioner op samt interaktive øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Intensiv DevOps-uddannelse-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “Forespørgsler til journald med journalctl i scripts”?

Filtrér systemd-journalposter efter unit, prioritet og tidspunkt til automatiseret triage af hændelser. Du øver dig i Intensiv DevOps-uddannelse med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på Intensiv DevOps-uddannelse?

Der kræves ingen tidligere erfaring. Intensiv DevOps-uddannelse på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 3 af 4.

Hvor lang tid tager lektionen “Forespørgsler til journald med journalctl i scripts”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne Intensiv DevOps-uddannelse-lektion?

Ja. Alle Intensiv DevOps-uddannelse-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. Parsing af web- og applikationslogs i stor skala
  2. Logovervågning i realtid og streaming-alarmer
  3. Forespørgsler til journald med journalctl i scripts
  4. Beregning af metrikker og histogrammer fra logstreams
← Tilbage til Intensiv DevOps-uddannelse