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 DevOps Bootcamp 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 DevOps Bootcamp, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso DevOps Bootcamp 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 esempionginx.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,catecc.)
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 20Filtrare 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 30Livelli di priorità e flag -p
Il flag -p corrisponde ai livelli di priorità standard di syslog:
0— emerg1— alert2— crit3— err4— warning5— notice6— info7— 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
fiFiltraggio 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..warningOutput 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 logPRIORITY— 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}"
fiSeguire 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-isoRicerca 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 denominatopython3SYSLOG_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=catCreazione 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-pagernegli 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) ejqconsentono di creare pipeline strutturate che alimentano sistemi di alerting o SIEM. - Il polling basato sul cursore con
--after-cursorevita di elaborare nuovamente le voci precedenti nelle esecuzioni ripetute. - Le corrispondenze native dei campi (
_COMM=,SYSLOG_IDENTIFIER=) sono più veloci dell'invio dell'output agrep.
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 DevOps Bootcamp, passa a CoddyKit PRO. Il corso DevOps Bootcamp 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 DevOps Bootcamp 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 DevOps Bootcamp?
Non è richiesta alcuna esperienza precedente. DevOps Bootcamp 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 DevOps Bootcamp?
Sì. Ogni lezione DevOps Bootcamp 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
- Analizzare log web e applicativi su larga scala
- Seguire i log in tempo reale e generare avvisi in streaming
- Interrogare journald negli script con journalctl
- Calcolare metriche e istogrammi dai flussi di log