Teil von SELFHTML aktuell Teil von Artikel Teil von Serverkonfiguration Teil von SELFHTML Server Konfiguration

SELFHTML Server Konfiguration:
Logfile-Auswertung

nach unten Einleitung
nach unten Die Script-Auswertung
nach unten Die Webalizer-Auswertung

Einleitung

Dieses Kapitel bezieht sich hauptsächlich auf die Auswertung der Apache-Logfiles. Diese Logfiles sind im combined-Format abgespeichert, da damit so ziemlich alle gängigen Programme klarkommen.

Die Logfiles sollten auf mehrere Gesichtspunkte hin ausgewertet werden: Traffic, Referrer und Suchbegriffe. Die Suchbegriffe sollten dabei einerseits von externen Suchmaschinen ausgewertet werden, sprich, wir wollten wissen, welche Suchbegriffe Hits auf uns liefern und andererseits wollten wir wissen, wie unsere SELFHTML-Suche benutzt wird.

nach obennach unten

Die Script-Auswertung

Diese Auswertung war aus mehreren Gründen nötig: wir brauchten eine Auswertung des Gesamt-Traffics, eine Übersichtsseite über alle Subdomains und außerdem brauchten wir eine Auswertung der Suchbegriffe unserer SELFHTML-Suche.

So gibt es insgesamt zwei Scripts: eines um die Übersichtsseite und den Gesamt-Traffic auszuwerten und eines um die Suchbegriffe herauszufiltern. Diese Scripte will ich kurz vorstellen.

Als erstes das Script zur Generierung der Übersichtsseite. Dieses Script hat im Grunde zwei Aufgaben: es soll pro konfigurierter Domain den Webalizer starten (nach Wunsch) und eine Übersichtsseite generieren. Dazu besteht es im Grunde aus vier Teilen:

Die ersten beiden Schritte werden im Grunde direkt nacheinander ausgefuehrt, da sie eng zusammen gehöhren. für jeden weiteren Schritt gibt es eine Funktion, die nacheinander ausgeführt werden:

#!/usr/bin/perl -w

use strict;
use vars qw($VERSION $CONFIG @LIBPATH $TPL $HISTFILE $INDFILE);

BEGIN
 {
  $VERSION = '0.5';
  $CONFIG  = '/home/cron/logrolling/config/rolling.xml';
  @LIBPATH = qw(/home/www/teamone.de/selfaktuell/cgi-bin/shared);
  $TPL     = '/home/cron/logrolling/config/templates/';
  $HISTFILE= '/home/cron/logrolling/files/histfile.dat';
  $INDFILE = '/home/www/teamone.de/webalizer/dokumente/index.html';
 }

use lib @LIBPATH;

use XML::Simple;           # wegen der Konfiguration
use Newsletter::Template;  # Modul zur Generierung des HTMLs

# forward deklarationen
sub stat_it($);
sub get_traffics(%);
sub write_histfile(%);
sub generate_html(%%);

# variablen-initialisierung
my $config      = XMLin($CONFIG);
my %href        = ();
my %traffics    = ();
$traffics{all}  = 0;

# jede konfigurierte Domain durchiterieren
foreach my $domain (@{$config->{log}})
 {
  print `$config->{webalizer} -c $domain->{conf}`; # webalizer starten
  my $traffic     = stat_it $domain;               # logfiles haendisch auswerten
  $href{$domain->{domain}} = $domain->{href};      # noetig um das HTML zu generieren

  $traffics{all} += $traffic;                      # Traffic zusammenzaehlen
  $traffics{$domain->{domain}} += $traffic;        # Traffic fuer die Domain dazuaddieren
 }

%traffics = get_traffics(\%traffics);              # Traffic aus der History-File dazu
generate_html(\%traffics,\%href);                  # HTML generieren
write_histfile(\%traffics);                        # Die History-File schreiben


###########################################
#
# Diese Funktion generiert das HTML.
#
sub generate_html(%%)
 {
  my $traffics    = shift;
  my $tpl_index   = new Newsletter::Template($TPL.'index.html');
  my $tpl_domains = new Newsletter::Template($TPL.'domains.html');
  my $traffic_all = delete $traffics->{all};

  $traffic_all    = 0;
  foreach(keys %{$traffics})
   {
    $traffic_all += $traffics->{$_};
   }

  $tpl_index->readin;
  $tpl_domains->readin;

  $tpl_index->assign(DOMAINS     => '');

  my $aktyear  = '';
  foreach my $domain (sort keys %{$traffics})
   {
    my ($dmn) = grep { $domain eq $_->{domain} } @{$config->{log}};
    if($dmn->{index} && $dmn->{index} eq "no") {
      next;
    }

    $tpl_domains->assign(DOMAIN  => $domain);
    $tpl_domains->assign(HREF    => $href{$domain});
    $tpl_domains->assign(TRAFFIC => sprintf("%.2f",$traffics->{$domain}/1024));

    $tpl_domains->parse;
    $tpl_index->append(DOMAINS   => $tpl_domains->as_string);
   }

  $tpl_index->assign(DATE    => scalar localtime);
  $tpl_index->assign(TRAFFIC => sprintf("%.2f",$traffic_all/1024));
  $tpl_index->assign(VERSION => $VERSION);
  $tpl_index->parse;

  open DAT, '>'.$INDFILE or die $INDFILE,': ',$!;
  print DAT $tpl_index->as_string;
  close DAT;

 }

###########################################
#
# Diese Funktion schreibt die History-File zurueck
#
sub write_histfile(%)
 {
  my $traffic = shift;
  local *DAT;

  open DAT, '>'.$HISTFILE or die $HISTFILE,': ',$!;

  foreach my $domain (keys %{$traffic})
   {
    print DAT $domain,':',$traffic->{$domain},"\n";
   }

  close DAT;
 }

###########################################
#
# Diese Funktion liest die History-File wieder ein und addiert den Traffic dazu
#
sub get_traffics(%)
 {
  my %traffics = %{shift @_};

  open DAT,'<'.$HISTFILE or die $HISTFILE,': ',$!;

  my $aktd = '';
  while(<DAT>)
   {
    next if /^\s*#/ || /^\s*$/; # comments and empty lines

    next unless /^\s*([^:\s]+):\s*(\d+)/;

    if($traffics{$1})
     {
      $traffics{$1} += $2;
     }
    else
     {
      $traffics{$1}  = $2;
     }
   }


  close DAT;
  return %traffics;
 }


###########################################
#
# Diese Funktion wertet die Logfile aus
#
sub stat_it($)
 {
  my $entry   = shift;
  my $traffic = 0;

  local *DAT;

  open DAT,$entry->{dir}.'/access-log' or die $entry->{dir},': ',$!;

  while(<DAT>)
   {
    next unless m!^\S+ \S+ \S+ \[[^\]]+\] "GET /([^"]+) HTTP/1.[10]" (\d+) (\d+) "[^"]+" "[^"]+"$!;
#    next if /\.(?:gif|jpg|png)/;

    $traffic += $3 if $3;
   }

  close DAT;

  return $traffic;
 }


# eof

Die Konfigurations-Datei ist (der Einfachheit halber) auch eine XML-Datei:

config.xml:

<?xml version="1.0"?>
<!DOCTYPE logs SYSTEM "logs.dtd">

<logs>
 <log
    href="www"
    domain="www.teamone.de"
    dir="/home/www/teamone.de/www/logs/"
    archive="/usr/backup/logs/www.tgz"
    gzip="yes"
    conf="/home/cron/logrolling/config/webalizer/www.conf"
    />

 <log
    href="alpentouren"
    domain="alpentouren.teamone.de"
    dir="/home/www/teamone.de/alpentouren/logs/"
    archive="/usr/backup/logs/alpentouren.tgz"
    gzip="yes"
    conf="/home/cron/logrolling/config/webalizer/alpentouren.conf"
    />

 <log
    href="rhps"
    domain="rhps.teamone.de"
    dir="/home/www/teamone.de/rockyhorrorpictureshow/logs/"
    archive="/usr/backup/logs/rhps.tgz"
    gzip="yes"
    conf="/home/cron/logrolling/config/webalizer/rhps.conf"
    />

 <log
    href="selfaktuell"
    domain="aktuell.de.selfhtml.org"
    dir="/home/www/teamone.de/selfaktuell/logs/"
    archive="/usr/backup/logs/selfaktuell.tgz"
    gzip="yes"
    conf="/home/cron/logrolling/config/webalizer/selfaktuell.conf"
    />

 <log
    domain="developer.selfhtml.org"
    index="no"
    dir="/home/www/teamone.de/selfdeveloper/logs/"
    archive="/usr/backup/logs/selfdeveloper.tgz"
    gzip="yes"
    conf="/home/cron/logrolling/config/webalizer/selfdeveloper.conf"
    />

 <log
    href="selffan"
    domain="selffan.teamone.de"
    dir="/home/www/teamone.de/selffan/logs/"
    archive="/usr/backup/logs/selffan.tgz"
    gzip="yes"
    conf="/home/cron/logrolling/config/webalizer/selffan.conf"
    />

 <log href="selfforum"
    domain="forum.de.selfhtml.org"
    dir="/home/www/teamone.de/selfforum/logs/"
    archive="/usr/backup/logs/selfforum.tgz"
    gzip="yes"
    conf="/home/cron/logrolling/config/webalizer/selfforum.conf"
    />

 <log
    href="selfhtml"
    domain="de.selfhtml.org"
    dir="/home/www/teamone.dehttp://de.selfhtml.org/logs/"
    archive="/usr/backup/logs/selfhtml.tgz"
    gzip="yes"
    conf="/home/cron/logrolling/config/webalizer/selfhtml.conf"
    />

 <log
    href="selfsuche"
    domain="suche.de.selfhtml.org"
    dir="/home/www/teamone.de/selfsuche/logs/"
    archive="/usr/backup/logs/selfsuche.tgz"
    gzip="yes"
    conf="/home/cron/logrolling/config/webalizer/selfsuche.conf"
    />

 <log
    href="webalizer"
    domain="stats.teamone.de/webalizer"
    dir="/home/www/teamone.de/webalizer/logs/"
    archive="/usr/backup/logs/webalizer.tgz"
    gzip="yes"
    conf="/home/cron/logrolling/config/webalizer/webalizer.conf"
    />

 <log
    href="selfhtml.fr"
    domain="selfhtml.selfhtml.com.fr"
    dir="/home/www/selfhtml.com.frhttp://de.selfhtml.org/logs/"
    archive="/usr/backup/logs/selfhtml.fr.tgz"
    gzip="yes"
    conf="/home/cron/logrolling/config/webalizer/selfhtml.fr.conf"
    />

 <log
    href="selfaktuell.fr"
    domain="www.selfhtml.com.fr"
    dir="/home/www/selfhtml.com.fr/www/logs/"
    archive="/usr/backup/logs/selfaktuell.fr.tgz"
    gzip="yes"
    conf="/home/cron/logrolling/config/webalizer/selfaktuell.fr.conf"
    />

 <log
    href="selfforum.fr"
    domain="selfforum.selfhtml.com.fr"
    dir="/home/www/selfhtml.com.fr/selfforum/logs/"
    archive="/usr/backup/logs/selfforum.fr.tgz"
    gzip="yes"
    conf="/home/cron/logrolling/config/webalizer/selfforum.fr.conf"
    />

 <log
    href="recherche"
    domain="recherche.selfhtml.com.fr"
    dir="/home/www/selfhtml.com.fr/recherche/logs/"
    archive="/usr/backup/logs/recherche.tgz"
    gzip="yes"
    conf="/home/cron/logrolling/config/webalizer/recherche.conf"
    />

 <apache>/usr/local/sbin/apachectl</apache>
 <webalizer>/usr/local/bin/de-webalizer</webalizer>
</logs>

logs.dtd:
<!ELEMENT logs (log+,apache,webalizer)>
  <!ELEMENT log EMPTY>
  <!ATTLIST log
            href    CDATA   #REQUIRED
            domain  CDATA   #REQUIRED
            dir     CDATA   #REQUIRED
            archive CDATA   #REQUIRED
            gzip    CDATA   #REQUIRED
            conf    CDATA   #REQUIRED
            >

     <!ELEMENT apache (#PCDATA)>
     <!ELEMENT webalizer (#PCDATA)>

Einige Konfigurations-Elemente sind schon für das Logrolling-Script, das ich später nochmal erwähnen werde. Das Script sollte im Grunde bugfrei sein, ich bin allerdings natürlich froh über jede Verbesserung.

Als nächstes möchte ich das Script vorstellen, das die Suchbegriffe auswertet. Dieses Script hat lediglich zwei Aufgaben: die Logfiles durchgehen und entsprechend die Suchbegriffe in einer History-File festhalten und die 500 am meisten gesuchten Begriffe ins HTML schreiben. Entsprechend einfach ist es auch:

#!/usr/bin/perl -w

use strict;
use vars qw($VERSION @LIBPATH $CONF);

BEGIN
 {
  $VERSION = '0.1';
  @LIBPATH =   @LIBPATH = qw(/home/www/teamone.de/selfaktuell/cgi-bin/shared);
  $CONF    = '/home/cron/logrolling/config/search.xml';
 }

use lib @LIBPATH;

use XML::Simple;          # Fuer die Konfiguration
use Newsletter::Template; # Zum generieren des HTMLs
use HTML::Entities;       # Um die Suchbegriffe korrekt zu escapen

# Forward-Deklarationen
sub generate_html($%%);
sub write_histfile($%);
sub decode($);

my $config     = XMLin($CONF);
my %ausdruecke = ();

# alle Suchmaschinen durchgehen
foreach my $searcher (keys %{$config->{searcher}})
 {
  # History-File einlesen
  open DAT, '<'.$config->{searcher}->{$searcher}->{histfile} or die $!;
  while(<DAT>)
   {
    next unless /^\s*(.+):(\d+)\s*$/;
    $ausdruecke{$1} = $2;
   }
  close DAT;

  # Logfile auswerten
  open DAT, '<'.$config->{searcher}->{$searcher}->{logfile} or die $!;
  while(<DAT>)
   {
    next unless m!/cgi-bin/such.pl\?suchausdruck=([^&]+)!;
    $ausdruecke{decode($1)}++;
   }
  close DAT;

  generate_html($searcher,$config,\%ausdruecke); # HTML generieren
  write_histfile($config->{searcher}->{$searcher}->{histfile},\%ausdruecke); # History-Files schreiben
  %ausdruecke = (); # Ausdruecke resetten
 }


###########################################
#
# Diese Funktion generiert das HTML.
#
sub generate_html($%%)
 {
  my $name       = shift;
  my $conf       = shift;
  my $ausdruecke = shift;
  my $tpl_index  = new Newsletter::Template($conf->{templatedir}.'/in_se.html');
  my $tpl_row    = new Newsletter::Template($conf->{templatedir}.'/row.html');

  $tpl_index->readin;
  $tpl_row->readin;

  $tpl_index->assign(ROWS => '');

  my $i          = 0;
  foreach my $ausdruck (sort { $ausdruecke->{$b} <=> $ausdruecke->{$a} } keys %{$ausdruecke})
   {
    last if $i == ($ARGV[0] ? $ARGV[0] : 500);
    $i++;

    $tpl_row->assign(TERM    => encode_entities($ausdruck));
    $tpl_row->assign(NUM     => encode_entities($ausdruecke->{$ausdruck}));

    $tpl_row->parse;

    $tpl_index->append(ROWS  => $tpl_row->as_string);
   }

  $tpl_index->assign(NAME    => $name);
  $tpl_index->assign(VERSION => $VERSION);
  $tpl_index->assign(DATE    => scalar localtime);

  $tpl_index->parse;
  open DAT,'>'.$conf->{searcher}->{$name}->{out} or die $!;
  print DAT $tpl_index->as_string;
  close DAT;

 }

###########################################
#
# Diese Funktion schreibt die History-Files zurueck
#
sub write_histfile($%)
 {
  my $fname      = shift;
  my $ausdruecke = shift;

  open DAT, '>'.$fname or die $!;

  my $i = 0;
  foreach my $ausdruck (sort { $ausdruecke->{$a} <=> $ausdruecke->{$b} } keys %{$ausdruecke})
   {
    print DAT $ausdruck,':',$ausdruecke->{$ausdruck},"\n";
   }

  close DAT;
 }


###########################################
#
# Diese dekodiert die URL-encodierten Ausdruecke
#
sub decode($)
 {
  my $txt = shift;
  $txt =~ tr/+/ /;
  $txt =~ s/%([a-f0-9]{2})/chr(hex($1))/ieg;

  return $txt;
 }


# eof

Natürlich ist die Konfigurations-Datei auch eine XML-Datei:

search.xml:

<?xml version="1.0"?>
<!DOCTYPE searchers SYSTEM "searchers.dtd">

<searchers>
 <templatedir>/home/cron/logrolling/config/templates/</templatedir>

 <searcher name="selfsuche">
  <logfile>/home/www/teamone.de/selfsuche/logs/access-log</logfile>
  <histfile>/home/cron/logrolling/files/searchers_hist_selfsuche.dat</histfile>
  <out>/home/www/teamone.de/webalizer/dokumente/selfsuche/ausdruecke.html</out>
 </searcher>

 <searcher name="recherche">
  <logfile>/home/www/selfhtml.com.fr/recherche/logs/access-log</logfile>
  <histfile>/home/cron/logrolling/files/searchers_hist_recherche.dat</histfile>
  <out>/home/www/teamone.de/webalizer/dokumente/recherche/ausdruecke.html</out>
 </searcher>
</searchers>

searchers.dtd:
<!ELEMENT searchers (templatedir,searcher+)>
   <!ELEMENT templatedir (#PCDATA)>
   <!ELEMENT searcher (logfile,histfile,out)>
   <!ATTLIST searcher
             name   CDATA   #REQUIRED
             >

   <!ELEMENT logfile  (#PCDATA)>
   <!ELEMENT histfile (#PCDATA)>
   <!ELEMENT out      (#PCDATA)>

Auch dieses Script sollte theoretisch bugfrei sein, doch auch hier freue ich mich über Verbesserungen.

nach obennach unten

Die Webalizer-Auswertung

Die Webalizer-Auswertung ist im Grunde eine leicht modifizierte Standard-Konfiguration. Wichtig ist nur zu beachten, das die Option Incremental auf yes gesetzt wird, da sonst keine inkrementellen Auswertungen gefahren werden können.

weiter Seite Das Backup-Konzept

zurück Seite Userverwaltung und Rechtevergabe

Teil von SELFHTML aktuell Teil von Artikel Teil von Serverkonfiguration Teil von SELFHTML Server Konfiguration

© 2007 bereichsübergreifende Seite Impressum