source: trunk/bin/alternc_stats_web.php @ 1396

Revision 1396, 5.7 KB checked in by anarcat, 8 years ago (diff)

re-compter correctement les hits

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1#!/usr/bin/php4 -q
2<?php
3
4/**
5 * Statistiques webs par compte AlternC
6 *
7 * Ce script lit tous les fichiers de log apache et insère les
8 * statistiques de visite par jour et par domaine / sous-domaine dans
9 * la table stat_http
10 *
11 * On assume que:
12 *
13 * - on est appelé à traiter un fichier de log donné qu'une seule fois
14 * - les fichiers de logs sont traités en ordre chronologique
15 *
16 * La façon correcte de faire ceci est de traiter access.log.0 juste
17 * après la rotation.
18 */
19
20/* Configuration */
21
22/**
23 * Combien de lignes de logs traite-t-on par bloc
24 *
25 * 10000 conseillé, plus possible (à tester), moins vivement
26 * déconseillé
27 */
28$each=10000;
29
30/**
31 * the maximum line length
32 *
33 * lines larger than this will not be parsed properly
34 *
35 * Was originally 2048, but was skipping too much of virus log
36 * entries. We still have some with 4096, but much less (at worst
37 * 1/10000 hits)
38 */
39@define('BUFSIZE', 4096);
40
41/* end of configuration */
42
43/**
44 * never stop because of time
45 */
46@set_time_limit(0);
47
48/**
49 * bypass login checks
50 */
51include("/var/alternc/bureau/class/config_nochk.php");
52
53// Libère le bureau !
54alternc_shutdown();
55
56$argv0 = array_shift($argv);
57
58# crude getopt for portability
59$verbose = $full = 0;
60foreach ($argv as $pos => $arg) {
61  switch ($arg) {
62  case "-v":
63    unset($argv[$pos]);
64    $verbose = 1;
65    break;
66  case "-f":
67    unset($argv[$pos]);
68    $full = 1;
69    @mysql_query("DELETE FROM stat_http");
70    break;
71  }
72}
73
74$total_hits = $total_good = 0;
75
76// process all logfiles
77foreach ($argv as $file) {
78
79  if ($verbose) {
80    echo "################################################\n";
81    echo date("d/m/Y H:i:s")." : Traitement de $file\n";
82    echo "################################################\n";
83  }
84
85  if (substr($file,-3)==".gz") {
86    $open="gzopen";
87    $gets="gzgets";
88    $close="gzclose";
89  } else {
90    $open="fopen";
91    $gets="fgets";
92    $close="fclose";
93  }
94
95  if (($f = $open($file, "rb")) === FALSE) {
96    die("impossible d'ouvrir le log $file");
97  }
98
99  $i = $l= $good = 0;
100
101  $domstat=array(); // On stocke sous forme de clé "dom/day" => "hit or bandwith"
102  $domuid=array();  // Cache des uids associés aux domaines.
103
104
105  $months=array("Jan"=>"01","Feb"=>"02","Mar"=>"03","Apr"=>"04","May"=>"05","Jun"=>"06","Jul"=>"07","Aug"=>"08","Sep"=>"09","Oct"=>"10","Nov"=>"11","Dec"=>"12");
106
107  /**
108   * match "escaped quotes" or "everything except quotes"
109   *
110   * this might represent a significant performance hit
111   */
112  $noquote = '(?:(?:(?<=\\\)")|(?:[^"]))*';
113
114  // Exemple de ligne apache :
115  // crawl18.dir.com - login [14/Jun/2004:06:38:47 +0200] "GET /modules/newbb?days=100 HTTP/1.0" 200 20156 "-" "Pompos/1.3 http://dir.com/pompos.html" 2 esperance-jeunes.org
116
117  // this pattern should match it
118  $pattern = '/^[^ ]* [^ ]* [^ ]* \\[([0-9]*)\\/([a-zA-Z]*)\\/([0-9]*):[0-9]*:[0-9]*:[0-9]* [^ ]* "'.$noquote.'" ([0-9-]*) ([0-9-]*) "'.$noquote.'" "'.$noquote.'" [0-9]* ([^ ]*)$/';
119
120  // parse a line at a time
121  while ($s=$gets($f,BUFSIZE)) {
122    $s=trim($s);
123    if (preg_match($pattern,$s,$mat)) {
124      // ok, 1: jour  2: mois (english)  3: année  4: http result (200/404 ...) 5: taille  6: domaine
125      // Ligne ok.
126      //    echo "Ligne ok : ";
127      //    for($j=1;$j<count($mat);$j++) echo "$j:".$mat[$j]." ";
128      // On calcule le jour : (= yearmonthday)
129      $day=$mat[3].$months[$mat[2]].$mat[1];
130      $dom = mysql_escape_string(strtolower($mat[6]));
131      $domstat[$dom."/".$day]["hit"]++;
132      $domstat[$dom."/".$day]["size"]+=intval($mat[5]);
133      $good++;
134    } else {
135      if ($verbose)
136        printf("Can't parse: %.60s...\n", $s);
137    }
138    if ($i/100==intval($i/100)) { echo "."; flush(); }
139    $i++; $l++;
140
141    // insérer une fois que notre bloc de lignes est plein
142    if ($i==$each) {
143      if ($verbose) echo " $l lines read\nInserting... ";
144      insert_lines($domstat, &$domuid);
145      $domstat = array();
146      $i=0;
147    }
148  }
149
150  // insérer les lignes qui n'avaient pas rempli un bloc
151  if ($verbose) echo "\nInserting remaining lines... ";
152  insert_lines($domstat, &$domuid); 
153  $domstat = array();
154
155  $close($f);
156 
157  $total_hits += $l;
158  $total_good += $good;
159
160  if ($verbose) echo "\n$l lines read ($good good)\n";
161
162}
163
164// handy function to avoid a copy-paste
165function insert_lines($domstat, &$domuid) {
166  global $verbose;
167  // on insère le tableau dans mysql.
168  $update=0; $insert=0;
169  foreach($domstat as $date => $stat) {
170    preg_match("/^([^\\/]*)\\/(.*)$/",$date,$mat);
171    $dom =$mat[1];
172    $date = $mat[2];
173    // on cherche l'uid de ce domaine
174    if (!$domuid[$dom]) {
175      list($domuid[$dom])=@mysql_fetch_array(mysql_query("SELECT compte FROM sub_domaines WHERE (domaine='".$dom."' AND sub='') OR (concat(sub,'.',domaine)='".$dom."');"));
176    }
177    // a-t-on déjà ce domaine ce jour ?
178    list($ct)=@mysql_fetch_array(mysql_query("SELECT COUNT(*) FROM stat_http WHERE day='".$date."' AND domain='".$dom."';"));
179    if ($ct) {
180      $sql="UPDATE stat_http SET hit= hit + '".$stat["hit"]."', size= size + '".$stat["size"]."' WHERE domain='".$dom."' AND day='".$date."';";
181      $update++;
182    } else {
183      $sql="INSERT INTO stat_http SET uid='".$domuid[$dom]."',day='".$date."',domain='".$dom."', hit='".$stat["hit"]."', size='".$stat["size"]."';";
184      $insert++;
185    }
186    mysql_query($sql) || die("Query failed: " . mysql_error());
187  }
188  if ($verbose) echo "$update updates and $insert inserts (uidcache size = ".count($domuid).") \n";
189
190}
191
192if ($verbose) echo "\n$total_hits lines read total ($total_good good)\n";
193
194// check validity
195if ($full) {
196  list($res) = mysql_fetch_array(mysql_query("SELECT SUM(hit) FROM stat_http"));
197  if ($res == $total_good) {
198    echo "correct count: $res\n";
199  } else {
200    echo "difference between database hits and lines read: $res => $total_good\n";
201  }
202}
203
204?>
Note: See TracBrowser for help on using the repository browser.