[Perl] Besoin d'aide

Fermé
barichon - 29 sept. 2009 à 12:24
Barichon Messages postés 19 Date d'inscription mardi 29 septembre 2009 Statut Membre Dernière intervention 24 novembre 2009 - 12 oct. 2009 à 13:02
Bonjour a tous,

je débute dans la programmation, je suis nul mais j'essaye d'apprendre...
Je suis actuellement sur un script perl, l'objectif est de lire un fichier qui se presentent sous cette forme:

xxxxxxxxx:yyyyyyyyyy
lllllllllllllll:ppppppppp
zzzz:ooooooo

Je veut lire ce fichier (ca c'est ok) et recupérer dans un tableau1 xxxxxxxxx
llllllllllll
zzzzzzz

et récupérer dansun tableau 2: yyyyyyyyyyyyy
ppppppppp
oooooooooo

voici le debut de mon script, je suis bloqué a cette étape de lecture pourriez vous m'aidez svp.

!/usr/bin/perl


open(FIC,"/etc/apache2/vhost.conf") or die ("Erreur lors de l'ouverture du fichier.conf");

@fic = <FIC> ;
foreach $line (@fic)
{
   print $line;
}
close("FIC");



Cdt,

Merci d'avance.
A voir également:

41 réponses

Barichon Messages postés 19 Date d'inscription mardi 29 septembre 2009 Statut Membre Dernière intervention 24 novembre 2009
5 oct. 2009 à 11:43
Salut lamj ;)

J'ai testé ta dernière version,

La ligne alloclips apparait toujours en 1er hors elle devrait apparaitre en derniers vu qu'il n'y a qu'une seul occurence de celle-ci dans access.log, non ?

Merci
0
lami20j Messages postés 21331 Date d'inscription jeudi 4 novembre 2004 Statut Modérateur, Contributeur sécurité Dernière intervention 30 octobre 2019 3 569
5 oct. 2009 à 12:15
Salut,

Ben, alors on ne teste pas les même fichiers.
Chez moi est affichée en dernier.
0
Barichon Messages postés 19 Date d'inscription mardi 29 septembre 2009 Statut Membre Dernière intervention 24 novembre 2009
5 oct. 2009 à 12:31
autant pour moi ca marhce très bien !

;)

L'objectif suivant c'est de faire un cut de chaque groupe d'oocurences de ce que l'on obtiens de "sort @$_ for @trie" et de les placées dans un fichier (vhostjjmmaaaa.log)dans le path log correspondant a cette ocurrence(@f2).

C'est dur ? tu t'y prendrais comment ?
0
lami20j Messages postés 21331 Date d'inscription jeudi 4 novembre 2004 Statut Modérateur, Contributeur sécurité Dernière intervention 30 octobre 2019 3 569
5 oct. 2009 à 13:03
Re,

Mets dans le script ce ces lignes et exécute le script.
Ensuite affiche le résultat.

print scalar @trie,"\n";
print scalar @$_ for @trie;print for sort @reste;

0
Barichon Messages postés 19 Date d'inscription mardi 29 septembre 2009 Statut Membre Dernière intervention 24 novembre 2009
5 oct. 2009 à 15:08
tiens après exucution:

sudo perl scriptlol.pl
6
2565111"access.log" [readonly][converted] 65641L, 17119557C
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
lami20j Messages postés 21331 Date d'inscription jeudi 4 novembre 2004 Statut Modérateur, Contributeur sécurité Dernière intervention 30 octobre 2019 3 569
5 oct. 2009 à 16:53
Re,

de les placées dans un fichier (vhostjjmmaaaa.log)
ça ce n'est pas difficile

dans le path log correspondant a cette ocurrence(@f2).
Ça, je n'ai pas compris.

Tu peux me donner un exemple?
0
Barichon Messages postés 19 Date d'inscription mardi 29 septembre 2009 Statut Membre Dernière intervention 24 novembre 2009
5 oct. 2009 à 18:38
Désolé j'ai du mal m'exprimé.

Chaque lignes de logs pour ce groupe d'occurences (en s'occupant en 1er du vhost qui a le plus d'occurences) devra etre gréppé du résultat et etre placé dans un fichier vhostjjmmaaaa.log a l'adresse "pathlog" qui lui correspond dans vhost.conf (ex /mnt/filer-genet-3/a/b/ab......com/ftp/logs/).

J'ai été plsu claire ? :(

lol
0
lami20j Messages postés 21331 Date d'inscription jeudi 4 novembre 2004 Statut Modérateur, Contributeur sécurité Dernière intervention 30 octobre 2019 3 569
5 oct. 2009 à 23:09
Re,

Essaie ça
#!/usr/bin/perl
use strict;use warnings;

open F,"access.log"  or die "E/S: $!\n";
open FF,"vhost.conf" or die "E/S: $!\n";
open FFF,">vhostjjmmaaaa.log" or die "E/S: $!\n";

# 1ère partie : obtenir les tableaux
my (@f1,@f2,@reste,%h);
push @f1,(split ":",$_)[0] and push @f2,(split ":",$_)[1] while(<FF>);
chomp@f2;

# 2ème partie : faire le tri par rapport au tableau @f1
while (<F>){
          /^(.*?)\s/;push @{$h{$1}},$_ if grep{/$1/} @f1;
            push @reste,$_ unless grep{/$1/}@f1;
}

my @trie = map  { $_->[1] }
           sort { $b->[0] <=> $a->[0] }
           map  { [ @$_+0, $_ ] } values %h;

print sort @$_ for @trie;print for sort @reste;

for my $e(@trie){
  for (@{$e}){
    /^(.*?)\s.*/ and print FFF grep { /^$1/ } qx/cat vhost.conf/;
  }
}
__END__
0
lami20j Messages postés 21331 Date d'inscription jeudi 4 novembre 2004 Statut Modérateur, Contributeur sécurité Dernière intervention 30 octobre 2019 3 569
6 oct. 2009 à 17:05
Salut,

Essaie ce script.
Toutefois, il n'est pas très performant vu qu'il y a trop d'appels système.
En fait vu le résultat que tu veux obtenir, je ne vois pas à quoi ça sers de faire un tri par nombre d'occurrences, à moins que tu as un traitement particulier dont tu n'as pas parlé.

Je vais pensé l'week-end prochain pour une optimisation.

#!/usr/bin/perl
use strict;use warnings;

open F,"access.log"  or die "E/S: $!\n";
open FF,"vhost.conf" or die "E/S: $!\n";

# 1ère partie : obtenir les tableaux
my (@f1,@f2,@reste,%h);
push @f1,(split ":",$_)[0] and push @f2,(split ":",$_)[1] while(<FF>);
chomp@f2;

# 2ème partie : faire le tri par rapport au tableau @f1
while (<F>){
          /^(.*?)\s/;push @{$h{$1}},$_ if grep{/$1/} @f1;
            push @reste,$_ unless grep{/$1/}@f1;
}

my @trie = map  { $_->[1] }
           sort { $b->[0] <=> $a->[0] }
           map  { [ @$_+0, $_ ] } values %h;

#print sort @$_ for @trie;print for sort @reste;

for my $e(@trie){
  for (@{$e}){
    /^((.*?\.).*?)\s.*/;
    my $fic = "$2" . qx/date '+%d%m%Y'/;
    open FFF,">>$fic" or die "E/S : $!\n";
    print FFF grep { /^$1/ } qx/cat vhost.conf/;
    close $fic;

  }
}
__END__
0
Barichon Messages postés 19 Date d'inscription mardi 29 septembre 2009 Statut Membre Dernière intervention 24 novembre 2009
6 oct. 2009 à 21:03
Tu assures en attendant, je test ca demain !
0
lami20j Messages postés 21331 Date d'inscription jeudi 4 novembre 2004 Statut Modérateur, Contributeur sécurité Dernière intervention 30 octobre 2019 3 569
6 oct. 2009 à 22:21
Re,

Essaie plutôt ça et dit si ça te conviens.
#!/usr/bin/perl
use strict;use warnings;
open F,"access.log"  or die "E/S: $!\n";
my %h;

while(<F>){
  next unless /^(.*?)\s.*/;
  $h{$1}++;
}
for (keys %h){
  my $z=$_;
  /^(.*?\.).*/;
  chomp(my $fic="$1" . qx/date '+%d%m%Y'/);
  my $c = grep { /^$z/ } qx/cat vhost.conf/;
  if($c>0){
    open FFF,">>$fic" or die "E/S : $!\n";
    print FFF grep { /^$z/ } qx/cat access.log/;
    close $fic;
  }
}
__END__
0
Barichon Messages postés 19 Date d'inscription mardi 29 septembre 2009 Statut Membre Dernière intervention 24 novembre 2009
6 oct. 2009 à 22:46
Sinon tu donnes des cours ? Combien de l'heure ? J'achète !

Merci ca fais vraiment plaisir de voir des gens comme toi, je test ça demain.
0
lami20j Messages postés 21331 Date d'inscription jeudi 4 novembre 2004 Statut Modérateur, Contributeur sécurité Dernière intervention 30 octobre 2019 3 569
7 oct. 2009 à 08:33
Salut,

Le dernier script que je te donné, selon moi, fonctionne (j'ai testé sur les deux fichiers que tu m'as donné).
En revanche access.log n'est pas grand.
J'ai fait un test sur un access.log de 200 Mo et le traitement a été fait en 1 minute (Athlon XP 1,5 Mhz, 512 DDRAM + 400 Mo swap)

Toutefois, je pense qu'on peut encore améliorer.
Si tu regardes bien, dans le script le fichiers access.log est parcouru plusieurs fois.
- une fois quand on stocke les host (voir la 1ère boucle while)
- dans la boucle for est parcouru en fonctionne de nombre de host trouvé et qui correspondent avec vhost
Donc ce n'est pas très efficace sur un fichier de quelque Go par exemple.

L'idéal sera de parcourrir le fichier access.log une seule fois et d'écrire dans vhostjjmmaa.log les lignes trouvées.

Je suis en train de penser à une solution.
D'ailleurs ce qui t'interesse c'est qu'en partant de l'access.log tu dois créer un vhostjjmmaa.log pour chaque vhost qui se trouve dans vhost.

Donc j'ai suivi ton raisonnement, et je suis parti à la recherche d'abord de vhost dans access.log (ce qui implique le 1ère parcours de access.log) et ensuite reprendre le vhost.conf pour voir si les vhost correspondent et ensuite pourcourrir le access.log pour chaque vhost.

Mon idée est en fait de lire le vhost.conf et ensuite de parcourrir une seule fois access.log et dès qu'en vhost est rencontré alors on écrit dans le fichier vhostjjmmaa.log.
Tu vois ce que je veux dire?


0
lami20j Messages postés 21331 Date d'inscription jeudi 4 novembre 2004 Statut Modérateur, Contributeur sécurité Dernière intervention 30 octobre 2019 3 569
7 oct. 2009 à 22:56
Salut,

Je viens de faire un test avec la dernière version que je t'ai donné et aussi avec une nouvelle que j'ai écrit selon le raisonnement de mon dernier message (Message N° 33 )

Le test je l'ai fait sur
lami20j@debian:~$ cat /proc/cpuinfo
processor : 0
vendor_id : AuthenticAMD
cpu family : 6
model : 8
model name : AMD Athlon(tm) XP 2200+
stepping : 0
cpu MHz : 1793.189

lami20j@debian:~$ free
total used free shared buffers cached
Mem: 516300 411508 104792 0 10540 170024
-/+ buffers/cache: 230944 285356
Swap: 393552 112172 281380

lami20j@debian:~$ uname -a
Linux debian 2.6.26-2-686 #1 SMP Wed Aug 19 06:06:52 UTC 2009 i686 GNU/Linux


J'ai utilisé un fichier access.log de 3.4 Go et plus de 20 millions lignes
lami20j@debian:/mnt/hda5/accesslog$ wc -l access.log; du -h access.log
20054931 access.log
3,4G    access.log


Pour la version du message 13 après presque 2heures j'ai eu Out of memory sans avoir le résultat voulu
lami20j@debian:/mnt/hda5/accesslog$ time perl stock_accesslog_v4.pl
Complété

real    116m2.399s
user    2m49.391s
sys     0m42.367s

En revanche avec une autre version le traitement a été effectué correctement dans 8minutes 32secondes
lami20j@debian:/mnt/hda5/accesslog$ time perl stock_accesslog_v5.pl

real    8m39.852s
user    2m51.499s
sys     0m31.422s

Il faudra qu'on parle en ce qui concerne cette dernière version.(Le chemin des logs n'est pas pris en compte. Un fichier vide sera crée pour chaque vhost, ce qui normalement ne dérange pas vu le gagne de performance.)
#!/usr/bin/perl
open F,"access.log" or die "E/S: $!\n";
open FF,"vhost.conf" or die "E/S: $!\n";
my (%h,%vhost);
chomp(my $date=qx/date '+%d%m%Y'/);

while(<FF>){
  /^(.*):.*/;
  $vhost{$1}++;
}

for(keys %vhost){
  /^(.*?)\..*/;
  my $vhostjjmmaa = "$1.$date";
  open $vhostjjmmaa,">>${vhostjjmmaa}.log" or die "E/S: $!\n";
}

while(<F>){
  next unless /^((.*?)\..*?)\s.*/;
  my $FH = "$2." . $date;
  print $FH $_;
}

for(keys %vhost){
  /^(.*?)\..*/;
  close "$1.$date";
}
__END__

Mais après cette histoire, je me pose une question.
Pourquoi ne pas configurer une des directives (TransferLog, CustomLog) directement dans la configuration des VirtualHost ?
Comme ça il n'y a plus besoin d'un script Perl pour avoir les logs par vhost.
Apache s'occupera lui même.



0
lami20j Messages postés 21331 Date d'inscription jeudi 4 novembre 2004 Statut Modérateur, Contributeur sécurité Dernière intervention 30 octobre 2019 3 569
8 oct. 2009 à 08:36
Salut,

Pour la version du message 13
Correction : Pour la version du message 31
0
C'est un test en version non optimisé ? 410 mega en used, en effet pour un fichier de test access.log (de 200 méga, si mes souvenirs sont bons) ça fais beaucoup...

Je vois que tu me concoctes un truc au ptits oignons, je ne sais pas comment te remercier !

Tu aimes le vin de bourgogne ?
0
lami20j Messages postés 21331 Date d'inscription jeudi 4 novembre 2004 Statut Modérateur, Contributeur sécurité Dernière intervention 30 octobre 2019 3 569
8 oct. 2009 à 21:01
0
Oui biensur je l'ai lu... mais le contexte "Internet" fais que j'ai du mal comprendre...

Ce test as été fais a partir de quelle version du coup ?
0
lami20j Messages postés 21331 Date d'inscription jeudi 4 novembre 2004 Statut Modérateur, Contributeur sécurité Dernière intervention 30 octobre 2019 3 569
8 oct. 2009 à 21:14
Re,

Ben, le script est dans le message.
Il est complétement modifié.
Je parcours le fichier access.log une seule fois, d''où le gagne de performances.

Mon raisonnement est dans le message 33
0
Pfff quel boulet !

Dslé j'ai pas cliquer sur la fenêtre qui donne le totalité du post (fatigue lol)

C'est un tres bonne nouvelle tout ca ! franchement Bravo !

en ce qui concerne ta question:

Mais après cette histoire, je me pose une question.
Pourquoi ne pas configurer une des directives (TransferLog, CustomLog) directement dans la configuration des VirtualHost ?
Comme ça il n'y a plus besoin d'un script Perl pour avoir les logs par vhost.
Apache s'occupera lui même.


Oui je suis d'accords avce toi, je ne connais pas cette fonction je vais faire qq recherches la dessus.
Mais vu y'aura des fichiers genére genre dl.082009.log pour un vhost et peut etre un autre du même nom pour un autre vhost (vu que dl représente juste le serivce de download)... tu voit ce que je veux dire ???
0
lami20j Messages postés 21331 Date d'inscription jeudi 4 novembre 2004 Statut Modérateur, Contributeur sécurité Dernière intervention 30 octobre 2019 3 569
9 oct. 2009 à 13:14
Re,

J'ai créer les répertoire selon vhost.conf.
Les fichiers logs sont créer dans le répertorie correspondant.
Les fichiers vides seront supprimé à la fin.
Le test sur le même fichier de 3.4 Go varie chez moi (en fonction de la charge de mon pc, puisque je fais d'autre choses aussi ;-) entre 8minutes et 10 minutes
A savoir que peut être les noms des fichiers on le nom
nomdomainejusque1erpoint.jjmmaa.log

Voici le script.
Tu me diras le résultat des tests.
A savoir que le script doit être exécuter en root vu qu'on écrit un peu partout dans /mnt

#!/usr/bin/perl
open F,"access.log" or die "E/S: $!\n";
open FF,"vhost.conf" or die "E/S: $!\n";
my (%h,%vhost);
chomp(my $date=qx/date '+%d%m%Y'/);

while(<FF>){
  s/\s*$//g;
  /^(.*):(.*)/;
  $vhost{$1}=$2;
}

for(keys %vhost){
  s/^\s*//g;
  /^(.*?)\..*/;
  my $vhostjjmmaa = "$1.$date";
  my $handle=$_;
  open $handle,">$vhost{$_}${vhostjjmmaa}.log" or die "E/S: $!\n";
}

while(<F>){
  next unless /^((.*?)\..*?)\s.*/;
  my $FH=$1;
  print $FH $_;
}

for(keys %vhost){ close $_;}

for(values %vhost){
  opendir(REP,$_);
  while(my $fic=readdir REP){
    next if $fic=~/\.\.?$/;
    chomp(my $taille = qx/du -sh "$_$fic"/);
    unlink "$_$fic" if $taille=~/^0/;
  }
  close REP;
}

__END__
0
Barichon Messages postés 19 Date d'inscription mardi 29 septembre 2009 Statut Membre Dernière intervention 24 novembre 2009
9 oct. 2009 à 14:40
merci beaucoup je pourrais tester que en live car focément j'ai pas les droit pour tester ça seul...

Peut tu me commenter tout ça ?

Merci encore pour cette contribution énorme !
0
lami20j Messages postés 21331 Date d'inscription jeudi 4 novembre 2004 Statut Modérateur, Contributeur sécurité Dernière intervention 30 octobre 2019 3 569
9 oct. 2009 à 15:30
Re,

#!/usr/bin/perl
open F,"access.log" or die "E/S: $!\n";
open FF,"vhost.conf" or die "E/S: $!\n";
my (%h,%vhost);
# la date du système
chomp(my $date=qx/date '+%d%m%Y'/);

# la cle du hash    = le nom de domaine
# la valeur du hash = le répertoire /mnt/....
while(<FF>){
  s/\s*$//g;
  /^(.*):(.*)/;
  $vhost{$1}=$2;
}

# ouverture d'un handle de fichier en écriture
# pour chaque fichier (dans /mnt/...)
for(keys %vhost){
  s/^\s*//g;
  /^(.*?)\..*/;
  my $vhostjjmmaa = "$1.$date";
  my $handle=$_;
  open $handle,">$vhost{$_}${vhostjjmmaa}.log" or die "E/S: $!\n";
}

# access.log est parcouru une seule fois
while(<F>){
# saute les lignes qui ne correspondent aux nom domaines
  next unless /^((.*?)\..*?)\s.*/;
  my $FH=$1; # je stocke la chaîne de caractères
             # qui corresponde aux handle ouvert
  print $FH $_; # j'écris dans le handle (le fichier /mnt/../vhostjjmmaa.log
}

# fermeture des handles ouverts
for(keys %vhost){ close $_;}

# suppression des fichiers vides dans /mnt/..
for(values %vhost){ # pour chaque vhost
  opendir(REP,$_);  # handle vers /mnt/..
  while(my $fic=readdir REP){ # chaque fichier
    next if $fic=~/\.\.?$/;   # sauf . et ..
    chomp(my $taille = qx/du -sh "$_$fic"/); # je calcule la taille
    unlink "$_$fic" if $taille=~/^0/;        # si zéro je supprime
  }
  close REP; # fermeture de handle en cours
}

__END__
0