Open Source im professionellen Einsatz
Linux-Magazin 01/2003

Logging nach Bedarf mit Log::Log4perl

Wachsame Schläfer

Mit Log::Log4perl lassen sich in Programme Log-Anweisungen einbauen, die bei der normalen Programmausführung schlafen. Besteht Bedarf, steuert eine externe Konfigurationsdatei das Erwachen der Schläfer. Sie zeigen an, was das Programm so treibt, ohne dass man dessen Code ändern muss.

992

Log::Log4perl ist ein Perl-Port des aus der Java-Welt stammenden Log4j-Systems, das auf drei Säulen steht: Logger lösen Log-Nachrichten aus, Prioritäten bestimmen, ob sie durchkommen und Appender leiten sie dann an konfigurierte Ausgabemedien weiter.

Die Prioritäten steuern, ob ein Logger die ihm übergebenen Nachrichten tatsächlich rausschreibt oder unterdrückt. Log::Log4perl bietet fünf Prioritäten: »DEBUG«, »INFO«, »WARN«, »ERROR« und »FATAL«. Wenn die Zentrale sagt, dass sie nur Nachrichten der Priorität »ERROR« und höher sehen will, sorgt Log::Log4perl dafür, dass mit »DEBUG«, »INFO« oder »WARN« geloggte Nachrichten gar nicht erst auftauchen. Sie stehen zwar im Code, werden aber zur Laufzeit unterdrückt.

Zum Logger gehören Kategorien, die typischerweise nach der Klasse benannt sind, in der sie ihre Dienste anbieten. Die Klasse »Riegel::Twix« wird also meist eine Instanz des Loggers der Kategorie »Riegel.Twix« nutzen. Der Knüller: Alle Logger eines Systems (die wahrscheinlich in Dutzenden verschiedener Klassen liegen und demnach Dutzenden von verschiedenen Kategorien angehören) lassen sich von einer zentralen Stelle ansprechen und fernsteuern.

Treten Probleme in »Riegel::Twix« auf, muss nicht das ganze System in den Debug-Modus, es reicht bereits aus, ein detailliertes Logging in der Kategorie »Riegel« anzuwerfen. Entsprechend springen die Logger der Kategorien »Riegel« und »Riegel.Twix« an. Dazu muss man nicht etwa den Code ändern, es genügt völlig, eine zentrale Konfigurationsdatei anzupassen.

Loggen für Faule

Das Tutorial auf [2] zeigt die Anwendung von Log::Log4perl im Detail. Heute ist "Loggen für Faule" dran - alle Vorzüge von Log4perl ohne viel Aufwand. Listing 1 (»Building.pm«) zeigt als Beispiel eine typische Perl-Anwendung: zwei Klassen, die die Temperatur eines Atomkraftwerks regeln und in einer Wohnung den Fernseher an- und ausschalten. Die Methoden sind gespickt mit Logging-Anweisungen: »DEBUG()«, »INFO()«, »ERROR()« sind alles Funktionen aus Log::Log4perl\'s »:easy«-Fundus, die alle zunächst inaktiv sind.

Die Basisklasse »Building« definiert den Konstruktor »new()«, den die abgeleiteten Klassen einfach erben. Die Klasse »Building::NuclearPowerPlant« abstrahiert ein Atomkraftwerk mit den Methoden »temperature()« zum Setzen und Abfragen der Reaktortemperatur und »is_ok()« für die Prüfung, ob noch alles im grünen Bereich läuft.

Die Klasse »Building::Residential« ahmt dagegen ein Privathaus nach und ist von der Basisklasse »Building« abgeleitet. Die Methode »tv("on"|"off")« schaltet den Fernseher im Wohnzimmer auf Befehl an und aus.

Listing 1:
>>Building.pm<<

01 #!/usr/bin/perl
02 ###########################################
03 # Mike Schilli, 2002 (m@perlmeister.com)
04 ###########################################
05 use warnings;
06 use strict;
07 
08 ###########################################
09 package Building;
10 ###########################################
11 use Log::Log4perl qw(:easy);
12 sub new {
13     my($class) = @_;
14     DEBUG("Create new $class");
15     bless {}, $class;
16 }
17 
18 ###########################################
19 package Building::NuclearPowerPlant;
20 ###########################################
21 use Log::Log4perl qw(:easy);
22 our @ISA = qw(Building);
23 
24 ###########################################
25 sub temperature {
26     my($self, $temp) = @_;
27 
28     if(defined $temp) {
29         DEBUG("Set temperature to $temp");
30         $self->{temp} = $temp;
31         $self->is_ok();
32     }
33 
34     return $self->{temp};
35 }
36 
37 ###########################################
38 sub is_ok {
39     my($self) = @_;
40     if(defined $self->{temp} and
41        $self->{temp} > 100) {
42         ERROR("I'm exploding!");
43         return 0;
44     }
45     INFO("OK");
46     return 1;
47 }
48 
49 ###########################################
50 package Building::Residential;
51 ###########################################
52 use Log::Log4perl qw(:easy);
53 our @ISA = qw(Building);
54 
55 ###########################################
56 sub tv {
57     my($self, $action) = @_;
58 
59     if(defined $action) {
60         DEBUG("Set tv to $action");
61         $self->{tv} = $action;
62     }
63 
64     INFO("TV is $self->{tv}");
65     return $self->{tv};
66 }
67 
68 1;

Aufpasser hinter den Kulissen

Alle drei Klassen ziehen dabei jeweils (!) »Log::Log4perl qw(:easy)« herein, um hinter den Kulissen Default-Logger zu erzeugen, die einfach auf die Kategorie des jeweiligen Klassennamens hören. Die auf gleiche Weise exportierten Funktionen »DEBUG()«, »INFO()«, »ERROR()« und weitere gelangen ebenfalls über das »:easy«-Tag in den Namensraum der jeweiligen Klasse.

Listing 2 (»building.pl«) zeigt ein Skript, das die Klassen verwendet. Auf der Kommandozeile nimmt es optional ein Argument entgegen, das die Log4perl-Konfigurationsdatei bestimmt. Im Format von Java-Properties-Dateien lässt sich Log4perl so bequem von außen fernsteuern. Findet »building.pl« allerdings keine Angabe, wird Log4perl nicht initialisiert, was im »:easy«-Modus seit Version 0.25 einfach alle Log-Anweisungen schlafen legt.

Von der Kommandozeile ohne Argument aufgerufen, erledigt »building.pl« zwar bereitwillig seine Aufgaben, zeigt allerdings nichts an:

$ building.pl
$


Wer trotzdem wissen will, was so im Einzelnen abgeht, der sollte sich eine Log4perl-Konfigurationsdatei nach »info .conf« anlegen. »info.conf« bestimmt, dass die Logger in der Kategorie »Building« und in allen ihren Unterklassen (also in diesem Beispiel die in »Building«, »Building::Residential« und »Building::NuclearPowerPlant« verwendeten Logger) zu schreiben beginnen, und zwar nur Nachrichten mit mindestens der Priorität »INFO«.

Der Appender »Screen« ist vom Typ »Log::Dispatch::Screen« und leitet einfach alle durchgelassenen Nachrichten nach »STDERR« weiter. Das Pattern-Layout legt mit

%d [%c]: %m%n


fest, dass jeder Nachricht (»%m«) zuerst das aktuelle Datum (»%d«) und die Logger-Kategorie (»%c«) vorangeht, während stets ein Zeilenumbruch (»%n«) nachfolgt.

Es folgt die Ausgabe des Programms »building.pl« (nach »STDERR«), nachdem es mit dem Parameter »info.conf« aufgerufen wurde:

2002/10/05 21:36:50  [Building.Residential]: TV is on
2002/10/05 21:36:50  [Building.NuclearPowerPlant]: I'm exploding!


Die »DEBUG«-Nachrichten werden, wie man sieht, unterdrückt. Hieße Zeile 1 in »info.conf« hingegen

1 log4perl.category.Building=DEBUG, Screen


kämen auch sie durch, wie die Ausgabe in Listing 4 zeigt.

Listing 2:
>>building.pl<<

01 #!/usr/bin/perl
02 ###########################################
03 # Mike Schilli, 2002 (m@perlmeister.com)
04 ###########################################
05 use warnings;
06 use strict;
07 
08 use Building;
09 use Log::Log4perl qw(:easy);
10 
11 if($ARGV[0]) {
12     Log::Log4perl->init($ARGV[0]);
13 }
14 
15 my $plant = Building::NuclearPowerPlant->new();
16 my $home  = Building::Residential->new();
17 
18    # Switch TV on
19 $home->tv("on");
20    # Overheat nuklear power plant
21 $plant->temperature(200);

Listing 3:
>>info.conf<<

01 log4perl.category.Building = INFO, Screen
02 log4perl.appender.Screen   = Log::Dispatch::Screen
03 log4perl.appender.Screen.layout  = PatternLayout
04 log4perl.appender.Screen.layout.ConversionPattern =  %d [%c]: %m%n

Listing 4:
Geschwätziges Log4perl

01 2002/10/06 15:11:13 [Building]: Create new Building::NuclearPowerPlant
02 2002/10/06 15:11:13 [Building]: Create new Building::Residential
03 2002/10/06 15:11:13 [Building.Residential]:  Set tv to on
04 2002/10/06 15:11:13 [Building.Residential]: TV is on
05 2002/10/06 15:11:13 [Building.NuclearPowerPlant]:  Set temperature to 200
06 2002/10/06 15:11:13 [Building.NuclearPowerPlant]:  I'm exploding!

Linux-Magazin kaufen

Einzelne Ausgabe
 
Abonnements
 
TABLET & SMARTPHONE APPS
Bald erhältlich
Get it on Google Play

Deutschland

Ähnliche Artikel

  • Laufzeit-Tacho

    Statt hochgezüchteter Prozessoren helfen oft schon simple Tricks, um Programme zu beschleunigen. Profiler können Engpässe entdecken, in die es sich lohnt, Entwicklungszeit zu investieren.

  • Geiz ist geil

    Ein Perl-Skript verfolgt für Schnäppchenjäger die Preisentwicklung auf Amazon und schlägt per E-Mail freudig Alarm, falls sich überwachte Produkte plötzlich verbilligen.

  • Perl-Snapshot

    Mit Clonezilla gehen Systembackups und Restores mit nur wenigen Tastendrücken elegant von der Hand. Eine selbst produzierte Lösung reduziert den Aufwand auf das Einlegen einer CD, auf die der Admin zuvor ein Perl-Skript gebrannt hat.

  • Perl-Screencast 10/2014

    In diesem Screencast geht es um die Automation des Build-Prozeses mit einem Jenkins-Server und ein paar Perl-Skripten.

  • E-Baywatcher

    Wer in letzter Sekunde in Versteigerungen eingreifen will, lässt sich rechtzeitig von einem Perl-Agenten daran erinnern. Der Agent sucht auf Ebay nach Stichworten und informiert seinen Mandanten sofort per Instant Message, wenn sich eine passende Auktion dem Ende nähert.

comments powered by Disqus

Stellenmarkt

Artikelserien und interessante Workshops aus dem Magazin können Sie hier als Bundle erwerben.