""" Debug logging utilities Fast checks with minimal overhead when debug is disabled. """ from django.core.cache import cache import os def is_debug_enabled(): """ Fast check if debug logging is enabled. Uses cache to avoid DB queries. Returns False immediately if disabled. Returns: bool: True if debug logging enabled, False otherwise """ # Check cache first (fastest) cache_key = 'debug_enabled' enabled = cache.get(cache_key) # If we have a cached value (True or False), use it if enabled is not None: return bool(enabled) # Cache miss - check database try: from igny8_core.business.system.models import DebugConfiguration config = DebugConfiguration.get_config() enabled = config.enable_debug_logging # Cache the actual boolean value cache.set(cache_key, enabled, 60) # Cache for 1 minute return bool(enabled) except Exception as e: # If DB not ready or model doesn't exist, default to False # Cache this to avoid repeated DB errors cache.set(cache_key, False, 10) return False def _should_log_in_this_worker(): """ Only log in the main worker to avoid duplicate logs. Returns True if this is the first worker or if we should always log. """ # Get worker PID - only log from worker with lowest PID to avoid duplicates worker_pid = os.getpid() # Cache the first worker PID that tries to log first_worker = cache.get('debug_first_worker_pid') if first_worker is None: cache.set('debug_first_worker_pid', worker_pid, 300) # Cache for 5 minutes return True # Only log if we're the first worker return worker_pid == first_worker def debug_log(message, category='general'): """ Log a debug message only if debug is enabled. Completely skips processing if debug is disabled. Args: message: Message to log category: Log category (ai_steps, api_requests, db_queries, celery_tasks) """ # Fast exit - don't even process the message if debug is disabled if not is_debug_enabled(): return # Only log in one worker to avoid duplicates if not _should_log_in_this_worker(): return # Check category-specific settings try: from igny8_core.business.system.models import DebugConfiguration config = DebugConfiguration.get_config() # Check category-specific flags if category == 'ai_steps' and not config.log_ai_steps: return if category == 'api_requests' and not config.log_api_requests: return if category == 'db_queries' and not config.log_database_queries: return if category == 'celery_tasks' and not config.log_celery_tasks: return except Exception: pass # Debug is enabled - log to console import sys import datetime timestamp = datetime.datetime.now().strftime("%H:%M:%S") worker_pid = os.getpid() prefix = f"[{timestamp}] [PID:{worker_pid}] [DEBUG:{category.upper()}]" print(f"{prefix} {message}", file=sys.stdout, flush=True) def debug_log_ai_step(step_name, message, **kwargs): """ Log an AI execution step only if debug is enabled. Completely skips processing if debug is disabled. Args: step_name: Name of the step (INIT, PREPARE, AI_CALL, etc.) message: Step message **kwargs: Additional context to log """ # Fast exit - don't even process if debug is disabled if not is_debug_enabled(): return # Only log in one worker to avoid duplicates if not _should_log_in_this_worker(): return # Format the message with context context_str = "" if kwargs: context_parts = [f"{k}={v}" for k, v in kwargs.items()] context_str = f" | {', '.join(context_parts)}" full_message = f"[{step_name}] {message}{context_str}" debug_log(full_message, category='ai_steps')