Skip to content

Commit 5058f4c

Browse files
Feat: Ajout de l'analyse syntaxique de fichier log
- Ajout de la méthode parse_fichier de ParseurLogApache qui permet de parser un fichier de log Apache - Ajout de la méthode parse_entree de ParseurLogApache qui permet de parser une entrée d'un fichier de log Apache - Ajout de get_information_entree de ParseurLogApache qui permet de récupérer la valeur d'une information dans une entrée - Ajout de FormatLogApacheInvalideException qui représente une erreur lors de l'analyse syntaxique d'un fichier log - Modification du fichier main.py pour appeller la fonction parse_entree et pour afficher un message en cas d'erreur dans l'analyse
1 parent 1404345 commit 5058f4c

2 files changed

Lines changed: 115 additions & 6 deletions

File tree

app/main.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import colorama
66
from cli.parseur_arguments_cli import ParseurArgumentsCLI, ArgumentCLIException
7+
from parse.parseur_log_apache import ParseurLogApache, FormatLogApacheInvalideException
78

89

910
if __name__ == "__main__":
@@ -25,7 +26,13 @@
2526
parseur_cli = ParseurArgumentsCLI()
2627
arguments_cli = parseur_cli.parse_args()
2728
# Analyse syntaxique du fichier log
29+
parseur_log = ParseurLogApache(arguments_cli.chemin_log)
30+
parseur_log.parse_fichier()
2831
# Analyse statistique du fichier log
2932
# Exportation de l'analyse
3033
except ArgumentCLIException as ex:
3134
print(f"Erreur dans les arguments fournis !\n {ex}")
35+
except FileNotFoundError as ex:
36+
print(f"Erreur dans la recherche du log Apache !\n{ex}")
37+
except FormatLogApacheInvalideException as ex:
38+
print(f"Erreur dans l'analyse du log Apache !\n{ex}")

app/parse/parseur_log_apache.py

Lines changed: 108 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,12 @@
33
"""
44

55
import os
6-
from re import match, compile
6+
from re import match
77
from 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

1014
class 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

Comments
 (0)