Przejdź do treści

Logowanie do journald z poziomu Pythona

Tworząc narzędzia systemowe, daemony lub usługi działające na systemach opartych o systemd, warto logować zdarzenia bezpośrednio do journald. Dzięki temu logi trafiają do centralnego dziennika systemowego.

W tym artykule pokażę, jak logować do journald w Pythonie - zarówno przy użyciu modułu systemd, jak i standardowej biblioteki logging z obsługą journald.


Instalacja modułu systemd-python

Aby korzystać z bezpośredniego API journald, zainstaluj bibliotekę:

pip install systemd-python

Metoda 1: systemd.journal.send()

Najprostszy sposób logowania. Przykład:

from systemd import journal

journal.send("Something happened",
             SYSLOG_IDENTIFIER="my_app",
             PRIORITY=5)

Parametry:

  • MESSAGE - pierwszy argument funkcji, treść loga
  • SYSLOG_IDENTIFIER - identyfikator źródła logu (np. nazwa aplikacji lub unit file)
  • PRIORITY - poziom ważności (cyfra od 0 do 7)

Poziomy PRIORITY:

Liczba Nazwa Opis
0 emerg Krytyczny - system nie działa
1 alert Wymaga natychmiastowej reakcji
2 crit Krytyczny błąd
3 err Błąd
4 warning Ostrzeżenie
5 notice Istotna informacja
6 info Informacyjny
7 debug Debugowanie

Uwaga: PRIORITY powinno być liczbą, np. PRIORITY=3, a nie tekstem typu "err". Podanie stringa może nie zadziałać.


Odczyt logów w journalctl 🔍

Przykład logowania:

journal.send("Something went wrong",
             SYSLOG_IDENTIFIER="my_app",
             PRIORITY=3)

Sprawdzenie logów:

journalctl -t my_app

Z filtrowaniem po poziomie:

journalctl -t my_app -p err

Wyświetlenie pełnych danych (w tym PRIORITY):

journalctl -t my_app -o verbose

Metoda 2: standardowy logging z JournalHandler

W większych aplikacjach Pythonowych zaleca się logowanie przez wbudowany moduł logging z wykorzystaniem handlera JournalHandler. Taki sposób:

  • umożliwia centralne zarządzanie logowaniem w całej aplikacji,
  • pozwala elastycznie dodawać różne backendy logujące (do pliku, stdout, journald, itp.),
  • jest zgodny z frameworkami (Django, Flask, Celery, FastAPI itp.),
  • daje możliwość konfiguracji zewnętrznej (np. przez plik logging.conf lub YAML).

Przykład użycia:

import logging
from systemd.journal import JournalHandler

logger = logging.getLogger("my_app")
logger.addHandler(JournalHandler())
logger.setLevel(logging.DEBUG)

logger.debug("App debug")
logger.info("Info")
logger.warning("Warning!")
logger.error("Error occurred")
logger.critical("Critical failure")
  • Domyślnie SYSLOG_IDENTIFIER w journald to nazwa loggera (my_app).
  • W journalctl możesz odczytać te logi za pomocą:
journalctl -t my_app

Poziomy logowania 🔎

JournalHandler automatycznie mapuje poziomy logging na poziomy syslog (PRIORITY):

logging level journald PRIORITY Nazwa syslog
DEBUG 7 debug
INFO 6 info
WARNING 4 warning
ERROR 3 err
CRITICAL 2 crit

🛑 Nie ma wsparcia dla PRIORITY=1 (alert) ani 0 (emerg). Jeśli potrzebujesz tych poziomów, skorzystaj z journal.send().


Dlaczego warto używać logging + JournalHandler w większych aplikacjach?

  • Centralizacja logiki logowania - konfigurujesz raz, działa wszędzie.
  • Elastyczność - możesz dodać dodatkowe handlery (pliki, syslog, e-mail).
  • Zgodność z frameworkami - wiele bibliotek i frameworków Pythona używa logging.
  • Zewnętrzna konfiguracja - możliwość ładowania ustawień z pliku.

Jeśli Twoja aplikacja to prosty skrypt CLI lub pojedynczy daemon, możesz używać journal.send() bezpośrednio. Ale jeśli budujesz coś większego - zdecydowanie polecam korzystać z logging + JournalHandler


Rozwiązywanie problemów (brak logów) 🛠️

1. Brak logów w journalctl -p emerg?

Sprawdź, czy:

journal.send("Test", PRIORITY=0)  # ✅ poprawnie
journal.send("Test", PRIORITY="emerg")  # ❌ NIE zadziała

2. Używaj -t zamiast -p do testów

journalctl -t my_app -o verbose

To pokaże logi niezależnie od poziomu.

3. Uruchom jako root (jeśli trzeba)

Niektóre poziomy mogą być pomijane w sandboxie lub przy ograniczonych uprawnieniach:

sudo python3 my_app.py

✅ Podsumowanie

  • systemd.journal.send() umożliwia szybkie logowanie
  • PRIORITY to liczba od 0 do 7
  • standardowe logging można podpiąć do journald
  • journalctl pozwala filtrować logi po identyfikatorze (-t) i poziomie (-p)
  • do debugowania używaj -o verbose