Odpytywanie journald za pomocą journalctl w skryptach
Filtruj wpisy dziennika systemd według jednostki, priorytetu i czasu, aby automatyzować wstępną analizę incydentów.
Odpytywanie journald za pomocą journalctl w skryptach to bezpłatna lekcja Linux Command Line & Bash Scripting Mastery na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Linux Command Line & Bash Scripting Mastery, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Linux Command Line & Bash Scripting Mastery zawiera 4 lekcji w sumie.
Dlaczego journald jest przydatny podczas wstępnej analizy incydentów
Współczesne systemy Linux korzystające z systemd centralizują wszystkie dane dzienników w dzienniku — ustrukturyzowanym, binarnym magazynie dzienników zarządzanym przez systemd-journald. W przeciwieństwie do zwykłych plików tekstowych w /var/log każdy wpis dziennika zawiera rozbudowane metadane: nazwę jednostki, poziom priorytetu, PID, UID, znacznik czasu i inne informacje.
W automatycznych skryptach do wstępnej analizy incydentów metadane te pozwalają Państwu:
- Filtrować dzienniki do jednej usługi bez łańcuchów poleceń
grep - Ograniczać zapytania do dokładnych przedziałów czasu (ostatnie 15 minut, od wdrożenia)
- Wyświetlać wyłącznie komunikaty krytyczne i błędy, pomijając nieistotne dane
- Przekazywać ustrukturyzowane dane wyjściowe bezpośrednio do potoków alertów
Narzędziem udostępniającym wszystkie te funkcje jest journalctl. W tej lekcji nauczą się Państwo sterować nim programowo wewnątrz skryptów Bash.
Podstawowe wywołanie journalctl
Najprostsza forma polecenia journalctl wyświetla cały dziennik. W skryptach prawie nigdy nie jest to potrzebne — należy zawsze dodać co najmniej jeden filtr. Oto najczęściej łączone opcje:
-u <unit>— filtrowanie według jednostki systemd (np.nginx.service)-p <priority>— filtrowanie według priorytetu syslog (0=emerg … 7=debug)--since/--until— przedział czasu-n <N>— ostatnie N wierszy--no-pager— wyłączenie interaktywnego stronicowania (niezbędne w skryptach)-o <format>— format danych wyjściowych (short,json,catitd.)
W skryptach nieinteraktywnych należy zawsze przekazywać opcję --no-pager, aby journalctl nie próbowało uruchomić less i nie zawiesiło działania.
#!/usr/bin/env bash
# Print the last 20 lines of the nginx service journal
journalctl --no-pager -u nginx.service -n 20Filtrowanie według jednostki Systemd
Opcja -u przyjmuje dowolną prawidłową nazwę jednostki. Można podać ją wielokrotnie, aby połączyć jednostki, co jest przydatne, gdy jedna aplikacja obejmuje kilka usług (np. API i pomocniczą bazę danych).
Nazwy jednostek mają postać <name>.service, <name>.socket, <name>.timer itd. Obsługiwane są wzorce globalne: -u 'myapp*' pasuje do myapp-api.service, myapp-worker.service i innych podobnych nazw.
W skrypcie do wstępnej analizy incydentu nazwa jednostki jest zazwyczaj przekazywana jako argument, dzięki czemu filtr jest dynamiczny.
#!/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 30Poziomy priorytetów i flaga -p
Flaga -p odwzorowuje standardowe poziomy priorytetów syslog:
0— emerg1— alert2— crit3— err4— warning5— notice6— info7— debug
Mogą Państwo określić pojedynczy poziom (-p err), aby wyświetlić tylko wpisy z tego poziomu, albo zakres (-p emerg..err), aby przechwycić wszystko — od komunikatów awaryjnych po błędy. Jest to najczęstszy wybór w przypadku automatycznego generowania alertów.
Oprócz wartości liczbowych akceptowane są nazwane aliasy (err, warning, crit).
#!/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
fiFiltrowanie według przedziału czasu za pomocą --since i --until
Filtry czasowe są podstawą zapytań dotyczących okna incydentu. journalctl akceptuje elastyczne znaczniki czasu w formacie czytelnym dla człowieka:
- Względne:
"10 minutes ago","2 hours ago","yesterday" - Bezwzględne:
"2026-06-11 14:00:00" - Słowa kluczowe specjalne:
today,yesterday,-1h(skrót)
W skryptach wdrożeniowych często zapisuje się znacznik czasu bezpośrednio przed wdrożeniem, a następnie odpyta dziennik od tego momentu, aby wykryć regresje wprowadzone przez wydanie.
#!/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..warningUstrukturyzowane dane wyjściowe w formacie JSON
W przypadku potoków przetwarzających dane maszynowo należy przekazać -o json (jeden obiekt JSON w wierszu, NDJSON) albo -o json-pretty (formatowanie). Każdy obiekt zawiera wszystkie pola dziennika:
MESSAGE— treść wpisu dziennikaPRIORITY— priorytet liczbowy (0–7)_SYSTEMD_UNIT— jednostka źródłowa__REALTIME_TIMESTAMP— liczba mikrosekund od początku epoki_PID,_UID,_HOSTNAME— metadane procesu
Mogą Państwo przekazać ten strumień NDJSON do jq, aby wyodrębniać, filtrować lub ponownie formatować pola na potrzeby dalszych systemów alertów, takich jak PagerDuty, webhooki Slacka lub odbiorniki 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Śledzenie dziennika w czasie rzeczywistym
Flaga -f sprawia, że journalctl śledzi dziennik na żywo — podobnie jak tail -f w przypadku pliku dziennika. W połączeniu z filtrami jednostki i priorytetu tworzy to ukierunkowany monitor działający w czasie rzeczywistym.
W potokach skryptowych bardziej użyteczny jest wzorzec odpytywania opartego na kursorze: należy zapisać bieżący kursor dziennika, a następnie przy każdym odpytywaniu przekazać --after-cursor=<cursor>, aby odczytać tylko nowe wpisy od ostatniego sprawdzenia. Pozwala to uniknąć ponownego przetwarzania starych wierszy.
Najnowszy kursor można pobrać za pomocą --show-cursor -n 0, a następnie przeanalizować wiersz -- cursor: z danych wyjściowych.
#!/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'Zapytania ograniczone do uruchomienia systemu za pomocą -b
Flaga -b ogranicza zapytanie do określonej sesji uruchomienia systemu. Jest to niezbędne po awarii lub nieoczekiwanym ponownym uruchomieniu, aby pobrać dzienniki z poprzedniego uruchomienia zamiast z bieżącego.
-b 0— bieżące uruchomienie (domyślne)-b -1— poprzednie uruchomienie-b -2— uruchomienie sprzed dwóch sesji--list-boots— wyświetla wszystkie zarejestrowane sesje uruchomienia wraz ze znacznikami czasu
Skrypty wykonywane po awarii często zrzucają krytyczne dzienniki z poprzedniego uruchomienia (-b -1), aby ustalić, dlaczego system uległ awarii lub dlaczego usługa nie uruchomiła się podczas startu.
#!/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-isoWyszukiwanie za pomocą grep w journalctl a dopasowania natywne
Po wszystkich flagach można przekazać surowy wzorzec grep, ale journalctl obsługuje również natywne dopasowania pól z użyciem składni FIELD=value. Natywne dopasowania są sprawdzane względem ustrukturyzowanych metadanych, dzięki czemu działają znacznie szybciej niż późniejsze przetwarzanie tekstu za pomocą grep.
Przydatne typowe dopasowania:
_PID=1234— dzienniki konkretnego procesu_COMM=python3— dzienniki dowolnego procesu o nazwiepython3SYSLOG_IDENTIFIER=myapp— dzienniki oznaczone niestandardowym identyfikatorem
Wiele argumentów FIELD=value jest łączonych operatorem AND, a znak + między nimi tworzy operację OR. Należy użyć -g <regex>, aby wykonać wyszukiwanie pełnotekstowe za pomocą grep, gdy ustrukturyzowane metadane są niewystarczające.
#!/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=catTworzenie wielokrotnego użytku skryptu funkcji triage
Po opanowaniu poszczególnych flag mogą Państwo połączyć je w wielokrotnego użytku funkcję Bash, która pozwoli zachować przejrzystość i spójność skryptów triage. Dobrze zaprojektowana funkcja powinna:
- przyjmować jednostkę, zakres priorytetów i przedział czasu jako parametry
- przyjmować bezpieczne wartości o małej liczbie szumów, gdy argumenty zostaną pominięte
- zwracać niezerowy kod wyjścia po znalezieniu błędów (co umożliwia integrację z potokami CI)
- zapisywać wyniki zarówno na stdout, jak i w opatrzonym znacznikiem czasu pliku dziennika na potrzeby ścieżki audytowej
#!/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"Skrypt automatycznego triage incydentów
Poniższy kompletny skrypt łączy wszystkie omówione zagadnienia w praktyczne, automatyczne narzędzie triage. Odczytuje listę krytycznych usług, odpyta dziennik dla każdej z nich w konfigurowalnym przedziale wstecz, agreguje wyniki i kończy działanie kodem błędu, jeśli wykryto jakiekolwiek błędy — dzięki temu nadaje się do użycia jako zadanie cron lub krok kontroli kondycji w 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}"Sprawdzenie wiedzy: filtrowanie zakresu priorytetów
Tworzą Państwo skrypt, który ma wysyłać alerty do inżynierów dyżurnych tylko wtedy, gdy usługa zapisze komunikaty o ważności error lub wyższej (czyli error, critical, alert lub emergency). Która kombinacja flag journalctl poprawnie obejmuje dokładnie ten zakres?
Podsumowanie lekcji: journalctl w skryptach
W tej lekcji nauczyli się Państwo programowo odpytywać dziennik systemd na potrzeby automatycznego triage incydentów:
- W skryptach należy zawsze przekazywać
--no-pager, aby zapobiec interaktywnemu blokowaniu. - Filtrowanie jednostek (
-u) ogranicza zapytania do jednej lub większej liczby usług; obsługiwane są wzorce glob i wiele flag-u. - Filtrowanie priorytetów (
-p emerg..err) uwzględnia tylko interesujące Państwa poziomy ważności — należy pamiętać, że niższe liczby oznaczają wyższą ważność. - Przedziały czasu (
--since/--until) ograniczają dane wyjściowe dziennika do okna wdrożenia lub okresu wstecz na podstawie znaczników czasu czytelnych dla człowieka. - Ograniczenie do uruchomienia (
-b -1) pozwala skryptom wykonywanym po awarii odczytywać dzienniki z poprzedniej sesji zakończonej awarią. - Dane wyjściowe JSON (
-o json) ijqumożliwiają tworzenie ustrukturyzowanych potoków zasilających systemy alertów lub SIEM. - Odpytywanie oparte na kursorze z użyciem
--after-cursorzapobiega ponownemu przetwarzaniu starych wpisów przy kolejnych uruchomieniach. - Natywne dopasowania pól (
_COMM=,SYSLOG_IDENTIFIER=) są szybsze niż przekazywanie danych potokiem dogrep.
Połączenie tych flag w wielokrotnego użytku funkcji Bash daje gotowe do użycia produkcyjnie narzędzie triage, które łatwo integruje się z cronem, potokami CI i procesami wysyłania alertów do inżynierów dyżurnych.
Często zadawane pytania
Czy lekcja „Odpytywanie journald za pomocą journalctl w skryptach” jest bezpłatna?
Tak — pełny tekst „Odpytywanie journald za pomocą journalctl w skryptach” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Linux Command Line & Bash Scripting Mastery, przejdź na CoddyKit PRO. Kurs Linux Command Line & Bash Scripting Mastery zawiera 4 lekcji w sumie.
Co nauczysz się w „Odpytywanie journald za pomocą journalctl w skryptach”?
Filtruj wpisy dziennika systemd według jednostki, priorytetu i czasu, aby automatyzować wstępną analizę incydentów. Ćwiczysz Linux Command Line & Bash Scripting Mastery z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Linux Command Line & Bash Scripting Mastery?
Nie wymagamy żadnego doświadczenia. Linux Command Line & Bash Scripting Mastery w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.
Ile czasu zajmuje lekcja „Odpytywanie journald za pomocą journalctl w skryptach”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Linux Command Line & Bash Scripting Mastery?
Tak. Każda lekcja Linux Command Line & Bash Scripting Mastery zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Parsowanie logów internetowych i aplikacyjnych na dużą skalę
- Śledzenie logów w czasie rzeczywistym i alerty strumieniowe
- Odpytywanie journald za pomocą journalctl w skryptach
- Obliczanie metryk i histogramów ze strumieni logów