Open Source im professionellen Einsatz

Graphen statt Zahlenreihen

Messreihen in Logdateien eignen sich leider nur selten dazu, Euphorie oder Gehaltserhöhungen auszulösen, und so nimmt es nicht wunder, dass als nächster Schritt gleich die Darstellung in einem Graphen folgt. Das Werkzeug RRDTool eignet sich hierfür hervorragend. Wem die etwas altertümliche Syntax des Oldtimers missfällt, der nutzt das Perl-Modul RRDTool::OO, das eine moderne objekt-orientierte Syntax bietet.

Um die Logmeldungen im menschenlesbaren Datumsformat Jahr/Monat/Tag/Stunde:Minute:Sekunde in das von RRDTool geforderte Sekundenformat umzuformen, nutzt das Listing 3 das CPAN-Modul DateTime::Format::Strptime und definiert in Zeile 13 ein entsprechendes Erkennungs-Pattern. Zeile 14 stellt die Zeitzone der erfassten Einträge auf die des lokalen Rechners ein.

Listing 3:
»rrdtemp«

001 #!/usr/bin/perl -w
002 use strict;
003 use local::lib;
004 use RRDTool::OO;
005 use DateTime::Format::Strptime;
006
007 my $logfile     = "temper.log";
008 my @data_points = ();
009 my $rrd_file    = "data.rrd";
010
011 my $date_fmt =
012   DateTime::Format::Strptime->new(
013     pattern   => "%Y/%m/%d %H:%M:%S",
014     time_zone => "local",
015 );
016
017   # Read logged temperature data
018 open FILE, "$logfile" or
019     die "Cannot open $logfile ($!)";
020 while( <FILE> ) {
021   if( /(.*) READ (.*)/ ) {
022     my($datestr, $temp) = ($1, $2);
023
024     my $dt =
025       $date_fmt->parse_datetime($datestr);
026     push @data_points,
027          [$dt->epoch(), $temp];
028   }
029 }
030 close FILE;
031
032   # Create RRD
033 my $rrd = RRDTool::OO->new(
034   file        => $rrd_file,
035   raise_error => 1,
036 );
037
038 my $rows = 60*24*30;
039
040 $rrd->create(
041   step => 60*5,
042   data_source => {
043     name    => "temp",
044     type    => "GAUGE"
045   },
046   archive => {
047       rows => $rows,
048       cpoints => 1,
049       cfunc   => 'AVERAGE',
050   },
051   start => $data_points[0]->[0] - 60,
052   hwpredict   => {
053       rows            => $rows,
054       alpha           => 0.1,
055       beta            => 0.0035,
056       gamma           => 0.5,
057       seasonal_period => 24*60/5,
058       threshold       => 14,
059       window_length   => 18,
060   },
061 );
062
063 for my $data_point (@data_points) {
064   $rrd->update(
065       time  => $data_point->[0],
066       value => $data_point->[1],
067   );
068 }
069
070   # Draw Graph
071 $rrd->graph(
072   image => "bounds.png",
073   width  => 1600,
074   height => 800,
075   start => $data_points[0]->[0],
076   end   => $data_points[-1]->[0],
077   draw => {
078     type   => "line",
079     color  => '000000',
080     legend => "Temperature over Time",
081     thickness  => 2,
082     cfunc      => 'AVERAGE',
083   },
084   draw           => {
085     type   => "line",
086     color  => '00FF00',
087     cfunc  => 'HWPREDICT',
088     name   => 'predict',
089     legend => 'hwpredict',
090   },
091   draw           => {
092     type   => "hidden",
093     cfunc  => 'DEVPREDICT',
094     name   => 'dev',
095   },
096   draw           => {
097     type   => "hidden",
098     name   => "failures",
099     cfunc  => 'FAILURES',
100   },
101   tick => {
102     draw => "failures",
103     color  => '#FF0000',
104      legend => "Failures",
105   },
106   draw => {
107     type   => "line",
108     color  => '0000FF',
109     legend => "Upper Bound",
110     cdef   => "predict,dev,2,*,+",
111   },
112   draw => {
113     type   => "line",
114     color  => '0000FF',
115     legend => "Lower Bound",
116     cdef   => "predict,dev,2,*,-",
117   },
118 );

Die While-Schleife ab Zeile 20 iteriert durch die Logzeilen, und das Regex-Pattern in Zeile 21 erfasst Zeilen mit Temperatureinträgen und lässt andere, wie zum Beispiel die Start- und Stopp-Nachrichten, außen vor.

Alle so gefundenen Messwerte speichert Listing 3 in dem Array »@data_points« zusammen mit den jeweiligen Zeitstempeln. Ab Zeile 32 geht dann RRDTool zu Werke und definiert zunächst eine neue Round-Robin-Datenbank [8] mit genügend Einträgen für 5 Monate. Zur Glättung von Ausrutschern fasst es jeweils fünf Minutenwerte zu einem Datenbankwert zusammen, dazu dient der »step«-Wert in Zeile 41.

Als Datentyp definiert es »GAUGE«, den Allerweltstyp für numerische Werte in RRDTool. Die For-Schleife ab Zeile 63 füttert dann die in »@data_points« zwischengespeicherten Werte mit ihren Zeitstempeln mit Hilfe der Methode »update()« in die RRD-Datenbank. Der Aufruf der Methode »graph()« ab Zeile 71 zeichnet schließlich ein Diagramm (Abbildung 4). Er beschriftet auch gleich die Achsen und skaliert sie entsprechend den Messwerten und Datumsangaben.

Das Auf und Ab im Graphen spiegelt die täglichen Schwankungen der Zimmertemperatur wider. Um aber festzustellen, ob ein Ausreißer wegen unvorhergesehener Ereignisse vorliegt - wenn sich zum Beispiel die Katze auf den Sensor legt oder das Gebäude in Flammen steht -, genügt es nicht, die absoluten Werte zu vergleichen, da diese nicht konstant bleiben. RRDTool bietet deswegen die so genannte Aberrant Behavior Detection an, die mit Hilfe von vier Parametern normales Verhalten vorhersagt und dann eintreffende Werte mit der Prognose vergleicht. Das Tool lernt aus den vergangenen Ereignissen und gibt Prognosen für das künftige Verhalten ab.

Stimmt in einem vordefinierten Zeitfenster eine definierbare Anzahl von Vorhersagen nicht mit der Wirklichkeit überein, löst das System Fehler aus, die im Diagramm in Abbildung 4 rot eingezeichnet sind. Die Abbildung zeichnet die Messwerte schwarz, die Prognose grün und die erlaubte Bandbreite um die Prognose, in denen ein Messwert noch als normal gilt, blau. Alarme erscheinen als rote Linien am Fuß des Graphen.

Abbildung 4: Der Graph mit den Messwerten (schwarz), Holt-Winters-Forecasting (grün), dem erlaubten Wertebereich innerhalb der Prognose (blau) und den ausgelösten Alarmen (rot).

Abbildung 4: Der Graph mit den Messwerten (schwarz), Holt-Winters-Forecasting (grün), dem erlaubten Wertebereich innerhalb der Prognose (blau) und den ausgelösten Alarmen (rot).

Leider löst das Verfahren auch Fehlalarme aus (wie zum Beispiel am Mittag des dritten Tages) und auch richtige Fehler erkennt es nicht immer zuverlässig. Der Admin spielt dann so lange an den vier Knöpfen herum, bis sich ein zufriedenstellendes Ergebnis zeigt. Das ist natürlich keine Garantie dafür, dass nicht schon am nächsten Tag wieder ein Fehlalarm ausgelöst wird, und das Drehen an den Knöpfen gleicht eher Zauberei als einer Ingenieurswissenschaft.

An Knöpfen drehen

Drehen darf der Admin an den Parametern »alpha«, »beta« und »gamma« (jeweils zwischen 0 und 1, ausschließlich) sowie an der Länge der Seasonal Period, also jenem Zeitraum, in dem sich Ereignisse wiederholen, zum Beispiel einem Tagesturnus für Temperaturen. Kleine Werte - also nahe null - für »alpha«, »beta« und »gamma« richten das Augenmerk auf Ereignisse, die schon etwas zurückliegen, während bei Werten nahe 1 die Vorhersage nahe an kürzlich gesichteten Werten liegt.

Während »alpha« die Prognose des Basiswerts des Graphen kontrolliert, arbeitet »beta« mit der Steigung des Graphen, »gamma« bestimmt die Prognose bei Wiederholungen in definierten Zeitfenstern. Ein Beispiel könnte »alpha=0.1«, »beta= 0.0035«, »gamma=0.5« und die Länge des saisonalen Zeitrahmens auf die Zahl der von RRDTool im Laufe eines Tages gesammelten Messwerte setzen.

Einen Fehler meldet das System, falls während eines »window_length« langen Zeitfensters eine Anzahl »threshold« oder mehr Messpunkte außerhalb des Confidence Band, also des blauen Bandes um die Prognose, liegen. Wie breit dieses Akzeptanzband genau ist, ermittelt RRDTool automatisch und lässt sich dabei weder in die Karten sehen noch gar beeinflussen.

Diesen Artikel als PDF kaufen

Als digitales Abo

Als PDF im Abo bestellen

comments powered by Disqus

Ausgabe 07/2013

Preis € 6,40

Insecurity Bulletin

Insecurity Bulletin

Im Insecurity Bulletin widmet sich Mark Vogelsberger aktuellen Sicherheitslücken sowie Hintergründen und Security-Grundlagen. mehr...

Linux-Magazin auf Facebook