Zum Inhalt springen

Logs und Journal

Ein Dienst startet nicht. Die Fehlermeldung von systemctl start lautet nur: «See journalctl -xeu nginx.service for details». Wer jetzt weiss, wo er nachschaut, hat das Problem meist in zwei Minuten gefunden. Logs lesen ist die halbe Administration.

systemd sammelt alle Meldungen von Kernel, Diensten und Login-Vorgängen in einer Datenbank, dem Journal. Jeder Eintrag trägt Zeitstempel, Unit, Prozess und Priorität. Das Werkzeug dazu ist journalctl:

Befehl Zeigt
journalctl Alles, vom ältesten Eintrag an (mit q verlassen)
journalctl -r Alles, neueste zuerst
journalctl -n 50 Die letzten 50 Zeilen
journalctl -f Laufend neue Einträge, wie tail -f
journalctl -u nginx Nur die Unit nginx
journalctl -b Nur seit dem letzten Boot (-b -1 der Boot davor)
journalctl -p err Nur Priorität err und schlimmer (emerg alert crit err warning notice info debug)
journalctl --since "1 hour ago" Zeitfenster, auch --since today, --since "2025-11-04 08:00", --until ...
journalctl -k Nur Kernel-Meldungen
journalctl -xeu nginx Unit nginx, ans Ende springen, mit Erklärungen (-x)

Die Optionen lassen sich kombinieren. Der Standardbenutzer auf Ubuntu ist in der Gruppe adm und sieht alles; sonst braucht es sudo.

Hands-on:

Terminal-Fenster
journalctl -n 20
journalctl -b -p err
journalctl -u ssh --since today
journalctl -u ticker -r | head
journalctl --disk-usage

Du kennst systemctl status bereits: Die Zeilen unter dem Statusblock sind die letzten zehn Journal-Einträge der Unit. Für eine schnelle Diagnose reicht das oft, für alles Weitere nimmst du journalctl -u.

Eigene Meldungen ins Journal schreibst du mit logger. Damit testest du, ob ein Filter stimmt, oder schreibst aus Skripten ins Log:

Terminal-Fenster
logger -t lernlabor "Hallo Journal"
logger -t lernlabor -p user.err "Das ist ein Fehler"
journalctl -t lernlabor
journalctl -t lernlabor -p err

-t setzt das Tag (den Programmnamen), -p die Priorität. In einer zweiten SSH-Sitzung kannst du journalctl -f laufen lassen und zusehen, wie die Meldungen eintreffen.

Vor dem Journal gab es nur Textdateien, und die gibt es weiterhin. Auf Ubuntu Server läuft zusätzlich rsyslog, das die Meldungen aus dem Journal in die gewohnten Dateien schreibt. Dazu schreiben manche Programme ihre Logs selbst, ohne Umweg über systemd.

Terminal-Fenster
ls -lt /var/log | head -n 15
sudo tail -n 5 /var/log/syslog
sudo tail -n 5 /var/log/auth.log
tail -n 5 /var/log/dpkg.log
sudo tail -n 5 /var/log/nginx/access.log
Datei Inhalt
syslog Das Sammelbecken: alles, was keinen eigenen Platz hat
auth.log Logins, sudo, SSH-Verbindungen, fehlgeschlagene Passwörter
kern.log Kernel-Meldungen
dpkg.log, apt/history.log Welche Pakete wann installiert oder entfernt wurden
nginx/access.log, nginx/error.log Jede Anfrage an den Webserver beziehungsweise seine Fehler, von nginx selbst geschrieben
wtmp, btmp Binär: Logins und fehlgeschlagene Logins, lesbar mit last und sudo lastb

Mach einen Request und schau zu: curl localhost/gibtsnicht, dann sudo tail -n 2 /var/log/nginx/access.log. Du siehst die Zeile mit Status 404.

Noch drei Werkzeuge für spezielle Fragen:

Terminal-Fenster
sudo dmesg -T | tail -n 20
last -n 10
last reboot
lastlog | head

dmesg zeigt den Kernel-Ringpuffer (USB-Geräte, Disk-Fehler, Out-of-Memory). last listet Logins und Reboots, lastlog den letzten Login jedes Benutzers.

Logdateien wachsen. Damit die Disk nicht vollläuft, dreht logrotate sie regelmässig: syslog wird zu syslog.1, dann syslog.2.gz und so weiter, alte werden gelöscht. Die Regeln liegen in /etc/logrotate.conf und pro Programm in /etc/logrotate.d/:

Terminal-Fenster
cat /etc/logrotate.d/nginx
systemctl list-timers logrotate.timer

Das Journal begrenzt sich selbst (SystemMaxUse= in /etc/systemd/journald.conf), journalctl --vacuum-time=30d räumt von Hand auf.

Ein Dienst startet nicht. Das Vorgehen ist immer dasselbe:

flowchart TD
    A["sudo systemctl start NAME schlägt fehl"] --> B["systemctl status NAME<br/>Exit-Code? letzte Zeilen?"]
    B --> C["journalctl -xeu NAME<br/>die eigentliche Fehlermeldung des Programms"]
    C --> D{"Was sagt die Meldung?"}
    D -->|"syntax error, unknown directive"| E["Konfiguration prüfen<br/>nginx -t, sshd -t, Skript von Hand starten"]
    D -->|"Address already in use"| F["Port belegt?<br/>sudo ss -tlnp"]
    D -->|"No such file, Permission denied"| G["Pfade und Rechte prüfen<br/>ls -l, User= in der Unit"]
    E --> H["beheben, daemon-reload falls Unit geändert, start, status"]
    F --> H
    G --> H

Hands-on: einen belegten Port provozieren. nginx hält Port 80, ein zweiter Webserver will ihn auch:

Terminal-Fenster
sudo ss -tlnp
sudo python3 -m http.server 80

ss -tlnp listet alle TCP-Ports (t), auf denen gelauscht wird (l), numerisch (n) mit Prozess (p). Python meldet «Address already in use», und in der ss-Ausgabe steht, dass es nginx ist. Genau diese Meldung siehst du im Journal, wenn zwei Dienste denselben Port wollen.

Lösung anzeigen
Terminal-Fenster
script labs/linux/09-dienste/logs.txt
sudo sed -i 's/sleep 10/slep 10/' /usr/local/bin/ticker.sh
sudo systemctl restart ticker
sleep 30
systemctl status ticker
journalctl -xeu ticker | tail -n 30
# Antwort 1: Exit-Code 127, "command not found": die Shell hat slep nicht gefunden.
# Antwort 2: Fünf Mal innert 10 Sekunden (Standard: StartLimitBurst=5, StartLimitIntervalSec=10s), dann "Start request repeated too quickly" und failed.
# Antwort 3: ticker.sh: line 9: slep: command not found
sudo sed -i 's/slep 10/sleep 10/' /usr/local/bin/ticker.sh
sudo systemctl reset-failed ticker
sudo systemctl start ticker
systemctl status ticker
exit

Selbstcheck · 5 Fragen

1. Welcher Befehl zeigt nur die Logs des Dienstes nginx seit dem letzten Boot?
2. Wo landet die Ausgabe, die ein Dienst auf stderr schreibt?
3. Was zeigt `sudo ss -tlnp`?
4. Welche Datei verrät, wer sich per SSH angemeldet hat oder es erfolglos versucht hat?
5. Welche Aussagen zu logrotate stimmen? (mehrere Antworten möglich)