Sistema profesional de análisis de logs con generación automática de reportes usando LLM local (Ollama) por defecto, con soporte para OpenAI, Anthropic y Google, cache in-memory y salida en Excel.
Proyecto refactorizado con arquitectura hexagonal (Ports & Adapters) para máxima mantenibilidad y extensibilidad.
log_analyzer/
├── app/ # Entrypoints (CLI y API)
│ ├── cli.py # Interfaz de línea de comandos
│ └── api.py # API REST con Flask
│
├── src/ # Core del dominio
│ ├── domain/ # Lógica de negocio
│ │ ├── model.py # Entidades y objetos de valor
│ │ └── use_cases.py # Caso de uso: GenerateReportUseCase
│ │
│ ├── ports/ # Interfaces (ABC)
│ │ ├── llm_port.py
│ │ ├── cache_port.py
│ │ ├── log_reader_port.py
│ │ ├── analyzer_port.py
│ │ └── report_writer_port.py
│ │
│ ├── adapters/ # Implementaciones
│ │ ├── llm_factory.py
│ │ ├── llm_ollama.py
│ │ ├── llm_openai.py
│ │ ├── llm_anthropic.py
│ │ ├── llm_google.py
│ │ ├── cache_key.py
│ │ ├── cache_memory.py
│ │ ├── log_reader_fs.py
│ │ ├── analyzer_regex.py
│ │ ├── report_writer_excel.py
│ │ └── report_writer_fs.py
│ │
│ └── config/ # Configuración centralizada
│ ├── settings.py # Variables de entorno
│ ├── constants.py # Constantes del proyecto
│ └── logging_config.py
│
├── datasets/ # Logs de ejemplo
├── out/ # Outputs (generados en runtime)
│ ├── reports/ # Reportes Excel/Markdown
│ └── analysis/ # Análisis JSON
│
├── requirements.txt
├── README.md
└── .gitignore
- Hexagonal (Ports & Adapters): Dominio independiente de infraestructura
- Dependency Inversion: Domain no importa adapters
- Single Responsibility: Cada componente tiene una responsabilidad clara
- Open/Closed: Extensible sin modificar código existente (nuevos adapters)
- Python 3.7+
- Ollama corriendo localmente (si usas
LLM_PROVIDER=ollama) - API keys (opcional) para OpenAI, Anthropic o Google
# Instalar Ollama: https://ollama.ai ollama pull mistral ollama serve
# Clonar o navegar al proyecto
cd log_analyzer
# Crear entorno virtual (recomendado)
python -m venv venv
# Activar entorno virtual
# Windows:
venv\Scripts\activate
# Linux/Mac:
source venv/bin/activate
# Instalar dependencias
pip install -r requirements.txt# Uso básico
python app/cli.py --input datasets/generated_logs.txt
# Especificar directorio de salida
python app/cli.py --input datasets/generated_logs.txt --output ./custom_out
# Con run_id personalizado
python app/cli.py --input datasets/generated_logs.txt --run-id mi-analisis-001
# Con nivel de logging
python app/cli.py --input datasets/generated_logs.txt --log-level DEBUGSalida esperada:
[INFO] Log Analyzer CLI
[INFO] Archivo de entrada: datasets\generated_logs.txt
[INFO] Directorio de salida: out
[INFO] Proveedor LLM: ollama (mistral)
[INFO] Iniciando análisis...
[INFO] [run_id=abc123] Iniciando generación de reporte
[INFO] [run_id=abc123] Leyendo logs desde archivo: datasets\generated_logs.txt
[INFO] [run_id=abc123] Analizando estructura del log
[INFO] [run_id=abc123] Análisis completado: 10 eventos, 6 errores, 2 warnings
[INFO] [run_id=abc123] Generando reporte con LLM
[INFO] [run_id=abc123] Reporte generado exitosamente: out\reports\abc123.xlsx
[OK] ✅ Análisis completado exitosamente!
Run ID: abc123
Reporte Excel: C:\lab\log_analyzer\out\reports\abc123.xlsx
Análisis JSON: C:\lab\log_analyzer\out\analysis\abc123.json
Resumen:
- Total eventos: 10
- Errores: 6
- Warnings: 2
# Iniciar servidor
python app/api.pyEl servidor iniciará en http://localhost:5000
GET / - Información de la API
curl http://localhost:5000/GET /health - Health check
curl http://localhost:5000/healthGET /datasets - Lista de archivos de logs disponibles
curl http://localhost:5000/datasetsRespuesta:
{
"status": "success",
"files": [
{
"name": "log1.txt",
"size_bytes": 2048,
"path": "/absolute/path/to/log1.txt"
},
{
"name": "log2.txt",
"size_bytes": 1024,
"path": "/absolute/path/to/log2.txt"
}
],
"count": 2
}POST /reports/download - Generar y descargar reporte en formato
# Descargar múltiples logs como CSV
curl -X POST http://localhost:5000/reports/download \
-H "Content-Type: application/json" \
-d '{
"report_name": "analisis_mensual",
"format": "csv",
"files": ["log1.txt", "log2.txt"]
}' \
-o analisis_mensual.csv
# Formatos soportados: excel, txt, csv, docRespuesta exitosa:
{
"status": "success",
"file_path": "/app/out/reports/abc123def456_report.csv",
"size_bytes": 4096,
"format": "csv",
"name": "analisis_mensual"
}POST /analyze - Analizar logs
# Ejemplo básico
curl -X POST http://localhost:5000/analyze \
-H "Content-Type: application/json" \
-d '{
"log_text": "2026-02-13 08:30:15 ERROR [main] com.example.service.UserService - Error al procesar\njava.lang.NullPointerException: Cannot invoke method\n\tat com.example.service.UserService.process(UserService.java:45)"
}'
# Con run_id personalizado
curl -X POST http://localhost:5000/analyze \
-H "Content-Type: application/json" \
-d '{
"log_text": "...",
"run_id": "custom-run-001"
}'Respuesta exitosa:
{
"status": "success",
"run_id": "abc123def456",
"report_paths": {
"excel": "C:\\lab\\log_analyzer\\out\\reports\\abc123def456.xlsx"
},
"analysis_path": "C:\\lab\\log_analyzer\\out\\analysis\\abc123def456.json",
"report_format": "excel",
"summary": {
"total_events": 10,
"total_errors": 6,
"total_warnings": 2
}
}Todas las configuraciones se pueden sobrescribir con variables de entorno:
| Variable | Default | Descripción |
|---|---|---|
LLM_PROVIDER |
ollama |
Proveedor LLM (ollama, openai, anthropic, google) |
OLLAMA_BASE_URL |
http://localhost:11434 |
URL de Ollama |
OLLAMA_MODEL |
mistral |
Modelo Ollama |
OPENAI_API_KEY |
"" |
API key de OpenAI |
OPENAI_MODEL |
gpt-4o-mini |
Modelo OpenAI |
ANTHROPIC_API_KEY |
"" |
API key de Anthropic |
ANTHROPIC_MODEL |
claude-sonnet-4-20250514 |
Modelo Anthropic |
GOOGLE_API_KEY |
"" |
API key de Google |
GOOGLE_MODEL |
gemini-1.5-flash |
Modelo Google |
CACHE_ENABLED |
true |
Habilita cache in-memory |
CACHE_TTL_SECONDS |
60 |
TTL del cache en segundos |
REPORT_FORMAT |
excel |
Formato de reporte (excel, markdown, both) |
OUT_DIR |
./out |
Directorio de salida |
DATASETS_DIR |
./datasets |
Directorio de datasets (logs disponibles) |
REPORT_DOWNLOAD_MAX_FILES |
10 |
Máximo de archivos para descargar reportes |
LOG_LEVEL |
INFO |
Nivel de logging (DEBUG, INFO, WARN, ERROR) |
REQUEST_TIMEOUT_SECONDS |
120 |
Timeout para requests HTTP |
Ejemplo:
# Windows CMD
set LLM_PROVIDER=ollama
set OLLAMA_MODEL=llama2
set LOG_LEVEL=DEBUG
python app/cli.py --input datasets/generated_logs.txt
# Linux/Mac
export LLM_PROVIDER=ollama
export OLLAMA_MODEL=llama2
export LOG_LEVEL=DEBUG
python app/cli.py --input datasets/generated_logs.txtEl sistema genera dos tipos de archivos en out/:
Análisis estructurado determinista del log:
{
"summary": {
"total_events": 10,
"total_errors": 6,
"total_warnings": 2
},
"error_groups": [
{
"exception": "NullPointerException",
"count": 2,
"top_frame": {
"where": "com.example.service.UserService.process",
"file": "UserService.java",
"line": 45
},
"logger": "com.example.service.UserService",
"samples": [...],
"first_ts": "2026-02-13 08:30:15",
"last_ts": "2026-02-13 08:35:17"
}
],
"warnings": [...],
"events": [...]
}Reporte tabular con formato profesional, generado por defecto.
Reporte profesional generado por el LLM con:
- Resumen ejecutivo
- Análisis de patrones
- Detalle de grupos de errores
- Recomendaciones técnicas
- Conclusiones
La API REST NO tiene autenticación implementada. Consideraciones:
- ✅ OK para desarrollo local
- ✅ OK para redes internas protegidas
- ❌ NO exponer en internet sin autenticación
- ❌ NO usar en producción sin seguridad adicional
Para producción, considerar:
- API Keys / Bearer tokens
- OAuth2 / JWT
- Rate limiting
- Firewall / VPN
- HTTPS obligatorio
El sistema envía los logs directamente al LLM. Si los logs contienen contenido malicioso o instrucciones de prompt injection, podrían influir en la salida del reporte.
Mitigaciones:
- Validar/sanitizar logs antes de procesar
- Usar modelos locales (Ollama) para evitar fuga de datos
- Revisar outputs generados en entornos críticos
set LLM_PROVIDER=openai
set OPENAI_API_KEY=tu_api_key
python app/cli.py --input datasets/generated_logs.txtset OLLAMA_BASE_URL=http://192.168.1.100:11434
python app/cli.py --input datasets/generated_logs.txtset REPORT_FORMAT=both
python app/cli.py --input datasets/generated_logs.txtset CACHE_TTL_SECONDS=120
python app/cli.py --input datasets/generated_logs.txtset REQUEST_TIMEOUT_SECONDS=300
python app/cli.py --input large_logs.txtpython app/cli.py --input datasets/generated_logs.txt --log-level DEBUGGracias a la arquitectura hexagonal, puedes extender el sistema fácilmente:
- Crear un adapter en
src/adapters/implementandoLLMPort - Registrar el adapter en
src/adapters/llm_factory.py - Usar
LLM_PROVIDERpara seleccionarlo sin tocar entrypoints
- Crear
src/adapters/log_reader_s3.pyimplementandoLogReaderPort - Usar en el entrypoint que corresponda
- Crear
src/adapters/analyzer_ml.pyimplementandoAnalyzerPort - Reemplazar
RegexLogAnalyzer()porMLAnalyzer()
El dominio no cambia, solo los adapters.
El .gitignore incluye out/ por defecto porque:
- ✅ Los reportes pueden contener información sensible
- ✅ Son archivos generados (no fuente)
- ✅ Cada ejecución genera nuevos archivos (ruido en git)
Si quieres versionar reportes específicos:
git add -f out/reports/importante.md# Verifica que Ollama esté corriendo
ollama serve
# Verifica el endpoint
curl http://localhost:11434/api/version# Descarga el modelo
ollama pull mistral# Aumenta el timeout
set REQUEST_TIMEOUT_SECONDS=300El formato DOC requiere python-docx (ya incluido en requirements.txt):
pip install python-docxNota: Los formatos Excel, CSV, TXT y Markdown funcionan sin esta dependencia gracias a lazy imports.
Si ves UnicodeEncodeError en la consola, el servidor lo maneja automáticamente desde la versión actual.
El analyzer usa regex específicos para logs tipo Java/Spring. Para otros formatos:
- Crear un nuevo analyzer implementando
AnalyzerPort - Reemplazar
RegexLogAnalyzeren los entrypoints
Para agregar nuevas funcionalidades:
- Ports: Define la interfaz (ABC) en
src/ports/ - Adapters: Implementa la interfaz en
src/adapters/ - Use Cases: Actualiza lógica de negocio en
src/domain/use_cases.py - Entrypoints: Compone dependencias en
app/cli.pyoapp/api.py
Este proyecto es de código abierto para fines educativos y de laboratorio.
- Patrón: Hexagonal (Ports & Adapters)
- Lenguaje: Python 3.7+
- LLM: Ollama (default), OpenAI, Anthropic, Google
- Framework API: Flask
- Testing: Arquitectura permite fácil testing con mocks de ports
- Logging:
loggingestándar con run_id tracking - Config: Variables de entorno + defaults
- Output: JSON (análisis) + Excel/Markdown (reporte)
Ventajas de esta arquitectura:
- ✅ Dominio desacoplado de infraestructura
- ✅ Fácil testing (mock de ports)
- ✅ Extensible sin modificar dominio
- ✅ Mantenible a largo plazo
- ✅ Claro y documentado
Maximiliano Rodrigo Soria
- 📱 Teléfono: +54 9 11 2704-3256 (Argentina)
- 💼 GitHub: MaximilianoRodrigoSoria
Para consultas, sugerencias o contribuciones al proyecto.
Happy logging! 📊🚀
flowchart TD
subgraph Entrypoints["🚪 Entrypoints"]
CLI["CLI · app/cli.py"]
API["API REST Flask · app/api.py"]
end
UC["AnalyzeUseCase<br/>(src/domain)"]
subgraph Ports["🔌 Ports (interfaces)"]
P1["LogReaderPort"]
P2["AnalyzerPort"]
P3["LLMPort"]
P4["CachePort"]
P5["ReportExporterPort"]
end
subgraph Adapters["🧩 Adapters (implementaciones)"]
A1["log_reader_fs"]
A2["analyzer_regex"]
A3["llm_factory<br/>Ollama · OpenAI · Anthropic · Google"]
A4["cache_memory"]
A5["report_exporter<br/>Excel · CSV · Markdown · TXT · DOC"]
end
OUT["📄 Reporte<br/>(Excel / CSV / MD / ...)"]
CLI --> UC
API --> UC
UC --> P1 --> A1
UC --> P2 --> A2
UC --> P3 --> A3
UC --> P4 --> A4
UC --> P5 --> A5
A5 --> OUT
