0Pricing
DevOps Bootcamp · Lekcja

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 DevOps Bootcamp 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 DevOps Bootcamp, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs DevOps Bootcamp 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, cat itd.)

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 20

Filtrowanie 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 30

Poziomy priorytetów i flaga -p

Flaga -p odwzorowuje standardowe poziomy priorytetów syslog:

  • 0 — emerg
  • 1 — alert
  • 2 — crit
  • 3 — err
  • 4 — warning
  • 5 — notice
  • 6 — info
  • 7 — 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
fi

Filtrowanie 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..warning

Ustrukturyzowane 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 dziennika
  • PRIORITY — 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-iso

Wyszukiwanie 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 nazwie python3
  • SYSLOG_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=cat

Tworzenie 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) i jq umożliwiają tworzenie ustrukturyzowanych potoków zasilających systemy alertów lub SIEM.
  • Odpytywanie oparte na kursorze z użyciem --after-cursor zapobiega ponownemu przetwarzaniu starych wpisów przy kolejnych uruchomieniach.
  • Natywne dopasowania pól (_COMM=, SYSLOG_IDENTIFIER=) są szybsze niż przekazywanie danych potokiem do grep.

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 DevOps Bootcamp, przejdź na CoddyKit PRO. Kurs DevOps Bootcamp 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 DevOps Bootcamp 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ąć DevOps Bootcamp?

Nie wymagamy żadnego doświadczenia. DevOps Bootcamp 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 DevOps Bootcamp?

Tak. Każda lekcja DevOps Bootcamp 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

  1. Parsowanie logów internetowych i aplikacyjnych na dużą skalę
  2. Śledzenie logów w czasie rzeczywistym i alerty strumieniowe
  3. Odpytywanie journald za pomocą journalctl w skryptach
  4. Obliczanie metryk i histogramów ze strumieni logów
← Powrót do DevOps Bootcamp