Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,5 @@ Thumbs.db
# Project specific
json/
html/
logs/
*.log
42 changes: 42 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ checkpatch/
├── core.py # Implementaciones de fixes (40+)
├── compile.py # Módulo de compilación de archivos
├── report.py # Generadores de HTML (8 reportes)
├── logger.py # Sistema de logging unificado ⭐ NUEVO
├── utils.py # Utilidades comunes
├── constants.py # Constantes y patterns
├── test_all.py # Suite unificada de tests
Expand Down Expand Up @@ -168,6 +169,13 @@ Sistema modular de **8 reportes interconectados** con navegación por breadcrumb
- Auto-scroll a anchors
- Sin dependencias externas

### ✅ Sistema de Logging
- Niveles configurables (DEBUG, INFO, WARNING, ERROR, CRITICAL)
- Salida colorizada por nivel de severidad
- Archivo de log opcional con timestamps
- Compatible con formato existente de mensajes
- Útil para debugging y análisis de problemas

---

## 📈 Estadísticas Actuales
Expand Down Expand Up @@ -259,6 +267,40 @@ Características:
- Puede restaurar backups antes/después de compilar
- Muestra errores de compilación detallados

### Logging y Debug ⭐ NUEVO
```bash
# Nivel de debug (muestra mensajes DEBUG adicionales)
./main.py --analyze /path/to/kernel --log-level DEBUG

# Nivel INFO (default, mensajes informativos)
./main.py --fix --json-input json/checkpatch.json --log-level INFO

# Nivel WARNING (solo warnings y errores)
./main.py --fix --json-input json/checkpatch.json --log-level WARNING

# Guardar log en archivo
./main.py --analyze /path/to/kernel --log-file logs/checkpatch.log

# Desactivar colores (útil para redireccionar output)
./main.py --fix --json-input json/checkpatch.json --no-color

# Combinación: DEBUG + archivo + sin colores
./main.py --analyze /path/to/kernel --log-level DEBUG --log-file logs/debug.log --no-color
```

Niveles de logging disponibles:
- `DEBUG` - Mensajes de debugging detallados (argumentos, archivos procesados, etc.)
- `INFO` - Mensajes informativos (default) - progreso, resultados, archivos modificados
- `WARNING` - Solo advertencias y errores
- `ERROR` - Solo errores críticos
- `CRITICAL` - Solo errores críticos del sistema

Características:
- Salida colorizada por nivel (rojo=ERROR, amarillo=WARNING, cyan=INFO, gris=DEBUG)
- Archivo de log con timestamps completos (guarda todos los niveles incluido DEBUG)
- Compatible con el formato de mensajes existente `[ANALYZER]`, `[AUTOFIX]`, `[COMPILE]`
- El archivo de log siempre captura nivel DEBUG, independiente del nivel de consola

### Tests y Análisis
```bash
# Suite unificada de tests (12 tests: compilation + fixes + integration)
Expand Down
13 changes: 7 additions & 6 deletions compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from typing import List, Dict, Tuple, Optional
import json
import time
import logger


class CompilationResult:
Expand Down Expand Up @@ -61,7 +62,7 @@ def ensure_kernel_configured(kernel_root: Path) -> bool:
if config_file.exists():
return True

print("[COMPILE] Kernel not configured. Running 'make defconfig'...")
logger.info("[COMPILE] Kernel not configured. Running 'make defconfig'...")
try:
result = subprocess.run(
['make', 'defconfig'],
Expand All @@ -72,14 +73,14 @@ def ensure_kernel_configured(kernel_root: Path) -> bool:
)

if result.returncode == 0 and config_file.exists():
print("[COMPILE] ✓ Kernel configured successfully")
logger.info("[COMPILE] ✓ Kernel configured successfully")
return True
else:
print(f"[COMPILE] ✗ Failed to configure kernel: {result.stderr[:200]}")
logger.error(f"[COMPILE] ✗ Failed to configure kernel: {result.stderr[:200]}")
return False

except Exception as e:
print(f"[COMPILE] ✗ Exception while configuring kernel: {e}")
logger.error(f"[COMPILE] ✗ Exception while configuring kernel: {e}")
return False


Expand Down Expand Up @@ -222,7 +223,7 @@ def cleanup_compiled_files(kernel_root: Path, compiled_files: List[Path]):

if obj_path.exists():
obj_path.unlink()
print(f"[CLEANUP] Removed: {obj_path.relative_to(kernel_root)}")
logger.debug(f"[CLEANUP] Removed: {obj_path.relative_to(kernel_root)}")

# También limpiar posibles archivos auxiliares (.cmd, .d, etc.)
cmd_file = obj_path.parent / f".{obj_path.name}.cmd"
Expand All @@ -234,7 +235,7 @@ def cleanup_compiled_files(kernel_root: Path, compiled_files: List[Path]):
d_file.unlink()

except Exception as e:
print(f"[CLEANUP WARNING] Could not clean {c_file}: {e}")
logger.warning(f"[CLEANUP WARNING] Could not clean {c_file}: {e}")


def compile_modified_files(files: List[Path], kernel_root: Path,
Expand Down
190 changes: 190 additions & 0 deletions logger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
#!/usr/bin/env python3
"""
logger.py - Sistema de logging unificado para checkpatch

Proporciona logging con niveles configurables y soporte para archivo de log.
"""

import logging
import sys
from pathlib import Path


# Colores ANSI para la consola
class Colors:
RESET = "\033[0m"
RED = "\033[91m"
GREEN = "\033[92m"
YELLOW = "\033[93m"
BLUE = "\033[94m"
MAGENTA = "\033[95m"
CYAN = "\033[96m"
GRAY = "\033[90m"


# Mapeo de niveles a prefijos y colores
LEVEL_CONFIG = {
logging.DEBUG: ("DEBUG", Colors.GRAY),
logging.INFO: ("INFO", Colors.CYAN),
logging.WARNING: ("WARNING", Colors.YELLOW),
logging.ERROR: ("ERROR", Colors.RED),
logging.CRITICAL: ("CRITICAL", Colors.MAGENTA),
}


class ColoredFormatter(logging.Formatter):
"""Formateador que añade colores a los mensajes de consola."""

def __init__(self, use_colors=True):
super().__init__()
self.use_colors = use_colors

def format(self, record):
if self.use_colors:
level_name, color = LEVEL_CONFIG.get(record.levelno, ("INFO", Colors.CYAN))

# Si el mensaje tiene un prefijo como [ANALYZER], [AUTOFIX], etc., respetarlo
msg = record.getMessage()
if msg.startswith('['):
# Mantener el formato existente con prefijo
return f"{color}{msg}{Colors.RESET}"
else:
# Nuevo formato con nivel de log
return f"{color}[{level_name}]{Colors.RESET} {msg}"
else:
return record.getMessage()


class CheckpatchLogger:
"""Logger singleton para toda la aplicación."""

_instance = None
_initialized = False

def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance

def __init__(self):
if not self._initialized:
self.logger = logging.getLogger('checkpatch')
self.logger.setLevel(logging.DEBUG) # Capturar todos los niveles
self.logger.propagate = False
self._initialized = True
self.file_handler = None
self.console_handler = None

def setup(self, level=logging.INFO, log_file=None, use_colors=True):
"""
Configura el sistema de logging.

Args:
level: Nivel de logging (DEBUG, INFO, WARNING, ERROR, CRITICAL)
log_file: Path opcional para archivo de log
use_colors: Si True, usa colores en la salida de consola
"""
# Limpiar handlers existentes
self.logger.handlers.clear()

# Console handler
self.console_handler = logging.StreamHandler(sys.stdout)
self.console_handler.setLevel(level)
self.console_handler.setFormatter(ColoredFormatter(use_colors=use_colors))
self.logger.addHandler(self.console_handler)

# File handler (opcional)
if log_file:
log_path = Path(log_file)
log_path.parent.mkdir(parents=True, exist_ok=True)

self.file_handler = logging.FileHandler(log_path, mode='a', encoding='utf-8')
self.file_handler.setLevel(logging.DEBUG) # El archivo captura todo
# Sin colores para el archivo
file_formatter = logging.Formatter(
'%(asctime)s - %(levelname)-8s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
self.file_handler.setFormatter(file_formatter)
self.logger.addHandler(self.file_handler)

def debug(self, msg):
"""Log a nivel DEBUG."""
self.logger.debug(msg)

def info(self, msg):
"""Log a nivel INFO."""
self.logger.info(msg)

def warning(self, msg):
"""Log a nivel WARNING."""
self.logger.warning(msg)

def error(self, msg):
"""Log a nivel ERROR."""
self.logger.error(msg)

def critical(self, msg):
"""Log a nivel CRITICAL."""
self.logger.critical(msg)


# Instancia global singleton
_logger_instance = CheckpatchLogger()


def setup_logging(level=logging.INFO, log_file=None, use_colors=True):
"""
Configura el sistema de logging global.

Args:
level: Nivel de logging (logging.DEBUG, logging.INFO, etc.)
log_file: Path opcional para archivo de log
use_colors: Si True, usa colores en la salida de consola
"""
_logger_instance.setup(level, log_file, use_colors)


def debug(msg):
"""Log a nivel DEBUG."""
_logger_instance.debug(msg)


def info(msg):
"""Log a nivel INFO."""
_logger_instance.info(msg)


def warning(msg):
"""Log a nivel WARNING."""
_logger_instance.warning(msg)


def error(msg):
"""Log a nivel ERROR."""
_logger_instance.error(msg)


def critical(msg):
"""Log a nivel CRITICAL."""
_logger_instance.critical(msg)


def get_level_from_string(level_str):
"""
Convierte string a nivel de logging.

Args:
level_str: String con el nivel (DEBUG, INFO, WARNING, ERROR, CRITICAL)

Returns:
logging level constant
"""
level_map = {
'DEBUG': logging.DEBUG,
'INFO': logging.INFO,
'WARNING': logging.WARNING,
'ERROR': logging.ERROR,
'CRITICAL': logging.CRITICAL,
}
return level_map.get(level_str.upper(), logging.INFO)
Loading