From fbc757f0a6186202e05ac2ab6ef855a3e2d7fc84 Mon Sep 17 00:00:00 2001 From: Lorenzo Venerandi Date: Sun, 1 Mar 2026 17:36:29 +0100 Subject: [PATCH] feat: Enhance logging configuration to support dynamic log levels --- src/app.py | 2 +- src/config.py | 6 ++++++ src/database.py | 27 +++++++++++++++++++++++++++ src/logger.py | 15 +++++++++------ 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/app.py b/src/app.py index 788bcf2..2b2df92 100644 --- a/src/app.py +++ b/src/app.py @@ -26,7 +26,7 @@ async def lifespan(app: FastAPI): config = get_config() # Initialize logging - initialize_logging() + initialize_logging(log_level=config.log_level) app_logger = get_app_logger() # Initialize database and run pending migrations before accepting traffic diff --git a/src/config.py b/src/config.py index 3bdf7e5..8344883 100644 --- a/src/config.py +++ b/src/config.py @@ -56,6 +56,8 @@ class Config: user_agents_used_threshold: float = None attack_urls_threshold: float = None + log_level: str = "INFO" + _server_ip: Optional[str] = None _server_ip_cache_time: float = 0 _ip_cache_ttl: int = 300 @@ -163,6 +165,7 @@ class Config: behavior = data.get("behavior", {}) analyzer = data.get("analyzer") or {} crawl = data.get("crawl", {}) + logging_cfg = data.get("logging", {}) # Handle dashboard_secret_path - auto-generate if null/not set dashboard_path = dashboard.get("secret_path") @@ -217,6 +220,9 @@ class Config: ), max_pages_limit=crawl.get("max_pages_limit", 250), ban_duration_seconds=crawl.get("ban_duration_seconds", 600), + log_level=os.getenv( + "KRAWL_LOG_LEVEL", logging_cfg.get("level", "INFO") + ).upper(), ) diff --git a/src/database.py b/src/database.py index 50fd5a0..2119893 100644 --- a/src/database.py +++ b/src/database.py @@ -848,6 +848,33 @@ class DatabaseManager: session.rollback() raise + def flag_all_ips_for_reevaluation(self) -> int: + """ + Flag ALL IPs for reevaluation, regardless of staleness. + Skips IPs that have a manual category set. + + Returns: + Number of IPs flagged for reevaluation + """ + session = self.session + try: + count = ( + session.query(IpStats) + .filter( + IpStats.need_reevaluation == False, + IpStats.manual_category == False, + ) + .update( + {IpStats.need_reevaluation: True}, + synchronize_session=False, + ) + ) + session.commit() + return count + except Exception as e: + session.rollback() + raise + def get_access_logs_paginated( self, page: int = 1, diff --git a/src/logger.py b/src/logger.py index 9762002..d556684 100644 --- a/src/logger.py +++ b/src/logger.py @@ -36,12 +36,13 @@ class LoggerManager: cls._instance._initialized = False return cls._instance - def initialize(self, log_dir: str = "logs") -> None: + def initialize(self, log_dir: str = "logs", log_level: str = "INFO") -> None: """ Initialize the logging system with rotating file handlers.loggers Args: log_dir: Directory for log files (created if not exists) + log_level: Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL) """ if self._initialized: return @@ -59,9 +60,11 @@ class LoggerManager: max_bytes = 1048576 # 1MB backup_count = 5 + level = getattr(logging, log_level.upper(), logging.INFO) + # Setup application logger self._app_logger = logging.getLogger("krawl.app") - self._app_logger.setLevel(logging.INFO) + self._app_logger.setLevel(level) self._app_logger.handlers.clear() app_file_handler = RotatingFileHandler( @@ -78,7 +81,7 @@ class LoggerManager: # Setup access logger self._access_logger = logging.getLogger("krawl.access") - self._access_logger.setLevel(logging.INFO) + self._access_logger.setLevel(level) self._access_logger.handlers.clear() access_file_handler = RotatingFileHandler( @@ -95,7 +98,7 @@ class LoggerManager: # Setup credential logger (special format, no stream handler) self._credential_logger = logging.getLogger("krawl.credentials") - self._credential_logger.setLevel(logging.INFO) + self._credential_logger.setLevel(level) self._credential_logger.handlers.clear() # Credential logger uses a simple format: timestamp|ip|username|password|path @@ -152,6 +155,6 @@ def get_credential_logger() -> logging.Logger: return _logger_manager.credentials -def initialize_logging(log_dir: str = "logs") -> None: +def initialize_logging(log_dir: str = "logs", log_level: str = "INFO") -> None: """Initialize the logging system.""" - _logger_manager.initialize(log_dir) + _logger_manager.initialize(log_dir, log_level)