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ę:
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ść logaSYSLOG_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:
Sprawdzenie logów:
Z filtrowaniem po poziomie:
Wyświetlenie pełnych danych (w tym PRIORITY):
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.conflub 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_IDENTIFIERwjournaldto nazwa loggera (my_app). - W
journalctlmożesz odczytać te logi za pomocą:
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
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:
✅ Podsumowanie
systemd.journal.send()umożliwia szybkie logowaniePRIORITYto liczba od 0 do 7- standardowe
loggingmożna podpiąć do journald journalctlpozwala filtrować logi po identyfikatorze (-t) i poziomie (-p)- do debugowania używaj
-o verbose