Skip to content

Commit 74fcf31

Browse files
Feat: Filtre (#41)
- Ajout de la classe FiltreLogAPache qui représente un filtre à appliquer lors d'une analyse - Ajout de l'argument du filtre sur l'adresse IP dans ParseurArgumentsCLI - Ajout de l'argument du filtre sur le code de statut http dans ParseurArgumentsCLI - Prise en compte uniquement des entrées qui passent le filtre dans l'analyseur de log Apache
1 parent 2789670 commit 74fcf31

4 files changed

Lines changed: 153 additions & 12 deletions

File tree

app/analyse/analyseur_log_apache.py

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

55
from collections import Counter
66
from parse.fichier_log_apache import FichierLogApache
7+
from analyse.filtre_log_apache import FiltreLogApache
78

89

910
class AnalyseurLogApache:
@@ -17,24 +18,29 @@ class AnalyseurLogApache:
1718
les statistiques des classements (tops).
1819
"""
1920

20-
def __init__(self, fichier_log_apache: FichierLogApache, nombre_par_top: int = 3):
21+
def __init__(self,
22+
fichier_log_apache: FichierLogApache,
23+
filtre: FiltreLogApache,
24+
nombre_par_top: int = 3):
2125
"""
2226
Initialise un nouveau analysateur de fichier log Apache.
2327
2428
Args:
2529
fichier_log_apache (FichierLogApache): Le fichier à analyser.
30+
filtre (FiltreLogApache): Le filtre à appliquer dans l'analyse. Si une entrée ne
31+
passe pas le filtre, elle ne sera pas pris en compte dans l'analyse.
2632
nombre_par_top (int): Le nombre maximal d'éléments à inclure dans
2733
les statistiques des classements (tops). Par défaut, sa valeur est égale à ``3``.
2834
2935
Raises:
30-
TypeError: Si l'argument ``fichier_log_apache`` n'est pas une instance
31-
de :class:`FichierLogApache`
32-
ou si l'argument ``nombre_par_top`` n'est pas un entier.
36+
TypeError: Les paramètres ne sont pas du type attendu.
3337
ValueError: Si l'argument ``nombre_par_top`` est inférieur à ``0``.
3438
"""
3539
# Vérification du type des paramètres
3640
if not isinstance(fichier_log_apache, FichierLogApache):
3741
raise TypeError("La représentation du fichier doit être de type FichierLogApache.")
42+
if not isinstance(filtre, FiltreLogApache):
43+
raise TypeError("Le filtre à appliquer aux entrées doit être de type FiltreLogApache.")
3844
if not isinstance(nombre_par_top, int) or isinstance(nombre_par_top, bool):
3945
raise TypeError("Le nombre par top doit être un entier.")
4046
# Vérification de la valeur du paramètre
@@ -43,8 +49,22 @@ def __init__(self, fichier_log_apache: FichierLogApache, nombre_par_top: int = 3
4349

4450
# Ajout des données
4551
self.fichier = fichier_log_apache
52+
self.filtre = filtre
4653
self.nombre_par_top = nombre_par_top
4754

55+
def _get_entrees_passent_filtre(self) -> list:
56+
"""
57+
Retourne les entrées qui passent le filtre.
58+
59+
Returns:
60+
list: La liste des entrées qui passent le filtre.
61+
"""
62+
entrees_valides = []
63+
for entree in self.fichier.entrees:
64+
if self.filtre.entree_passe_filtre(entree):
65+
entrees_valides.append(entree)
66+
return entrees_valides
67+
4868
def _get_repartition_elements(self,
4969
liste_elements: list,
5070
nom_elements: str,
@@ -94,19 +114,23 @@ def get_analyse_complete(self) -> dict:
94114
95115
L'analyse suit la structure suivante :
96116
- chemin: chemin du fichier
117+
- total_entrees: voir :meth:`get_total_entrees`
118+
- filtre: filtre appliqué à l'analyse
97119
- statistiques:
98-
- requetes:
99-
- top_urls: voir :meth:`get_top_urls`
100-
- repartition_code_statut_http:
101-
voir :meth:`get_total_par_code_statut_http`
120+
- total_entrees_filtre: voir :meth:`get_total_entrees_filtre`
121+
- requetes:
122+
- top_urls: voir :meth:`get_top_urls`
123+
- repartition_code_statut_http: voir :meth:`get_total_par_code_statut_http`
102124
103125
Returns:
104126
dict: L'analyse sous forme d'un dictionnaire.
105127
"""
106128
return {
107129
"chemin": self.fichier.chemin,
130+
"total_entrees": self.get_total_entrees(),
131+
"filtre": self.filtre.get_dict_filtre(),
108132
"statistiques": {
109-
"total_entrees": self.get_total_entrees(),
133+
"total_entrees_filtre": self.get_total_entrees_filtre(),
110134
"requetes": {
111135
"top_urls": self.get_top_urls(),
112136
"repartition_code_statut_http": self.get_total_par_code_statut_http()
@@ -123,9 +147,19 @@ def get_total_entrees(self) -> int:
123147
"""
124148
return len(self.fichier.entrees)
125149

150+
def get_total_entrees_filtre(self) -> int:
151+
"""
152+
Retourne le nombre d'entrées qui ont passées le filtre dans le fichier.
153+
154+
Returns:
155+
int: Le nombre total d'entrées.
156+
"""
157+
return len(self._get_entrees_passent_filtre())
158+
126159
def get_top_urls(self) -> list:
127160
"""
128161
Retourne le top :attr:`nombre_par_top` des urls les plus demandées.
162+
Les entrées prisent en compte sont uniquement celles qui ont passées le filtre.
129163
130164
Returns:
131165
list: Une liste de dictionnaires où chaque clé contient :
@@ -136,14 +170,15 @@ def get_top_urls(self) -> list:
136170
La liste est triée dans l'ordre décroissant du nombre total d'apparitions.
137171
"""
138172
return self._get_repartition_elements(
139-
[entree.requete.url for entree in self.fichier.entrees],
173+
[entree.requete.url for entree in self._get_entrees_passent_filtre()],
140174
"url",
141175
True
142176
)
143177

144178
def get_total_par_code_statut_http(self) -> list:
145179
"""
146180
Retourne la répartition des réponses par code de statut htpp retourné.
181+
Les entrées prisent en compte sont uniquement celles qui ont passées le filtre.
147182
148183
Returns:
149184
list: Une liste de dictionnaires où chaque clé contient :
@@ -154,6 +189,6 @@ def get_total_par_code_statut_http(self) -> list:
154189
La liste est triée dans l'ordre décroissant du nombre total d'apparitions.
155190
"""
156191
return self._get_repartition_elements(
157-
[entree.reponse.code_statut_http for entree in self.fichier.entrees],
192+
[entree.reponse.code_statut_http for entree in self._get_entrees_passent_filtre()],
158193
"code"
159194
)

app/analyse/filtre_log_apache.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
"""
2+
Module pour les filtres lors d'une analyse d'un fichier log Apache.
3+
"""
4+
5+
from typing import Optional
6+
from parse.entree_log_apache import EntreeLogApache
7+
8+
9+
class FiltreLogApache:
10+
"""
11+
Représente le filtre à appliquer lors d'une analyse d'un fichier de log Apache.
12+
13+
Attributes:
14+
adresse_ip (Optional[str]): L'adresse IP que doit avoir une entrée pour
15+
pouvoir passer le filtre. Si sa valeur est ``None``, ce filtre ne sera
16+
pas appliqué.
17+
code_statut_http (Optional[int]): Le code de statut http que doit avoir une entrée
18+
pour pouvoir passer le filtre. Si sa valeur est ``None``, ce filtre ne sera
19+
pas appliqué.
20+
"""
21+
22+
def __init__(self, filtre_adresse_ip: Optional[str], filtre_code_statut_http: Optional[int]):
23+
"""
24+
Initalise le filtre à appliquer lors d'une analyse.
25+
26+
Args:
27+
filtre_adresse_ip (Optional[str]): L'adresse IP que doit avoir une entrée pour
28+
pouvoir passer le filtre. Si sa valeur est ``None``, cette vérification ne sera
29+
pas appliqué.
30+
filtre_code_statut_http (Optional[int]): Le code de statut http que doit
31+
avoir une entrée pour pouvoir passer le filtre. Si sa valeur est ``None``,
32+
cette vérification ne sera pas appliqué.
33+
34+
Raises:
35+
TypeError: Les paramètres ne sont pas du type attendu.
36+
"""
37+
# Vérification des paramètres
38+
if filtre_adresse_ip is not None and not isinstance(filtre_adresse_ip, str):
39+
raise TypeError("L'adresse IP dans un filtre doit être une chaîne de caractère.")
40+
if (filtre_code_statut_http is not None
41+
and not isinstance(filtre_code_statut_http, int)
42+
or isinstance(filtre_code_statut_http, bool)):
43+
raise TypeError("Un code de statut http dans un filtre doit être un entier.")
44+
45+
# Ajout des filtres
46+
self.adresse_ip = filtre_adresse_ip
47+
self.code_statut_http = filtre_code_statut_http
48+
49+
def entree_passe_filtre(self, entree: EntreeLogApache) -> bool:
50+
"""
51+
Indique si l'entrée passée en paramètre passe le filtre.
52+
53+
Args:
54+
entree (EntreeLogApache): L'entrée à vérifier.
55+
56+
Returns:
57+
bool: True si l'entrée passe le filtre, False sinon.
58+
59+
Raises:
60+
TypeError: L'``entrée`` n'est pas de type :class:`EntreeLogApache`
61+
"""
62+
# Vérification du paramètre
63+
if not isinstance(entree, EntreeLogApache):
64+
raise TypeError("L'entrée à vérifier pour le filtre doit être de type EntreeLogApache")
65+
66+
# Vérification que l'entrée passe le filtre
67+
# Application du filtre sur l'adresse IP si activé
68+
if self.adresse_ip is not None:
69+
if self.adresse_ip != entree.client.adresse_ip:
70+
return False
71+
# Application du filtre sur le code de statut http si activé
72+
if self.code_statut_http is not None:
73+
if self.code_statut_http != entree.reponse.code_statut_http:
74+
return False
75+
76+
return True
77+
78+
def get_dict_filtre(self) -> dict:
79+
"""
80+
Retourne le filtre sous forme d'un dictionnaire.
81+
Les clés représentent le champs d'une entrée et leur valeur la valeur
82+
que doit avoir ce champs. Si la valeur d'un filtre est ``None``, cela signifie que
83+
cette vérification n'est pas activé.
84+
85+
Returns:
86+
dict: Les filtres sous forme d'un dictionnaire.
87+
"""
88+
return {
89+
"adresse_ip": self.adresse_ip,
90+
"code_statut_http": self.code_statut_http
91+
}

app/cli/parseur_arguments_cli.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,18 @@ def __set_arguments(self) -> None:
4444
help="Fichier JSON où sera écrit l'analyse. Par défaut, un fichier avec le "
4545
"nom 'analyse-log-apache.json' dans le repertoire courant sera crée.",
4646
)
47+
self.add_argument(
48+
"-i",
49+
"--ip",
50+
type=str,
51+
help="L'adresse IP que doivent avoir les entrées à analyser."
52+
)
53+
self.add_argument(
54+
"-c",
55+
"--code-statut-http",
56+
type=int,
57+
help="Le code de statut http que doivent avoir les entrées à analyser."
58+
)
4759

4860
def parse_args(self,
4961
args: Optional[list] = None,

app/main.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from cli.afficheur_cli import AfficheurCLI
55
from cli.parseur_arguments_cli import ParseurArgumentsCLI, ArgumentCLIException
66
from parse.parseur_log_apache import ParseurLogApache, ParsageLogApacheException
7+
from analyse.filtre_log_apache import FiltreLogApache
78
from analyse.analyseur_log_apache import AnalyseurLogApache
89
from export.exporteur import Exporteur, ExportationException
910

@@ -26,8 +27,10 @@ def main() -> None:
2627
# Analyse syntaxique du fichier log
2728
parseur_log = ParseurLogApache(arguments_cli.chemin_log)
2829
fichier_log = parseur_log.parse_fichier()
30+
# Filtre à appliquer lors de l'analyse
31+
filtre_log = FiltreLogApache(arguments_cli.ip, arguments_cli.code_statut_http)
2932
# Analyse statistique du fichier log
30-
analyseur_log = AnalyseurLogApache(fichier_log)
33+
analyseur_log = AnalyseurLogApache(fichier_log, filtre_log)
3134
analyse = analyseur_log.get_analyse_complete()
3235
# Exportation de l'analyse
3336
exporteur = Exporteur(arguments_cli.sortie)

0 commit comments

Comments
 (0)