33"""
44
55import os
6- from re import match , compile
6+ from re import match
77from datetime import datetime
8+ from parse .fichier_log_apache import FichierLogApache , EntreeLogApache
9+ from donnees .client_informations import ClientInformations
10+ from donnees .requete_informations import RequeteInformations
11+ from donnees .reponse_informations import ReponseInformations
812
913
1014class ParseurLogApache ():
@@ -16,10 +20,10 @@ class ParseurLogApache():
1620 """
1721
1822 PATTERN_ENTREE_LOG_APACHE = (
19- r'(?P<ip>\S+) (?P<rfc>\S+) (?P<user >\S+)'
20- r' (\[(?P<timestamp >.+?)\]|-) "((?P<method >\S+) (?P<url>\S+) (?P<protocol >\S+)|-)"'
21- r' (?P<status >\d+) (?P<size >\d+|-)'
22- r'( "(?P<referer >.*?)" "(?P<user_agent >.*?)")?'
23+ r'(?P<ip>\S+) (?P<rfc>\S+) (?P<utilisateur >\S+)'
24+ r' (\[(?P<horodatage >.+?)\]|-) "((?P<methode >\S+) (?P<url>\S+) (?P<protocole >\S+)|-)"'
25+ r' (?P<code_status >\d+) (?P<taille_octets >\d+|-)'
26+ r'( "(?P<ancienne_url >.*?)" "(?P<agent_utilisateur >.*?)")?'
2327 )
2428
2529 def __init__ (self , chemin_log ):
@@ -43,4 +47,102 @@ def __fichier_existe(self, chemin_fichier):
4347 """
4448 if not os .path .isfile (chemin_fichier ):
4549 return False
46- return True
50+ return True
51+
52+ def parse_fichier (self ):
53+ """
54+ Effectue une analyse syntaxique du fichier de log Apache puis retourne
55+ une représentation du fichier avec les informations trouvées.
56+ Returns:
57+ log_analyse (FichierLogApache): Représentation du fichier.
58+ Raises:
59+ FormatLogApacheInvalideException: Format du fichier log invalide.
60+ """
61+ log_analyse = FichierLogApache (self .chemin_log )
62+ numero_ligne = 1
63+ with open (self .chemin_log , "r" ) as log :
64+ for ligne in log :
65+ try :
66+ log_analyse .ajoute_entree (self .parse_entree (ligne ))
67+ numero_ligne += 1
68+ except FormatLogApacheInvalideException as ex :
69+ raise FormatLogApacheInvalideException (
70+ f"Le format de l'entrée à la ligne { numero_ligne } "
71+ f"('{ ligne } ') est invalide."
72+ ) from ex
73+ return log_analyse
74+
75+ def parse_entree (self , entree ):
76+ """
77+ Effectue une analyse syntaxique d'une entrée dans un fichier de log
78+ Apache puis retourne une représentation de l'entrée avec les
79+ informations trouvées.
80+ Args:
81+ entree (str): Entrée à analyser.
82+ Returns:
83+ entree_analysee (EntreeLogApache): Représentation de l'entrée.
84+ Raises:
85+ FormatLogApacheInvalideException: Format de l'entrée du fichier log invalide.
86+ """
87+ # Analyse de l'entrée
88+ analyse = match (self .PATTERN_ENTREE_LOG_APACHE , entree )
89+ if not analyse :
90+ raise FormatLogApacheInvalideException ()
91+ resultat_analyse = analyse .groupdict ()
92+ # Récupération des informations liées au client
93+ adresse_ip = self .get_information_entree (resultat_analyse , "ip" )
94+ identifiant_rfc = self .get_information_entree (resultat_analyse , "rfc" )
95+ utilisateur = self .get_information_entree (resultat_analyse , "utilisateur" )
96+ agent_utilisateur = self .get_information_entree (resultat_analyse , "agent_utilisateur" )
97+ informations_client = ClientInformations (
98+ adresse_ip , identifiant_rfc , utilisateur , agent_utilisateur
99+ )
100+ # Récupération des informations liées à la requête
101+ horodatage = self .get_information_entree (resultat_analyse , "horodatage" )
102+ if horodatage :
103+ horodatage = datetime .strptime (horodatage , "%d/%b/%Y:%H:%M:%S %z" )
104+ methode_http = self .get_information_entree (resultat_analyse , "methode" )
105+ url = self .get_information_entree (resultat_analyse , "url" )
106+ protocole_http = self .get_information_entree (resultat_analyse , "protocole" )
107+ ancienne_url = self .get_information_entree (resultat_analyse , "ancienne_url" )
108+ informations_requete = RequeteInformations (
109+ horodatage , methode_http , url , protocole_http , ancienne_url
110+ )
111+ # Récupération des informations liées à la réponse
112+ code_statut = self .get_information_entree (resultat_analyse , "code_status" )
113+ if code_statut :
114+ code_statut = int (code_statut )
115+ taille_octets = self .get_information_entree (resultat_analyse , "taille_octets" )
116+ if taille_octets :
117+ taille_octets = int (taille_octets )
118+ informations_reponse = ReponseInformations (
119+ code_statut , taille_octets
120+ )
121+ return EntreeLogApache (
122+ informations_client , informations_requete , informations_reponse
123+ )
124+
125+ def get_information_entree (self , analyse_regex , nom_information ):
126+ """
127+ Retourne la valeur de l'information dans l'analyse si elle possède une valeur
128+ ou None si elle ne possède pas de valeur (égale à - ou vide).
129+ Args:
130+ analyse_regex (Match[str]): Résultat du regex de l'analyse.
131+ nom_information (str): Nom de l'information souhaitée.
132+ Returns:
133+ Union[str, None]: La valeur sous forme de chaîne de caractère ou None si
134+ aucune valeur n'a été trouvée.
135+ """
136+ if nom_information in analyse_regex :
137+ valeur = analyse_regex [nom_information ]
138+ if valeur != "-" and valeur != "" :
139+ return valeur
140+ return None
141+
142+
143+
144+
145+ class FormatLogApacheInvalideException (Exception ):
146+
147+ def __init__ (self , * args ):
148+ super ().__init__ (* args )
0 commit comments