fa5987215f
update ruff and pyproject.toml. Sync or reinstall the package
164 lines
6.8 KiB
Markdown
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 | |