Files
logwatcher/docs/architecture.md
T
maurane fa5987215f docs(docs): 📝 update documentation files
update ruff and pyproject.toml. Sync or reinstall the package
2026-09-17 18:13:57 +02:00

164 lines
6.8 KiB
Markdown

# Architecture
## Vue d'ensemble
Logwatcher est un outil en ligne de commande Python qui analyse des fichiers
de logs LAME MDC, identifie les erreurs pertinentes pour le support N2, et
génère des rapports texte.
Le traitement suit un pipeline linéaire :
```text
Flux fichiers fichiers de logs
fichiers de logs
│
▼
parser.py lit et parse les fichiers en LogEntry
│
▼
classifier.py classe chaque entrée : N2 ou hors N2
│
▼
reporter.py génère les trois rapports (all, n2, other)
│
▼
rapports .log
```
```text
Flux mail
boîte Exchange (dossier Logs)
│
▼
read_mail.py
│
▼
perser.py
│
▼
classifier.py
│
▼
reporter.py
│
▼
notifier.py
```
L'envoi du mail précède le déplacement des mails vers `Analyzed`. Si l'envoi échoue, les mails restent dans `Logs` et le rapport est régénéré au prochain passage : un rapport peut être envoyé deux fois en cas d'échec après envoi, mais jamais perdu.
## Structure du package
```text
src/logwatcher/
├── __init__.py # expose __version__
├── __main__.py # point d'entrée : python -m logwatcher
├── cli.py # interface en ligne de commande (Typer)
├── config.py # constantes : chemins, formats, source type
├── logging_config.py # configuration du logging
├── models.py # LogEntry : structure de données
├── mail_reader.py # lecture de la boîte mail (EWS)
├── mail_utils.py # utilitaires boîte mail (dossiers, constantes)
├── notifier.py # envoi du rapport n2 par mail
├── parser.py # lecture et parsing des logs
├── classifier.py # classification N2 / hors N2
└── reporter.py # génération des rapports texte
```
### Modules
#### [`classifier.py`](../src/logwatcher/classifier.py) — classification
* `N2_PATTERNS` : dictionnaire des motifs d'erreurs pertinents pour le N2, fournis par les techniciens.
* `classify_log_entries()` : sépare les entrées en deux listes (relevant, irrelevant) et remplit entry.error_name pour les entrées pertinentes.
#### [`cli.py`](../src/logwatcher/cli.py) — point d'entrée
* Définit `app = typer.Typer()` et la commande principale.
* Valide les arguments (`--input-files` / `--input-dir` mutuellement exclusifs).
* Orchestre le pipeline : parsing → classification → rapports.
* Gère les erreurs utilisateur (`BadParameter`, code de sortie 2) et les erreurs d'exécution (code de sortie 1).
* Expose `--version` (eager, affiche et quitte).
#### [`config.py`](../src/logwatcher/config.py) — constantes
* Chemins : `OUTPUT_PATH`, `RESULT_PATH`, `LOGGING_PATH`, `TEST_PATH`, `FIXTURE_PATH`
* Date et fuseau : `DATETIME_FORMAT`, `FRENCH_TIMEZONE`
* Types : `SourceType` (`FILE`, `MAIL`)
#### [`logging_config.py`](../src/logwatcher/logging_config.py) — logging
* `setup_logging()` : configure le logger racine.
* Handler console (`INFO`, ou `DEBUG` si verbose) + handler fichier.
* Le fichier de log `logwatcher.log` est horodaté et écrit dans le dossier de sortie.
* Les loggers verbeux des dépendances (exchangelib) sont ramenés au niveau WARNING, afin de ne pas polluer `logwatcher.log`.
#### [`mail_reader.py`](../src/logwatcher/mail_reader.py) — lecture de la boîte mail
Accès à la boîte via EWS (exchangelib), en authentification NTLM.
* `connect_to_mailbox()` : lit `EMAIL`, `PASSWORD` et `EWS_URL` dans l'environnement, construit le compte et vérifie la connexion par un aller-retour serveur (accès à `account.protocol.version`).
* `fetch_log_messages()` : retourne les mails du dossier Logs.
* `extract_logs_from_mails()` : pour chaque mail, extrait les logs du corps ou de la pièce jointe `CR_*`, et les normalise en une liste de lignes. Ignore les lignes non conformes et avertit si le corps annonce une pièce jointe introuvable.
* `move_analyzed_mails()` : déplace les mails traités vers le dossier `Analyzed`.
#### [`mail_utils.py`](../src/logwatcher/mails_utils.py) — utilitaires boîte mail
* `get_or_create_folder(account, folder_name)` retourne un dossier du compte, et le crée s'il n'existe pas. Utilisé pour les dossiers `Analyzed` et `Sent`.
* Constantes : `LOG_DIR`, `ANALYZED_FOLDER`, `SENT_FOLDER`, `LOG_IN_ATTACHMENT_PATTERN`.
#### [`notifier.py`](../src/logwatcher/notifier.py) — envoi du rapport
* `send_n2_report(account, summary, n2_log_file)` : construit un message Exchange avec `MAIL_TEMPLATE` comme corps, attache `n2_log_file`, et l'envoie aux destinataires de `N2_REPORT_RECIPIENTS`. Une copie du message envoyé est conservée dans `Logs/Sent` (copy_to_folder). L'envoi passe par les services Exchange (message.send) : aucun serveur SMTP externe n'est requis.
#### [`models.py`](../src/logwatcher/models.py) — LogEntry
Dataclass immuable (par convention) représentant une ligne de log parsée.
Champs principaux :
* `server_ip`, `mdc_server_name` : origine du log
* `store_name` : magasin concerné
* `start_time`, error_time : horodatages
* `error_message` : message d'erreur complet
* `error_name` : nom du pattern N2 correspondant (rempli par le classifier)
* `raw_line` : ligne brute d'origine
* `ligne` : numéro de ligne dans le fichier source
LogEntry est créée uniquement par le parser. Le classifier l'enrichit
(remplit `error_name`). Le modèle lui-même ne contient pas de logique métier.
#### [`parser.py`](../src/logwatcher/parser.py) — lecture et parsing
* Patterns réutilisables : `SERVER_IP_PATTERN`, `MDC_SERVER_NAME_PATTERN`, `DATE_TIME_PATTERN`, `STORE_NAME_PATTERN`, `ERROR_MESSAGE_PATTERN`.
* `LOG_PATTERN` : expression régulière compilée du format d'une ligne LAME MDC.
* `parse_line()` : parse une ligne, retourne `LogEntry | None`.
* `parse_lines()` : parse un itérable de lignes, ignore les lignes non conformes.
* `parse_file()` : lit un fichier (encodage windows-1252) et délègue à `parse_lines()`.
#### [`reporter.py`](../src/logwatcher/reporter.py) — rapports
* Templates texte (`string.Template`) : `BASE_TEMPLATE`, `N2_SUPPORT_TEMPLATE`, `OTHER_TEMPLATE`, `ERROR_TEMPLATE`.
* `build_reports()` : construit les trois rapports (`dict n2, other, all`).
* `write_log_report()` : prend un SourceType (`FILE` ou `MAIL`) pour adapter le libellé de l'en-tête ("Fichier(s) lu(s)" ou "Mail(s) lu(s)"). Les fichiers générés s'appellent `all.log`, `n2.log` et `other.log`.
* `_get_period()` : calcule les bornes min/max des error_time.
## Dépendances
| Package | Rôle |
|---------|------|
| `exchangelib` | Accès EWS à la boîte mail et envoi des rapports |
| `mypy` | Typage statique (dev) |
| `pytest` | Tests (dev) |
| `pytest-cov` | Couverture (dev) |
| `ruff` | Linting/formatage (dev) |
| `typer` | Interface en ligne de commande |