This text gives an example of a simple Syslog configuration (SOHO type) and describes a little Konqueror/CGI kioslave/Bash based logfile viewer. The Syslog config files are included in the documentation of the viewers downloadable packages. All examples and source files are commented in english. This software needs no compilation.
This document refers to version 0.1 of the centaurilog package - check the internet for newer versions: Click here to see the downlad page.
Dieser Text stellt eine einfache Syslog Konfiguration (für den SOHO Einsatz) vor und beschreibt eine kleine Konqueror/CGI kioslave/Bash basierte Logfile Anzeige. Die Syslog Konfiguaritionsdateien sind den downloadbaren Packeten der Anzeige Anwendung enthalten. Alle Beispiele und Quellentexte sind auf Englisch kommentiert. Diese Software bedarf keiner Kompilierung.
Dieses Dokument beschreibt Version 0.1 des centaurilog Pakets - bitte im Internet nach neueren Versionen sehen: Hier der Verweis zur Download Seite.
Bei den meisten Linux Distributionen ist
ksyslogd
zu kompliziert konfiguriert. Im SOHO Betrieb
ist die Menge der anfallenden Daten klein genug um dies zu
vereinfachen. Wir konfigurieren zunächst einen Server und dann
Arbeitsplätze. Die Arbeitsplatzrechner sollen Fehlermeldungen
zum Server weiterreichen.
# Server side example for /etc/syslog.conf - see "man syslog.conf". # print warnings on tty10, use write to announce desasters kern.warn;*.err;authpriv.none /dev/tty10 *.crit * # all mail-messages in one file (no sync) mail.* -/var/log/mail # Warnings in one file (sync for error only) *.=warn;*.=err -/var/log/errors *.crit /var/log/errors
Die folgende Konfiguation für Arbeitsplatzrechner führt einerseits ein lokales Logfile (mail wird hier nicht getrennt behandelt) und sendet Warnungen und Fehler zu Server (heisst hier alpha):
# Workstation example for /etc/syslog.conf - see "man syslog.conf". # print warnings on tty10, use write to announce desasters kern.warn;*.err;authpriv.none /dev/tty10 *.crit * # forward errors to server 'alpha' *.err @alpha # extra log file for error messages (no snyc here!) *.err -/var/log/errors # save the rest in one file (avoid sync if non-critical) *.crit /var/log/messages *.*;*.!=crit -/var/log/messages
Achtung: Bitte daran
denken den Server aus dem Beispiel (hier alpha)
umzubennen! Zudem sollte der syslogd
richtig gestartet
werden. Bei Debian können die dafür nötigen Optionen
in /etc/defaults/
eingetragen werden:
# Debian syslogd configuration: /etc/default/syslogd # The client might disable --MARK-- messages: # SYSLOGD="-m0" # The server also enables remote logging for the domain: SYSLOGD="-m0 -r -s centauri.home" # Another way for the server to specify clients is a list of hosts: # SYSLOGD="-m0 -r -l alpha7:alpha8:alpha9"
Achtung: Hier daran
denken den Domänennamen zu editieren. Das Beispiel geht davon
aus, dass per DNS Server eine Domäne aufgesetzt ist.
Alternativ können auch einzelne Hosts angegeben werden (deren
IP-Adressen könnten in /etc/hosts/
stehen).
Diese Beispiele sind auch in der Dokumentation der oben zum Download angebotenen Archive enthalten.
Ohne weiteres Zutun würden die oben
eingeführten Logfiles über alle Grenzen wachsen. Es ist
also nötig periodisch neue Dateien zu beginnen und zu alte
Dateien zu löschen. Bei Debian könnte diese Aufgabe von
logrotate
übernommen werden. Leider müsste
man dann aber die Konfiguration aus syslog.conf
teilweise in die /etc/logrotate.d
Konfiguation
übertragen. Die wäre unpraktisch - anstelle dessen wird
syslogd-listfiles
benutzt. Das Tool listet die von
syslogd
benutzten Dateien auf. Debian hat zwei
Cron-Jobs (/etc/cron.daily/ksyslogd
und
/etc/cron.daily/ksyslogd
) dafür vorgesehen.
Eventuelle andere Logs werden aber meist über
logrotate
verwaltet (Mail z.B.).
Im SOHO Betrieb wollen wir vermutlich von
täglichem Logfilewechsel auf wöchentlichen Wechsel
umstellen. Dazu braucht nur in den Dateien unter
/etc/logrotate.d
das Schlüsselwort "daily" nach
"weekly" umgeändert werden. Leider sind bei Debian die
Cron-Jobs nicht so leicht zu ändern. Wir änderen hier
zwei Dateien ab:
#!/bin/bash # Modified /etc/cron.daily/ksyslogd exit 0 # inserted line to disable daily rotation ....
#!/bin/bash # Modified /etc/cron.weekly/ksyslogd ... # skip to line 31 or so and change '--weekly' to '--all'... for LOG in `syslogd-listfiles --all` ...
Wie oben zu sehen war landen die Logfile Daten auch bei einer einfachen Konfiguration in mehreren Dateien. Zudem steht in diesen Dateien ziemlich viel uninteressantes. Ein Viewer muss also mehrere Dateien zusammenfassen und nach Inhalt filtern können. Ausser kompliziert zu konfigurirenden Programmen (z.B. logtool) gibt es ausgerechnet bei KDE wenig an Viewer Tools. Nutzen wir also an dieser Stelle KDEs CGI kioslave um ein recht mächtiges aber einfaches Tool selber zu implementieren. Da es sich im Kern um ein Shell-Script handelt ist es leicht eigenen Bedürfnissen anzupassen. Als Oberfläche wird Konqueror benutzt, die Ein-/Ausgabe erfolgt also per HTML.
Die oben zum Download angebotenen Archive
enthalten auch eine Manual-Seite zur genaueren Beschreibung des
Tools. Nach der Installation könnten wir also in Konqueror die
URL man:centaurilog
eingeben. Hier steht
man:
für den Manual kioslave, der aber ein in C++
geschriebenes Programm ist und uns hier nicht weiter interessiert.
Unser Logfileviewer (genauer: CGI) muss zunächst für den
Benutzer konfiguriert werden. Das geht z.B. mit den Tasten
Alt+F2
und der Eingabe centaurilog
--setup
. Nun können wir Logfiles aus einer laufenden
Konqueror Instanz ansehen indem wir als URL
cgi:centaurilog
eingeben.
Alternativ kann man das Script
centaurilog
auch direkt aufrufen, eine Konqueror
Instanz wird dann automatisch gestartet (siehe auch den Eintrag der
im System Menü eingerichtet wird). Wer sich die Mühe
macht ein Konqueror-Profil unter dem Namen "centaurilog" abzulegen
wird dann auch regelmässig durch ein nach eigenen Vorgaben
eingerichtetes Fenster belohnt. Es sei noch angedeutet dass sich
Queries "bookmarken" lassen - und dass die Query-Argumente auch
beim direkten Aufruf mit der Option --query
angegeben
werden können.
Der Script Code ist recht einfach und lädt fortgeschrittene Bash Programmierer sicher zu eigenen Kreationen ein:
#!/usr/bin/env bash declare this="${0##*/}" function show_help() { cat <<EOF This is a KDE/Konqueror based logfile viewer. usage: $this --setup $this [--nocheck] [--profile name] [--query urlargs] options: --setup do the KDE setup for this user and quit --nocheck do not check if --setup was run before --profile konqueror profile, use '' to override '$this' --query url-encoded query arguments passed to konqueror --help show this text and quit EOF exit 1 } function run_setup() { local paths="$(kreadconfig --file kcmcgirc --group General --key Paths)" local instd="$(readlink -f "$0")" ; instd="${instd%/*}" if ! grep -q -E "(^|,)${instd}/?(\$|,)" <<<$paths ; then echo "$this: user $USER: CGI config updated to include: $instd" [ -n "$paths" ] && instd="$paths,$instd" kwriteconfig --file kcmcgirc --group General --key Paths "$instd" fi [ -n "$1" ] && exit 0 } function run_normal() { local pdir="$HOME/.kde/share/apps/konqueror/profiles" [ -r "$pdir/$this" ] && prof="$this" while [ $# -gt 0 ] ; do case $1 in -pro*|--pro*) prof="$2"; shift ;; -que*|--que*) uarg="?$2"; shift ;; -noc*|--noc*) fnoc="x" ;; -set*|--set*) fset="x" ;; -h*|--h*) show_help ;; *) echo "$this: unknown option - try '--help'" exit 2 ;; esac ; shift ; done [ -z "$fnoc" -o -n "$fset" ] && run_setup "$fset" [ -z "$prof" ] && exec konqueror "cgi:${this}$uarg" exec konqueror --profile $prof "cgi:${this}$uarg" } function render_form() { [ -f /var/log/errors ] || dispError="display: none" [ -f /var/log/mail ] || dispMail="display: none" cat <<EOF <script language="javascript"> function lock(n) { var x = document.getElementById("chkSyslog"); if(x == null) return; var y = document.getElementById("chkErrors"); if(y == null) return; if(x.checked && n==1) y.checked = false; if(y.checked && n==2) x.checked = false; } </script> <h2>Logfile Viewer - Query Form</h2> <form action="cgi:${this}" method="GET"> <div class='spacer'></div><table class="query"> <tr> <td valign="top" rowspan="2"><b>Select the Logfile(s):</b></td> <td><br></td> </tr> <tr> <td align="right">System Log (all) </td> <td><input id="chkSyslog" name="chkSyslog" type="checkbox" $CHK_SYSLOG onclick="lock(1)" value="x"></td> </tr> <tbody style="$dispError"><tr> <td></td> <td align="right">... (Errors only) </td> <td><input id="chkErrors" name="chkErrors" type="checkbox" $CHK_ERRORS onclick="lock(2)" value="x"></td> </tr></tbody> <tbody style="$dispMail"><tr> <td></td> <td align="right">Mail Log</td> <td><input type="checkbox" name="chkMail" $CHK_MAIL value="x"></td> </tr></tbody> <tr> <td></td> <td align="right">max. Entry Count </td> <td><input type=text name=txtMaxlines> (Default: $TXT_MAXLINES)</td> </tr> <tr> <td colspan="3"><b>Content Filters (optional):</b></td> </tr> <tr> <td valign="top" rowspan="3"></td> <td align="right">Select a Computer </td> <td><input type="text" name="txtComputer" value="$TXT_COMPUTER"></td> </tr> <tr> <td align="right">Filter on Words</td> <td><input type="text" name="txtFilter" value="$TXT_FILTER"> <input type="checkbox" name="chkExclude" $CHK_EXCLUDE value="x"> Exclude</td> </tr> <tr> <td colspan="2"> <br><INPUT type="reset"> <INPUT type="submit"> <a href="man:${this}">Display Help</a></td> </tr> </table></form> EOF } function render_data() { # take care about temp files ... temp="${TMPDIR:-/tmp}/$$_showlog_" trap "rm -f ${temp}*" 0 # convert query string back to varibles ltab=$'\a' set x ${QUERY_STRING//&/ } while [ $# -gt 1 ] ; do # UrlDecode and \ handling. It's woodo ... don't panic! nam="${2%%=*}" ; val="${2#*=}" ; shift val="${val//\%5C/ }" ; val="${val//+/$ltab}" read $nam <<<"$(printf "${val//\%/\x}")" done # which logfiles? if [ -n "$chkSyslog" ] ; then [ -f /var/log/messages ] && logf="/var/log/messages $logf" [ -f /var/log/messages.0 ] && logf="/var/log/messages.0 $logf" fi if [ -n "$chkErrors" ] ; then [ -f /var/log/errors ] && logf="/var/log/errors $logf" [ -f /var/log/errors.0 ] && logf="/var/log/errors.0 $logf" fi if [ -n "$chkMail" ] ; then [ -f /var/log/mail ] && logf="/var/log/mail $logf" [ -f /var/log/mail.0 ] && logf="/var/log/mail.0 $logf" fi if [ -z "$logf" ] ; then echo "<h2>Logfile Viewer - No Logfiles are Matching the Request</h2>" echo "[<A href="cgi:${this}">another query</A>]" return fi for fnam in $logf ; do [ -r "$fnam" ] && continue sudo=x ; break done # do we need kdesu to get root rights? maxl=$((txtMaxlines + 0)) &>/dev/null [ -z "$maxl" -o "$maxl" = 0 ] && maxl="$TXT_MAXLINES" msgs="${temp}0" if [ -n "$sudo" ] ; then kdesu -d -c "sort -m -k1M -k2n $logf | tail -n $maxl >$msgs ; chown $UID $msgs ; chmod 600 $msgs" else sort -M -n -m $logf | tail -n $maxl >$msgs ; chmod 600 $msgs fi # filter on computer names ... if [ -n "$txtComputer" ] ; then sinf="for $txtComputer" srex="^.{15} $txtComputer " [ -z "${txtComputer//[a-z0-9-_]/}" ] && sopt="x" fi msgs="${temp}1" grep -h -E "$srex" "${temp}0" >$msgs lcnt=$(wc -l $msgs) cdat=$(date +"%b %e") # html header stuff and javascript ... cat <<EOF <h2>Logfile Viewer - Results (processed ${lcnt% *} Entries $sinf)</h2> [<A href="cgi:${this}">another query</A>] [<A href="#bottom">end of page</A>] <script language="javascript"> var curshow function toggle(name,t) { var x = document.getElementById(name); if(x == null) return; if(curshow != x) { if(curshow == null) curshow = document.getElementById("$cdat") if(curshow != null && curshow.style.display == "inline") curshow.style.display = "none" ; curshow = x } x.style.display = (x.style.display == "inline") ? "none" : "inline"; } </script> EOF # filter for text ... if [ -n "$txtFilter" ] ; then lbrk=$'\n' [ -n "$chkExclude" ] && vopt="-v" grep $vopt -i -F "${txtFilter//$ltab/$lbrk}" $msgs >"${temp}2" rm -f $msgs; msgs="${temp}2" lcnt=$(wc -l $msgs) echo "<h3>Remaining Entries after Filtering: ${lcnt% *}</h3>" fi echo "<table class="result">" sed -e "s/&/\&/g" -e "s/</\</g" $msgs | while read fmon fdat ftim fnam fmsg ; do # output date and time ... fdat="$fmon $fdat" if [ "$fdat" != "$ldat" ] ; then [ -n "$ldat" ] && echo "</tbody>" ldat="$fdat" ; ltim= [ "$ldat" = "$cdat" ] && vmod="inline" || vmod="none" echo "<tr><td colspan=3><em><b>$ldat</b> </em>" echo "[<A href=\"javascript:toggle('$ldat')\">Click to show or hide</A>]" echo "</td></tr><tbody id='$ldat' style='display: $vmod'>" fi [ "$ftim" = "$ltim" ] && ftim=" " || ltim="$ftim" echo "<tr><td class='tim'>$ftim</td>" # output computer name and message ... [ -z "$sopt" ] && echo "<td class='nam'>${fnam}</td>" echo "<td class='txt'>${fmsg}</td></tr>" done [ -n "$ldat" ] && echo "</tbody>" echo "</table>[<A href='cgi:${this}'>another query</A>] [<A href='#top'>top of page</A>]" } # launch konqueror if not called as cgi script... [ -z "${!QUERY_STRING*}" ] && run_normal $* # set defaults and read configuration CHK_SYSLOG="checked" CHK_ERRORS= CHK_MAIL= TXT_MAXLINES="10000" TXT_COMPUTER="$HOSTNAME" TXT_FILTER="" CHK_EXCLUDE= if [ -r "$HOME/${this}.conf" ] ; then . $HOME/${this}.conf elif [ -r "/etc/${this}.conf" ] ; then . /etc/${this}.conf fi # cgi call: send html frame and exec worker ... echo -e "Content-Type: text/html ; charset=utf-8\n\n" echo "<html><title>CentauriTools - Logfile Viewer</title>" echo "<body><style>$STYLE</style><a name="top"></a>" [ -z "$QUERY_STRING" ] && render_form || render_data echo "<div class='spacer'></div>" echo "<h4 name="bottom">Version 0.1 © 2005-2006" echo " <a href="http://www.j-pfennig.de/LinuxImHaus">Dr. Jürgen Pfennig</a>" echo " - code published under BSD license.</h4></body></html>" # end