Publié le 04/12/2012
Auteur Fobec
Réseaux sociaux
0 partages
0 tweets
3 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 6216 fois
Public
Internaute
Auteur de la publication
Fobec
Admin
Auteur de 261 articles
|BIO_PSEUDO|
Commentaires récents

Publié par traitstone dans CMS

c'est bou et tres bon chose

Publié par Djoe dans java

Rien à redire, fonctionne parfaitement. Merci beaucoup

Publié par Diégo DELPY dans CMS

IL FAUT IMPERATIVEMENT DONNER DES CHEMINS COMPLETS à pFrom et à pTo, sinon ça marche
bizzarrement.
Exemple :

// Chemin relatif : PAS BON !
pFrom := \'Bureau\\Télécharg...

Publié par fobec dans CMS

faire le menage !!!!

Publié par BIBAK dans CMS

merci infiniment, ce sont des beau icons::: :)