Wiadomości jądra Linux po starcie systemu powinny być dostępne tylko dla administratora. To samo tyczy się jego wskaźników. Analogicznie możemy postąpić z logami jądra, które są wyświetlane na konsoli podczas i po starcie serwera. Za ich wyświetlanie odpowiedzialna jest jedna z najbardziej znanych funkcji z interfejsu jądra Linuksa – printk(). Jest to standardowe narzędzie, które służy do wyświetlania wiadomości i zwykle najbardziej podstawowy sposób na śledzenie i debugowanie kodu jądra. jeżeli jesteśmy zaznajomieni z printf(3) to można powiedzieć, iż printk() jest na nim oparty, chociaż ma pewne funkcjonalne różnice: jego komunikaty mogą zostać określone dzięki poziomu szczegółowości (na czym się skupimy tutaj) oraz ciąg formatu (ang. format string) – choć w dużej mierze zgodny z C99, nie podąża dokładnie za tą samą specyfikacją.
Wszystkie komunikaty printk() są wypisywane do bufora logu jądra, który jest buforem pierścieniowym (ang. ring buffer) eksportowanym do przestrzeni użytkownika (ang. userspace) przez urządzenie strumieniowe /dev/kmsg. Najzwyklejszym sposobem na odczytanie go to użycie polecenia: dmesg, które wypisze nam cały bufor dziennika jądra. Funkcji printk() zwykle używa się w ten sposób:
gdzie KERN_INFO jest jednym z ośmiu poziomów szczegółowości dziennika zdefiniowanym w include/linux/kern_levels.h (zauważmy, iż jest on konkatenowany z łańcuchem formatu nie będąc osobnym argumentem). Dostępne poziomy dziennika to:
Nazwa: Ciąg: Alias funkcji: Opis: KERN_EMERG "<0>" pr_emerg() /* system bliski awarii lub jest niestabilny */ KERN_ALERT "<1>" pr_alert() /* konieczna natychmiastowa interwencja */ KERN_CRIT "<2>" pr_crit() /* stan krytyczny, taki jak awaria sprzętu */ KERN_ERR "<3>" pr_err() /* stan błędu (używany przez sterowniki) */ KERN_WARNING "<4>" pr_warn() /* ostrzeżenie, mogące wskazywać na problemy */ KERN_NOTICE "<5>" pr_notice() /* normalna, ale istotna wiadomość systemowa */ KERN_INFO "<6>" pr_info() /* wiadomość informacja np. init sterownika */ KERN_DEBUG "<7>" pr_debug() /* komunikaty diagnostyczne */Poziom szczegółowości dziennika określa ważność komunikatu. Jądro systemu decyduje, czy natychmiast wyświetlać komunikat (wydrukować go na bieżącej konsoli), w zależności od poziomu dziennika i bieżącego poziomu console_loglevel (zmiennej jądra). jeżeli priorytet komunikatu jest wyższy (niższa wartość poziomu dziennika) niż console_loglevel, komunikat zostanie wydrukowany na konsoli. W przypadku pominięcia poziomu dziennika komunikat jest drukowany z poziomem KERN_DEFAULT. Możemy sprawdzić bieżący poziom console_loglevel dzięki polecenia:
agresor@darkstar:~$ cat /proc/sys/kernel/printk 4 4 1 7Kolejno liczby te odnoszą się do: current (console_loglevel) – aktualny poziom, gdzie komunikaty o niższym priorytecie (czyli o większej krytyczności) od tej wartości wypisywane będą na bieżącej konsoli; default (default_message_loglevel) – domyślny poziom dla komunikatów bez ustalonego priorytetu; minimum (minimum_console_loglevel) – minimalny poziom, który możemy ustawić; boot-time-default (default_console_loglevel) – domyślny poziom dla komunikatów, jakie mają pojawić się na konsoli. W systemie Ubuntu 22.04 wartości te są ustawiane przez plik zmieniający ustawienia jądra dzięki programu sysctl:
root@darkstar:~# cat /etc/sysctl.d/10-console-messages.conf # the following stops low-level messages on console kernel.printk = 4 4 1 7W celu zmiany bieżącego poziomu logowania na konsoli możemy po prostu przesłać do tej ścieżki interesujący nas poziom logowania np. chcemy tylko, aby naprawdę krytyczne błędy się tam pojawiały:
echo 3 3 1 3 > /proc/sys/kernel/printkInnym sposobem zmiany poziomu logowania jest użycie polecenia dmesg z parametrem -n:
dmesg -n 3W ten sposób logowane i wyświetlone będą tylko komunikaty o wartości niższej (nie mniejszej równej [!) niż ustawiony poziom. Możemy również określić poziom komunikatów konsoli podczas rozruchu jądra dzięki parametru loglevel=. I tutaj ciekawostka. Możemy również zrobić to konfiguracją sysctl na poziomie rozruchu, ponieważ Vlastimil Babka z SUSE zaproponował zmianę, która umożliwia od jądra w wersji 5.8 dodawanie opcji sysctl jako parametrów startowych jądra:
root@darkstar:~# cat /etc/default/grub | grep GRUB_CMDLINE_LINUX_DEFAULT GRUB_CMDLINE_LINUX_DEFAULT="sysctl.kernel.printk=3 3 1 3"Więcej informacji: Odpluskiwanie jądra Linuksa - printk(), Debugging by printing, Message logging with printk, How to set sysctl using kernel command line parameter?