Linux-Magazin: Syslog
Teil 2: Programmieren mit SyslogSystem-Logging bietet eine einfache Möglichkeit, die Ausgabe von Programmen zentral aufzufangen und zu verwalten. Diese Technik ist keineswegs auf Unix oder Linux beschränkt, sondern findet sich z.B. bei IOS (Cisco) und ka9q wieder. In diesem Teil werden wir sehen, wie diese Möglichkeit in eigenen Programmen genutzt werden kann. |
|
Die meisten Syslog-Nachrichten werden innerhalb von Systemprogrammen erzeugt, die selbst nicht mehr mit einer Konsole verbunden sind und daher dort nicht schreiben können, sogenannte Dämonen. Meistens handelt es sich dabei um C-Programme. Wir unten sehen zu sehen ist, können jedoch auch Shell-, Perl- und andere Skripte Syslog-Nachrichten schreiben.
Wer unter X11 arbeitet, der möchte vielleicht Syslog-Nachrichten auf einen Blick sehen. Dafür existiert das Programm xconsole, welches gelesene Nachrichten in einem speziellen Fenster darstellt. Dieses Fenster hat einen Puffer, man kann also auch die Nachrichten lesen, die vor einer Stunde geschrieben wurden.
Voraussetzung für die Benutzung ist jedoch, daß der syslogd entsprechende Nachrichten zur Verfügung stellt. Dazu wird eine "Pipe" benötigt, in der die syslogd schreibt und xconsole ausliest.
Sie wird mit mknod angelegt. Damit sie von allen Benutzern gelesen werden kann, muß der Mode entsprechend gesetzt werden.
mknod -m 644 /dev/xconsole p
Natürlich muß der Administrator des Systems von nun an aufpassen, welche Nachrichten dort hineingeschrieben werden. Normale Benutzer solllten auf keinen Fall unberechtigt Paßwörter lesen können. Im vorherigen Teil wird daher nur
mail.=info
für die XConsole gelogt. Auf diese Weise sieht der Benutzer, wer sich auf seinem System einlogt. Der tcpd schreibt seine Meldungen normallerweise mit diesem Typ und dieser Priorität. Die Liste kann natürlich erweitert werden, allerdings sollte man sich gut überlegen, wieviel gelogt wird.
|
Tabelle 1: Syslog-Routinen |
|
| openlog() | Öffnet einen Syslog-Stream |
| syslog() | Schreibt Syslog-Nachrichten |
| closelog() | Schließt den Syslog-Stream |
System Logging kann die Suche nach Fehlern in Programmen erheblich erleichtern. Oft ist es schwierig oder zeitaufwendig, nachträglich Logroutinen oder zusätzliche Ausgaberoutinen in Programme einzubauen. Sehr einfach hingegen ist es, zusätzliche Ausgaben per Syslog zu verteilen.
Syslog in C-Programmen
Zuerst muß mit der Routine openlog() die Verbindung zum Syslog aufgebaut werden. Diese Routine nimmt verschiedene Parameter an, die in Tabelle 2 beschrieben werden. Der wichtigste Parameter ist der Bezeichner. Hier sollte der Name des laufenden Programms angegeben werden. Wenn es mehrfach gestartet sein kann, sollte LOG_PID zusätzlich als Option angegeben werden. Damit läßt sich anschließend genau bestimmen, welches Programm die Nachricht erzeugt hat.
Syslog-Nachrichten werden vom syslogd anhand der angegebenen Facility und Priority getrennt und in unterschiedlichen Logdateien gespeichert bzw. auf Konsolen angezeigt oder an weitere Rechner geschickt. Es stehen insgesamt 24 Facilities (Typen) und 8 Prioritäten zur Verfügung. Bis auf 8 lokale Typen sind sie allerdings vordefiniert und werden von vielen Programmen bereits benutzt.
|
Tabelle 2: openlog() |
|
| void openlog(ident, option, facility) | |
| char *ident | Der Identifizierer für erzeugte Syslog-Nachrichten. Üblicherweise ist dieses der Programmname. |
| int option |
Hier werden zusätzliche Parameter für die erzeugten
Syslog-Nachrichten festgelegt. Möglich ist eine ODER-Verknüpfung
der folgenden Konstanten: LOG_CONS - Es wird direkt auf die Konsole geschrieben, wenn ein Fehler mit dem System-Logging auftritt. LOG_NDELAY - Die Verbindung zum Logdämon wird sofort aufgebaut und nicht erst, wenn die erste Nachricht geschrieben wird. LOG_PERROR - Syslog-Nachrichten werden ebenfalls auf der Fehlerausgabe stderr ausgegeben. LOG_PID - Jede Syslog-Nachricht enthält die Prozeß-ID des laufenden Programms. Das ist insbesondere dann sinnvoll, wenn das Programm mehrfach gestartet sein kann. |
| int facility | Hier wird der Typ der Syslog-Nachrichten definiert. Siehe dazu Tabelle 1 aus dem vorherigen Teil oder syslog(3). |
Die Typen umfassen Mail, News, UUCP, Drucksysteme, Cron, allgemeine Dämonen, Kernel etc. Eine konkrete Aufzählung findet sich in <syslog.h> oder im ersten Teil dieser Serie. Damit eine sinnvolle Zuordnung der Log-Nachrichten zu Logdateien erfolgen kann, sollte der Typ gut gewählt werden. Alle Nachrichten, die etwas mit dem Newssystem zu tun haben, sollten z.B. mit LOG_NEWS gelogt werden.
Der Aufruf von openlog() kann entfallen. Dann wird allerdings kein Bezeichner gesetzt und keine Prozeß-ID geschrieben. Die Nachrichten können anschließend nicht mehr klar zugeordnet werden, daher sollte nicht auf den Aufruf verzichtet werden.
Nachdem jetzt die Voraussetzungen geschaffen sind, können die ersten Syslog-Nachrichten erzeugt werden. Hierfür ist die in Tabelle 3 beschriebene Routine syslog() zuständig.
| Tabelle 3: syslog() | |
| void syslog(priority, format, ...) | |
| int priority | Die Priorität dieser Nachricht. Siehe Tabelle 2 aus dem vorherigen Teil oder syslog(3). |
| char *format, ... | Die eigentliche Nachricht. Es kann ein Format-String verwendet werden. Die Benutzung wird in der Manualpage von printf(3) beschrieben. |
Der erste Parameter bezeichnet die Priorität der Nachricht. Im vorherigen Teil dieses Workshops ist eine Liste möglicher Prioritäten abgedruckt. Hier sollte unbedingt ein passender Wert angegeben werden, damit die Nachrichten auch in einer passenden Logdatei landen. Oftmals werden z.B. äußerst wichtige Nachrichten (.emerg/.alert) auf der Konsole oder auf die Terminals der eingeloggten Benutzer ausgegeben.
Nachrichten mit der Priorität Debug oder Info sind im normalen Betrieb nicht wichtig. Da manche Programme Debug-Informationen ständig rausschreiben, kann es vorkommen, daß hier recht viele Nachrichten ankommen. Daher werden diese im normalen Betrieb u.U. ignoriert und die Konfiguration vom syslogd muß ggf. zeitweise geändert werden.
Der zweite Parameter leitet die eigentliche Nachricht ein. Dabei handelt es sich um einen variablen Format-String, wie er z.B. auch von printf() verwendet wird. Dieser Parameter hat eine variable Länge und kann wiederum aus mehreren Argumenten bestehen. Sein erstes Argument enthält Formatanweisungen wie %s, %d, %f (String, Integer, Realzahl) etc. Weitere Argumente enthalten die Daten, die anhand der Formatanweisungen dargestellt werden. Die Bedeutung weiterer Typen sollte der Manpage zu printf() entnommen werden.
Schließlich ist da noch die Routine closelog(), mit der die Verbindung zum Log-System wieder geschlossen wird. Die Verwendung dieser Routine ist ebenfalls optional. Will man während des Programmlaufs die Facility ändern, so muß die Verbindung zum Log-System zuerst geschlossen und anschließend neu geöffnet werden. Wird closelog() nicht verwendet, so übernimmt openlog() das Schließen der Verbindung.
Abbildung 1 zeigt zum Abschluß ein kleines C-Programm als Beispiel, welches jeweils in den angesprochenen Sprachen wiederholt wird. Zuerst wird das Logging aktiviert mit dem Bezeichner 'freax' sowie dem Typen Local3. In jeder geschriebenen Zeile soll die Prozeß-ID enthalten sein. Wenn ein Fehler auftritt, soll direkt auf die Konsole geschrieben werden.
Anschließend werden zwei Zeilen ausgegeben. Die erste als local3.debug und die zweite mit einem anderen Typ und anderer Priorität, nämlich news.notice. Je nach verwendeter Sprache ist dazu mehr oder weniger Aufwand nötig.
| Abbildung 1: Syslog-Beispiel in C | |
#include <syslog.h>
void main()
{
int counter = 10;
openlog("freax.c", LOG_CONS | LOG_PID, LOG_LOCAL3);
syslog (LOG_DEBUG, "Der Counter steht auf %d.", counter);
counter++;
openlog("froax.c", LOG_CONS | LOG_PID, LOG_NEWS);
syslog (LOG_NOTICE, "Und jetzt steht er auf %d.", counter);
closelog();
}
| |
Syslog in Perl-Programmen
Die Perl-Routinen für Syslog-Nachrichten benötigen die gleichen Parameter wie die C-Routinen. Die Verwendung geschieht damit analog und es ist kein Umdenken nötig.
Die Perl-Routinen sind allerdings flexibler als die C-Äquivalente. Das liegt daran, daß sie sich nicht auf das Logsystem des Systems abstützen, sondern die Nachrichten über das Netz an den Loghost schicken. Als Loghost ist 'localhost', also der lokale Rechner, voreingestellt.
Dieses beschert einem Linuxer allerdings zwei Tücken. Zum einen gehen die Nachrichten verloren, wenn der syslogd keine Nachrichten aus dem Netzwerk empfängt (-r nicht angegeben). Zum anderen werden diese Nachrichten nicht mehr an andere Rechner weitergeleitet, da sie bereits aus dem Netzwerk empfangen wurden.
Um auf die Syslog-Routinen zugreifen zu können, muß ein zusätzliches Paket eingebunden werden. Dieses nennt sich Sys::Syslog. Die Dokumentation dieses Pakets kann man sich jederzeit mit "perldoc Sys::Syslog" ansehen.
Sowohl die Typen als auch Prioritäten und Optionen werden allerdings in Kleinbuchstaben und ohne den C-Präfix LOG_ angegeben. Soll eine Nachricht mit einem anderen Typen versehen werden, so kann diser einfach vor die Priorität geschrieben werden.
Abbildung 2 zeigt das oben vorgestellte Beispiel diesmal in Perl.
| Abbildung 2: Syslog-Beispiel in Perl | |
#! /usr/bin/perl
use Sys::Syslog;
openlog "freax.pl", "cons.pid", "local3";
$counter = 10;
syslog "debug", "Der Counter steht auf %d", $counter;
$counter++;
syslog ('news|notice', "Und jetzt steht er auf %d.", $counter);
closelog;
| |
Syslog in Python-Programmen
Auch in der Programmiersprache Python sieht die Programmierung mit Syslog ähnlich unkompliziert aus. Dort muß ebenfalls ein Paket namens 'syslog' eingebunden werden. Es werden die gleichen Konstanten wie auch in C verwendet.
Abbildung 3 zeigt das bereits vorgestellte Beispiel diesmal in Python.
| Abbildung 3: Syslog-Beispiel in Python | |
#! /usr/bin/python
from syslog import *
openlog ("freax.py", LOG_PID|LOG_CONS, LOG_LOCAL3);
counter = 10;
syslog (LOG_DEBUG, "Der Counter steht auf " + `counter`);
counter = counter + 1;
openlog ("froax.py", LOG_PID|LOG_CONS, LOG_NEWS);
syslog (LOG_NOTICE, "Und jetzt steht er auf " + `counter`);
| |
Syslog in Shell-Skripten
Auf Shell-Ebene steht das Programm logger zur Verfügung, welches die angegebene Nachricht per Syslog weiterschickt. Die Parameter sind leicht verständlilch. Mit "-t" wird ein "tag" angegeben, welcher dem Bezeichner in C entspricht. Mit "-i" wird ebenfalls die Prozeß-ID geschrieben und mit "-p" werden Typ und Priorität angegeben. Der Rest wird als Nachricht interpretiert.
Abbildung 4 zeigt das bereits vorgestellte Beispiel diesmal als Shell-Skript.
| Abbildung 4: Syslog-Beispiel in Shell-Skripten | |
#! /bin/sh counter=10 logger -i -t freax.sh -p local3.debug "Der Counter steht auf" $counter"." counter=$[$counter + 1] logger -i -t froax.sh -p news.notice "Und jetzt steht er auf" $counter"." | |
Im Abbildung 5 sind die mit den bisherigen Beispielen erzeugten Nachrichten in einem XConsole-Fenster zu sehen.
| |
| Abbildung 5: Die Syslog-Nachrichten der bisherigen Beispiele | |
Logs im Rechnernetz
Wer ein Netzwerk betreibt, sowohl privat als auch in einer Firma, ist dankbar, wenn er nicht auf allen Rechnern Logdateien verwalten muß, sondern nur auf einem Loghost. Wie im vorherigen Teil beschrieben, ist der syslogd in der Lage, Nachrichten über das Netz zu verbreiten und von dort aufzulesen. So lassen sich nicht nur Unix-Rechner leichter verwalten, sondern auch Router bekannter Hersteller wie Cisco, ISPA oder ka9q.
Ein Cisco-Router kann z.B. mit den in Abbildung 6 gezeigten Befehlen derart konfiguriert werden, daß er auf einen Unix-Rechner logt.
| Abbildung 6: Einstellungen auf einer Cisco | |
logging 134.107.120.3 logging trap notification debug ip-routing debug novell-routing | |
Fortan schickt er Informationen des IP- und Novell-Routings ab der Priorität notice über das Netzwerk an den Loghost mit der IP-Nummer 134.107.120.3. Als Facility wird dabei local7 (siehe Beispiel in der letzten Folge) verwendet.
| |
| Abbildung 7: In der XConsole überwacht der Administrator das Netz | |