Files

133 lines
4.4 KiB
Markdown

# Especificación de Logging — ComercioNet
## Objetivo
Implementar un sistema de logging jerárquico con formato visual de árbol (`├──`, `└──`, `│`) que permita entender rápidamente el flujo de procesamiento de cada archivo y sus sub-operaciones (SAP B1, SQL, etc.).
## API
El módulo `logger_manager.py` expone una función única:
```python
from logger_manager import get_logger
log = get_logger() # devuelve una instancia de TaskLogger
```
### Métodos de `TaskLogger`
| Método | Descripción | Prefijo visual |
|---|---|---|
| `info(msg, _last=False)` | Mensaje informativo | `├──` o `└──` |
| `warning(msg, _last=False)` | Advertencia | `├──` o `└──` |
| `error(msg, _last=False)` | Error | `├──` o `└──` |
| `task(name, emoji="")` | Context manager — abre un bloque anidado (push depth) | `├── + emoji + name` |
| `last_task(name, emoji="")` | Context manager — último bloque del padre (push depth) | `└── + emoji + name` |
### Parámetro `_last`
En `info()`, `warning()`, `error()`, el parámetro `_last=True` cambia el prefijo de `├──` a `└──`, indicando que es el último mensaje en ese nivel.
```python
log.info("Primer paso") # ├── Primer paso
log.info("Paso intermedio") # ├── Paso intermedio
log.info("Último paso", _last=True) # └── Último paso
```
## Estructura jerárquica con `task()` / `last_task()`
```python
with log.task("📦 Archivo X.xml"):
log.info("XML parseado")
with log.task("🔐 SAP B1"):
log.info("Sesión iniciada")
log.info("Catálogo OK")
log.last_task("📁 Movido a processed")
```
### Salida generada
```
2026-07-31 10:15:03 ─── 📦 Archivo X.xml
├── XML parseado
├── 🔐 SAP B1
│ ├── Sesión iniciada
│ └── Catálogo OK
└── 📁 Movido a processed
```
## Formato de cada línea
```
{timestamp} ─── {prefijo_árbol}{mensaje}
```
Ejemplo:
```
2026-07-31 10:15:03 ─── │ ├── XML parseado
```
- `timestamp`: `YYYY-MM-DD HH:mm:ss` (precisión de segundos)
- `───`: separador fijo
- `prefijo_árbol`: caracteres de indentación y árbol según profundidad
- `mensaje`: texto del log
## Formato en archivo de log
El archivo `logs/comercio-net.log` usa el mismo formato con caracteres de árbol. No se incluyen niveles (INFO, WARNING, ERROR) en el texto — la diferenciación visual se logra con emojis y el contexto jerárquico.
## Emojis por etapa
| Etapa | Emoji |
|---|---|
| Procesar archivo XML | 📦 |
| Parseo XML / datos extraídos | 📄 |
| Guardar JSON / HTML | 💾 |
| SAP B1 (sesión, catálogo, draft) | 🔐 |
| Consultas HTTP (GET / POST) | 🔄 |
| Éxito / Draft creado | ✅ |
| Advertencia (precio difiere) | ⚠️ |
| Error | ❌ |
| Archivo movido | 📁 |
| Inicio / fin de servicio | 🚀 / 🛑 |
## Configuración vía entorno
Variable `LOG_LEVEL` en `.env` (valores: `DEBUG`, `INFO`, `WARNING`, `ERROR`). Por defecto `INFO`.
```
LOG_LEVEL=DEBUG
```
## Thread-safety
Se usa `contextvars` para mantener el stack de profundidad por cada hilo / contexto asíncrono, permitiendo ejecución concurrente sin mezclar indentaciones.
## Archivos modificados
| Archivo | Cambio |
|---|---|
| `logger_manager.py` | Clases `TaskLogger`, `TreeFormatter`, `_TaskContext`. `get_logger()` devuelve `TaskLogger`. |
| `service.py` | Usa `get_logger()`. `process_file()` y bloques SAP envueltos con `task()`. |
| `sapb1_manager.py` | Usa `log.info()/warning()/error()` en lugar de `print()`. |
| `sql_manager.py` | Usa `log.error()` en lugar de `print()`. |
| `main.py` | Usa `get_logger()` y `task()` en el ciclo principal. |
| `mail_sender.py` | Usa `log.info()/warning()` para logging de envío de correos. |
## Ejemplo completo de salida
```
2026-07-31 10:15:03 ─── 🚀 Servicio ComercioNet - Procesador OC
2026-07-31 10:15:03 ─── 📦 OC98765.xml
├── 📄 XML parseado (orden E001-2439)
├── 💾 JSON guardado en data/output/OC98765.json
├── 💾 HTML generado
├── 🔐 SAP B1
│ ├── Sesión iniciada (B1SESSION: a634d0ec...)
│ ├── 🔄 [GET] CardCode por GLN
│ ├── Catálogo: 1520 items
│ ├── Precios: 980 registros
│ ├── ✅ Draft creado → DocEntry 2022
│ └── 💾 Payload guardado
└── 📁 XML movido a processed/
```