Publié le 04/12/2012
Auteur Fobec
Réseaux sociaux
0 partages
0 tweets
0 plus
0 commentaires

Analyser le fichier logs de Apache

L'ensemble du trafic d'un serveur Apache est enregistré dans un fichier log. Chaque ligne contient une foule d'information sur chaque requête que ce soit le format du fichier demandé, le référent ou encore l'adresse IP. En général, les logs sont accessibles chez les grands hébergeurs. Voyons comment construire un analyseur de trafic en temps réel de son site web en PHP.

La class ApacheLog Parser

Le but de la Class est de parcourir chaque ligne du fichier logs et d'en extraire les valeurs dans un tableau. Pour faciliter le filtrage, 3 fonctions ont été ajoutées:
- open(): ouvre le fichier et lancer l'analyse. Le format log ou compressé gz est accepté. L'utilisation du paramètre CallBack fixe la règle de filtrage,
- getCurrentFile(): retourne le fichier log en cours,
- setParseFormat(): optionnel, modifie la méthode de parsing, lorsque le format est de type long.
<?php
/**
 * ApacheLog_Parser : parser le fichier log de Apache
 *
 * @author Fobec 12/2012
 * @copyright http://www.fobec.com/php5/1120/analyser-fichier-logs-apache.html
 */
class ApacheLog_Parser {
 
    const PARSE_FORMAT_CLASSIC='short';
    const PARSE_FORMAT_LONG='server';
    private $parseFormat=self::PARSE_FORMAT_CLASSIC;
 
/**
 * Analyse le fichier log
 * @param String $filename
 * @param function $callback
 * @return Array
 */
    public function open($filename,$callback=NULL) {
        if (!is_readable($filename)) {
            throw new Exception('File '.$file.' could not be open !!!');
        }
 
        if ($callback!=NULL && is_callable($callback)==FALSE) {
            throw new Exception('Invalid Callback !!!');
        }
 
        $ext=strtolower(strrchr($filename,'.'));
        if ($ext=='.gz') {
            return $this->openfile_gz($filename,$callback);
        } else {
            return $this->openfile($filename,$callback);
        }
    }
/**
 * Trouver le fichier log du jour
 * @param String $path dossier fichier log
 * @return String
 */
    public function getCurrentFile($path) {
        $curfile=array('date'=>0,'name'>'');
        //dossier inaccessible
        $dh = opendir($path);
        if (!$dh) {
            throw new Exception('Path '.$path.' could not be open !!!');
        }
 
        while (($file = readdir($dh)) !== false) {
            if ($file!='.'&&$file!='..') {
                $dt=filemtime($path.$file);
                if ($file!='.htaccess' && $dt>$curfile['date'] && strpos($file, 'access')!== false) {
                    $curfile['date']=$dt;
                    $curfile['name']=$path.$file;
                }
            }
        }
        closedir($dh);
 
        return $curfile['name'];
    }
/**
 * Fixer le format des lignes Apache
 * @param <type> $parseFormat
 */
    public function setParseFormat($parseFormat) {
        $this->parseFormat=$parseFormat;
    }
 
 
/*******************************************************************************
 * Private
 *******************************************************************************/
 
/**
 * Ouvrir fichier non compressé
 * @param <type> $filename
 * @param <type> $callback
 * @return <type>
 */
    private function openfile($filename,$callback=NULL) {
        $ar=array();
        $handle = fopen($filename, 'r');
        $n=array();
        while (!feof($handle)     ) {
            $buf = fgets($handle);
            $n=$this->parse($buf);
            if ($n!=NULL && $callback!=NULL) {
                $bool=call_user_func($callback, $n);
            } else {
                $bool=($n!=NULL);
            }
            if ($bool) {
                $ar[]=$n;
            }
        }
        fclose($handle);
        return $ar;
    }
/**
 * Ouvrir fichier compressé gz
 * @param <type> $filename
 * @param <type> $callback
 * @return <type>
 */
    private function openfile_gz($filename,$callback=NULL) {
        $ar=array();
        $handle = gzopen($filename, 'r');
        while (!gzeof($handle)) {
            $buf = gzgets($handle, 4096);
            $n=$this->parse($buf);
            if ($n!=NULL && $callback!=NULL) {
                $bool=call_user_func($callback, $n);
            } else {
                $bool=($n!=NULL);
            }
            if ($bool) {
                $ar[]=$n;
            }
        }
        gzclose($handle);
        return $ar;
    }
/**
 * Parser une ligne
 * @param <type> $line
 * @return <type>
 */
    private function parse($line) {
        if ($this->parseFormat==self::PARSE_FORMAT_CLASSIC) {
            $n = sscanf(trim($line), '%s %s %s [%[^]]] "%s %s %[^"]" %d %s "%[^"]" "%[^"]"',
                $out['ip'],
                $out['client'],
                $out['user'],
                $out['time'],
                $out['http_method'],
                $out['uri'],
                $out['http_prot'],
                $out['http_code'],
                $out['size'],
                $out['referer'],
                $out['ua']
            );
 
            if ($n==11) {
                return $out;
            } else {
                return NULL;
            }
        }
        else if ($this->parseFormat==self::PARSE_FORMAT_LONG) {
            $n = sscanf(trim($line), '%s %s %s [%[^]]] "%s %s %[^"]" %d %s %s "%[^"]" "%[^"]"',
                $out['ip'],
                $out['client'],
                $out['user'],
                $out['time'],
                $out['http_method'],
                $out['uri'],
                $out['http_prot'],
                $out['http_code'],
                $out['size'],
                $out['server'],
                $out['referer'],
                $out['ua']
            );
 
            if ($n==12) {
                return $out;
            } else {
                return NULL;
            }
        }
    }
}
?>

Comment afficher l'adresse IP, l'url et le UserAgent

Pour fichier log access.log, le script ci-dessous va extraire et afficher l'adresse IP, l'url demandée et le UserAgent pour chaque ligne.
<?php
require 'apachelog_parser.php';
$parser=new ApacheLog_Parser();
$f=$_SERVER['DOCUMENT_ROOT'].'/logs/access.log';
$n=$parser->open($f);
foreach ($n as $row) {
    echo $row['ip'].' - '.$row['uri'].' - '.$row['ua'].'<br/>';
}
?>

Comment trouver les erreurs sur son serveur

Dans l'exemple suivant, la fonction filterbyError() est utiliser pour filtrer les lignes. Ne seront retournées que les requêtes ayant générées une erreur. Pour ce faire, la fonction filterbyError() est passée en paramètre à la Class. Contrairement pour chaque ligne, le parser appelle la fonction de comparaison et détermine si la ligne est ajoutée ou non au tableau de sortie.
<?php
require 'apachelog_parser.php';
$parser=new ApacheLog_Parser();
$parser->setParseFormat(ApacheLog_Parser::PARSE_FORMAT_LONG);
$f= $parser->getCurrentFile($_SERVER['DOCUMENT_ROOT'].'/logs/');
$n=$parser->open($f,'filterbyError');
foreach ($n as $row) {
    echo $row['http_code'].' - '.date("H:m:s",strtotime($row['time'])).' - '.$row['uri'].'<br/>';
}
 
function filterbyError($rows) {
    //200:ok, 301&302:redirect, 304 Not Modified
    if (!in_array($rows['http_code'],array('200','301','302','304'))) { 
        return TRUE;
    } else {
        return FALSE;
    }
}
?>

Comment trouver les pages indexées par Google

Pour déterminer les pages crawlées par Google, la fonction filterByGoogleBot() recherche la mention GoogleBot dans l'UserAgent de la requête. Le script est inclu dans une class pour illustrer l'appel d'un Callback avec dans ce cas.
<?php
require 'apachelog_parser.php';
 
class Sample_Class {
    public function show() {
        $parser=new ApacheLog_Parser();
        $parser->setParseFormat(ApacheLog_Parser::PARSE_FORMAT_LONG);
        $f= $parser->getCurrentFile($_SERVER['DOCUMENT_ROOT'].'/logs/');
        $n=$parser->open($f,array($this,'filterByGoogleBot'));
        foreach ($n as $row) {
            echo date("H:m:s",strtotime($row['time'])).' - '.$row['uri'].' - '.$row['ip'].'<br/>';
        }
    }
    public public static function filterByGoogleBot($rows) {
        if (stripos($rows['ua'],'Googlebot')!== false) {
            return TRUE;
        } else {
            return FALSE;
        }
    }
}
$o=new Sample_Class();
$o->show();
?>

Aller plus loin dans l'analyse des logs

L'analyse des logs Apache est intéressante pour identifier le trafic sur son site web. La comparaison avec une fonction callback permet d'imaginer tous les types de filtrage et d'extraire l'information dont on a besoin. Ces tableaux de bord ainsi construits sont une aide précieuse pour tout webmaster d'un site internet.

Ajouter un commentaire

Les champs marqués d'un * sont obligatoires, les adresses emails se sont pas publiées.

A lire aussi

Réseaux sociaux
Présentation de l'article
Catégorie
php5 - class
Mise a jour
04/12/2012
Visualisation
vu 7450 fois
Public
Internaute
Auteur de la publication
Fobec
Admin
Auteur de 267 articles
|BIO_PSEUDO|
Commentaires récents

Publié par Deepan dans php5

Bonjour,
Merci pour ce tuto qui m'a bien aide.
Je donne ici les modifications apportees pour que cela fonctionne chez moi.

/****************************************
* Ouvrir u...

Publié par Fobec dans logiciel

prise en charge du format ipV6. L'api est compatible avec tous les ip qu'elles soient au format ipV4 ou ipV6.

Publié par Fobec dans php5

Le code PHP sur les boucles a ete corrige dans l'article.
Merci Etiazam !

Publié par agence cms open source dans tuto

Vu la multitude des outils de gestion de contenu Open Source, sélectionner l'un d'entre eux exige de réaliser une comparaison fine. Les lecteurs défendent les raisons de leurs cho...

Publié par Celibataire dans news

Le trustrant est pas clair du tout peu d'informations sont disponibles sur lui!