0Pricing
Linux Command Line & Bash Scripting Mastery · Lezione

Interrogare journald negli script con journalctl

Filtri le voci del journal di systemd per unità, priorità e intervallo temporale, così da automatizzare il triage degli incidenti.

Interrogare journald negli script con journalctl è una lezione Linux Command Line & Bash Scripting Mastery gratuita su CoddyKit. Questa è la lezione 3 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Linux Command Line & Bash Scripting Mastery, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Linux Command Line & Bash Scripting Mastery include 4 lezioni in totale.

Perché usare journald per il triage degli incidenti

I moderni sistemi Linux che eseguono systemd centralizzano tutto l'output dei log nel journal, un archivio di log strutturato e binario gestito da systemd-journald. A differenza dei semplici file di testo in /var/log, ogni voce del journal contiene metadati dettagliati: nome dell'unità, livello di priorità, PID, UID, timestamp e altro.

Negli script automatizzati di triage degli incidenti, questi metadati consentono di:

  • Filtrare i log di un singolo servizio senza concatenare comandi grep
  • Limitare le query a finestre temporali precise (gli ultimi 15 minuti, dal momento di un deploy)
  • Produrre solo i messaggi critici o di errore, ignorando il rumore
  • Inviare output strutturato direttamente alle pipeline di avvisi

Lo strumento che espone tutte queste funzionalità è journalctl. In questa lezione imparerà a utilizzarlo programmaticamente all'interno degli script Bash.

Invocazione di base di journalctl

La forma più semplice di journalctl scarica l'intero journal. Negli script, quasi mai è ciò che si desidera: aggiunga sempre almeno un filtro. Ecco le opzioni più comuni da concatenare:

  • -u <unit> — filtra per unità systemd (ad esempio nginx.service)
  • -p <priority> — filtra per priorità syslog (0=emerg … 7=debug)
  • --since / --until — finestra temporale
  • -n <N> — ultime N righe
  • --no-pager — disabilita la paginazione interattiva (essenziale negli script)
  • -o <format> — formato dell'output (short, json, cat ecc.)

Passi sempre --no-pager negli script non interattivi, affinché journalctl non tenti di avviare less bloccandosi.

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

Filtrare per unità Systemd

L'opzione -u accetta qualsiasi nome di unità valido. Può specificarla più volte per combinare le unità, una possibilità utile quando una singola applicazione si estende su più servizi (ad esempio un'API e il relativo sidecar del database).

I nomi delle unità seguono il modello <name>.service, <name>.socket, <name>.timer ecc. È supportato il globbing: -u 'myapp*' corrisponde a myapp-api.service, myapp-worker.service e così via.

In uno script di triage, in genere si riceve il nome dell'unità come argomento, rendendo dinamico il filtro.

#!/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

Livelli di priorità e flag -p

Il flag -p corrisponde ai livelli di priorità standard di syslog:

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

È possibile specificare un singolo livello (-p err) per visualizzare solo quel livello, oppure un intervallo (-p emerg..err) per acquisire tutto, dalle emergenze agli errori: è la scelta più comune per gli avvisi automatici.

Gli alias denominati (err, warning, crit) sono accettati insieme ai valori numerici.

#!/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

Filtraggio per intervallo temporale con --since e --until

I filtri temporali sono alla base delle query relative alla finestra di un incidente. journalctl accetta timestamp flessibili e leggibili:

  • Relativi: "10 minutes ago", "2 hours ago", "yesterday"
  • Assoluti: "2026-06-11 14:00:00"
  • Parole chiave speciali: today, yesterday, -1h (forma abbreviata)

Negli script di deploy, un modello comune consiste nel catturare il timestamp subito prima di un deploy e poi interrogare il journal a partire da quel momento, per rilevare eventuali regressioni introdotte dal rilascio.

#!/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

Output strutturato in formato JSON

Per le pipeline leggibili dalle macchine, passare -o json (un oggetto JSON per riga, NDJSON) oppure -o json-pretty (formattato). Ogni oggetto contiene tutti i campi del journal:

  • MESSAGE — il testo del log
  • PRIORITY — priorità numerica (0–7)
  • _SYSTEMD_UNIT — unità di origine
  • __REALTIME_TIMESTAMP — microsecondi dall'epoca Unix
  • _PID, _UID, _HOSTNAME — metadati del processo

È possibile inviare questo flusso NDJSON a jq per estrarre, filtrare o riformattare i campi destinati ai sistemi di alerting a valle, come PagerDuty, i webhook di Slack o gli ingestori SIEM.

#!/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

Seguire il journal in tempo reale

Il flag -f fa sì che journalctl segua il journal in tempo reale, in modo analogo a tail -f su un file di log. In combinazione con i filtri per unità e priorità, diventa un monitor mirato in tempo reale.

Nelle pipeline con script, il modello più utile è il polling basato sul cursore: salvare il cursore corrente del journal e, a ogni interrogazione, passare --after-cursor=<cursor> per leggere solo le nuove voci dall'ultimo controllo. In questo modo si evita di elaborare nuovamente le righe già lette.

Recuperare il cursore più recente con --show-cursor -n 0 e analizzare la riga -- cursor: nell'output.

#!/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'

Query limitate all'avvio con -b

Il flag -b limita una query a una specifica sessione di avvio. È essenziale dopo un arresto anomalo o un riavvio imprevisto, per recuperare i log dell'avvio precedente invece di quelli corrente.

  • -b 0 — avvio corrente (predefinito)
  • -b -1 — avvio precedente
  • -b -2 — due avvii precedenti
  • --list-boots — mostra tutte le sessioni di avvio registrate con i timestamp

Gli script post-mortem scaricano comunemente i log critici dell'avvio precedente (-b -1) per diagnosticare la causa dell'arresto anomalo del sistema o del mancato avvio di un servizio.

#!/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

Ricerca con grep in journalctl e corrispondenze native

È possibile passare un pattern grezzo di grep dopo tutti i flag, ma journalctl supporta anche le corrispondenze native dei campi usando la sintassi FIELD=value. Le corrispondenze native vengono valutate sui metadati strutturati e sono molto più veloci dell'elaborazione successiva del testo con grep.

Corrispondenze utili comuni:

  • _PID=1234 — log di un processo specifico
  • _COMM=python3 — log di qualsiasi processo denominato python3
  • SYSLOG_IDENTIFIER=myapp — log contrassegnati con un identificatore personalizzato

Più argomenti FIELD=value vengono combinati con AND; un + tra di essi crea un OR. Usare -g <regex> per la ricerca full-text con grep quando i metadati strutturati non sono sufficienti.

#!/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

Creazione di una funzione riutilizzabile per il triage

Una volta acquisita familiarità con i singoli flag, combinarli in una funzione Bash riutilizzabile mantiene gli script di triage ordinati e coerenti. Una funzione ben progettata dovrebbe:

  • Accettare come parametri l'unità, l'intervallo di priorità e la finestra temporale
  • Usare valori predefiniti sicuri e con poco rumore quando gli argomenti vengono omessi
  • Restituire un codice di uscita diverso da zero quando vengono trovati errori (per integrarsi con le pipeline CI)
  • Scrivere i risultati sia su stdout sia in un file di log con timestamp, per garantire una traccia di audit
#!/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"

Script automatizzato per il triage degli incidenti

Lo script completo seguente riunisce tutti i concetti in uno strumento pratico per il triage automatizzato. Legge un elenco di servizi critici, interroga il journal per ciascuno nell'intervallo configurabile precedente, aggrega i risultati e termina con un codice di errore se vengono rilevati errori, rendendolo adatto come cron job o passaggio di controllo dello stato in una pipeline CI.

#!/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}"

Verifica delle conoscenze: filtraggio per intervallo di priorità

Sta scrivendo uno script che deve avvisare gli ingegneri reperibili solo quando un servizio registra messaggi con gravità di errore o superiore (ovvero error, critical, alert o emergency). Quale combinazione di flag di journalctl acquisisce esattamente questo intervallo?

Riepilogo della lezione: journalctl negli script

In questa lezione ha imparato a interrogare programmaticamente il journal di systemd per il triage automatico degli incidenti:

  • Passi sempre --no-pager negli script per evitare blocchi interattivi.
  • Il filtraggio per unità (-u) limita le query a uno o più servizi; sono supportati i glob e più flag -u.
  • Il filtraggio per priorità (-p emerg..err) acquisisce solo i livelli di gravità necessari: ricordi che i numeri più bassi indicano una gravità maggiore.
  • Le finestre temporali (--since / --until) limitano l'output dei log a una finestra di deploy o a un periodo precedente, usando timestamp leggibili.
  • La limitazione all'avvio (-b -1) consente agli script post-mortem di leggere i log di una sessione precedente terminata con un arresto anomalo.
  • L'output JSON (-o json) e jq consentono di creare pipeline strutturate che alimentano sistemi di alerting o SIEM.
  • Il polling basato sul cursore con --after-cursor evita di elaborare nuovamente le voci precedenti nelle esecuzioni ripetute.
  • Le corrispondenze native dei campi (_COMM=, SYSLOG_IDENTIFIER=) sono più veloci dell'invio dell'output a grep.

Combinare questi flag in una funzione Bash riutilizzabile consente di ottenere uno strumento di triage di livello produttivo, facilmente integrabile con cron, le pipeline CI e i flussi di lavoro per gli avvisi agli ingegneri reperibili.

Domande Frequenti

La lezione «Interrogare journald negli script con journalctl» è gratuita?

Sì — il testo completo di «Interrogare journald negli script con journalctl» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Linux Command Line & Bash Scripting Mastery, passa a CoddyKit PRO. Il corso Linux Command Line & Bash Scripting Mastery include 4 lezioni in totale.

Cosa imparerò in «Interrogare journald negli script con journalctl»?

Filtri le voci del journal di systemd per unità, priorità e intervallo temporale, così da automatizzare il triage degli incidenti. Eserciti Linux Command Line & Bash Scripting Mastery con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Linux Command Line & Bash Scripting Mastery?

Non è richiesta alcuna esperienza precedente. Linux Command Line & Bash Scripting Mastery su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 4.

Quanto tempo richiede la lezione «Interrogare journald negli script con journalctl»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Linux Command Line & Bash Scripting Mastery?

Sì. Ogni lezione Linux Command Line & Bash Scripting Mastery include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Analizzare log web e applicativi su larga scala
  2. Seguire i log in tempo reale e generare avvisi in streaming
  3. Interrogare journald negli script con journalctl
  4. Calcolare metriche e istogrammi dai flussi di log
← Torna a Linux Command Line & Bash Scripting Mastery