[PHP] Dataverkeer opslaan bij statistieken

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
Naast aantal hits, bezochte pagina's, gebruikte browser etc. wil ik ook het verbruikte dataverkeer per uur opslaan in een database. De eenvoudigste weg hiervoor (die voor mij overigens nog redelijk moeilijk was :)), is het uitlezen van de apache logfiles:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function parse_line($line) {
  $data = array();
  $today = date('d/M/Y');
  $regexp = '/^(.+?) (.+?) (.+?) \\\[(.+?)\\] "(.+?)" (\\d+) (\-|\\d+)( "(.+?)")?( "(.+?)")?\\s*$/i';
  if (preg_match($regexp, $line, $matches) && count($matches) > 0) {
    if (strstr($matches[4], $today)) {
      // niet alle matches opgesomd...
      $data["datetime"] = $matches[4];
      $data["length"] = $matches[7];
      return $data;
    }
    else {
    return false;
  }
}

function parse_log() {
  $lines = file("access.log");
  $log = array();
  for ($i = 0; $i < count($lines); $i++) {
    $data = parse_line($lines[$i]);
    if ($data != false) {
      $log[] = $data;
    }
  }
  return $log;
}

Deze code bevriest alleen als de logfile groter is dan een paar MB. Wat ik dus wil, is de logfile bijvoorbeeld per 100 regels uitlezen. En omdat ik toch elke dag de logfile uitlees, hoeven alleen de regels van vandaag uitgelezen te worden. Hiertoe ben ik begonnen met het volgende: ik neem de datum van vandaag (regel 3) en geef false terug als deze datum niet met de datum in de gegeven logfile-regel overeenkomt. De bedoeling is dat parse_log op dat moment stopt met regels uit access.log te halen.

Ik heb hulp nodig bij het volgende:
  • logfile per 100 regels uitlezen
  • functie parse_log stoppen en resultaat laten retourneren als parse_line een datum tegenkomt die niet overeenkomt met die van vandaag
Alle hulp wordt zeer gewaardeerd :)

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 19:51

Creepy

Tactical Espionage Splatterer

Je zult een functie ala fread moeten gebruiken om regel voor regel het bestand in te lezen.
Op http://www.php.net/manual/en/ref.filesystem.php staan een aantal bruikbare functie om regel voor regel in te lezen i.p.v. alles in 1 keer.

Het stoppen van je functie kan vrij makkelijk aljs je bijv. een while loop gebruikt i.p.v. een for of break; gebruiken om uit je for loop te springen.

Overigen zijn deze zaken redelijk basic PHP te noemen. Ik kan me ook niet echt voorstellen dat je zelf al actief aan het zoeken bent geweest voor een oplossing? Ook mis ik in je topicstart de verschillende zaken die je nu zelf al hebt geprobeerd om je functie te stoppen en niet de gehele file in 1 keer in te lezen. Zoals je ondertussen al weet gaan we er vanuit dat je zelf eerst actief opzoek gaat naar een oplossing voor de vragen die je stelt. GoT is nog steeds een discussie forum en geen helpdesk ;)

[ Voor 64% gewijzigd door Creepy op 02-05-2006 14:13 ]

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Acties:
  • 0 Henk 'm!

  • BalusC
  • Registratie: Oktober 2000
  • Niet online

BalusC

Carpe diem

Je zou ook cronolog.exe kunnen gebruiken om de logfiles over de dagen te verdelen. Ik heb zelf een cronolog ingesteld op /logfiles/%y%m/%y%m%d.log. Zodoende blijven de logfiles kleiner (alhoewel het in mijn geval toch nog 7 à 10MB per dag is).

Een andere mogelijkheid is om Apache naar MySQL te laten loggen en daarvanuit de data te ophalen (heb je gelijk ook bandbreedteverbruik van images en apps, voorzover van toepassing). Zie voor wat inkoppers mijn statsgenerator.

[ Voor 11% gewijzigd door BalusC op 02-05-2006 14:54 ]


Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
@BalusC - ik had zelf ook al gekeken naar mogelijkheden om direct vanuit Apache naar een mysql database te loggen, maar hiervoor moet je de httpd.conf kunnen aanpassen. Dat is bij mijn thuisserver geen probleem, maar wel bij mijn (online) hosting provider. Tot nu toe heb ik hier geen workaround voor kunnen vinden: ik dacht eerst aan .htaccess, maar dat werkt niet omdat virtual hostst in de httpd.conf zelf moeten worden toegevoegd. Weet jij een andere workaround?

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • djluc
  • Registratie: Oktober 2002
  • Laatst online: 14:28
Je hoster bellen om hen die instelling te laten maken?

Acties:
  • 0 Henk 'm!

  • BalusC
  • Registratie: Oktober 2000
  • Niet online

BalusC

Carpe diem

Ah ja, dan zijn jouw mogelijkheden wel erg beperkt. Je zou eens PHP icm JS kunnen gebruiken, bijvoorbeeld document.fileSize :)

Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
@BalusC - ik had ook al naar document.fileSize gekeken, maar dat is IE only :( Ik ben nu op zoek naar een cross-browser variant (bv. de hele DOM langslopen en van elk element het aantal KB's bepalen en optellen) maar heb al begrepen dat er qua nauwkeurigheid geen alternatief is voor logfile analyse.

Vandaar dat ik naast mijn javascript zoektocht verder ben gegaan met het script uit de TS:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
function parse_line($line) {
  $data = array();
  $today = date('d/M/Y');
  $regexp = '/^(.+?) (.+?) (.+?) \\\[(.+?)\\] "(.+?)" (\\d+) (\-|\\d+)( "(.+?)")?( "(.+?)")?\\s*$/i';

  if (preg_match($regexp, $line, $matches) && count($matches) > 0) {
    if (strstr($matches[4], $today)) {
      $data["ip"] = $matches[1];
      $data["datetime"] = $matches[4];
      $data["http"] = $matches[5];
      $data["status"] = $matches[6];
      $data["length"] = $matches[7];
      $data["referer"] = $matches[9];
      $data["user_agent"] = $matches[11];    
    }
  }
  return $data;
}

function parse_log() {
  $log = array();
  $handle = fopen("access.log", "r");
  while (!feof($handle)) {
    if ($line = fgets($handle)) {
      echo $line;
      if ($data = parse_line($line)) {
        $log[] = $data;
      }
      else {
        fclose($handle);
      }
    }
  }
  return $log;
}

print_r(parse_log());

Ik lees nu regel voor regel de logfile is, en wil stoppen op het moment dat ik een andere datum dan vandaag tegenkom. De fclose($handle) in regel 30 geeft een foutmelding. Als ik die regel vervang door "exit", stopt (zoals verwacht ;)) het hele script. Op welke manier kan ik netjes het doorlopen van de logfile stoppen?
code:
1
2
Warning: fgets(): 1 is not a valid stream resource in 
C:\Program Files\Apache2\htdocs\test\logfile.php on line 26

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

Verwijderd

php met js om aan de server kant iets uit te lezen?? Hrmm das wel erg raar als ik zo vrij mag zijn.

[ Voor 60% gewijzigd door Verwijderd op 02-05-2006 16:45 . Reden: eerst lezen dan blaten ]


Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
@bogusje - het idee zou dan zijn om clientside met javascript de grootte van de gerenderde pagina uit te lezen en deze via een postback naar de server te sturen, welke de info toevoegt aan de database. In plaats van de logfiles uit te lezen, koppel je dus via de client de documentgrootte terug :)

Overigens heb ik mijn probleem als volgt opgelost:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function parse_log() {
  $log = array();
  $handle = fopen("access.log", "r");
  $next = true;
  while (!feof($handle) && $next == true) {
    if ($line = fgets($handle)) {
      echo $line;
      if ($data = parse_line($line)) {
        $log[] = $data;
      }
      else {
        $next = false;
      }
    }
  }
  return $log;
}

Nu stopt de functie op het moment dat hij een datum tegenkomt die anders is dan die van vandaag :) Als iemand een opmerking hierop heeft, hoor ik het graag. Misschien moet ik de handle nog afsluiten oid...

[ Voor 52% gewijzigd door Reveller op 02-05-2006 17:09 ]

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."

Pagina: 1