--- title: Logging Constraints category: constraints severity: critical --- # Logging Constraints ## Core Rule Use `logging.getLogger(__name__)` - never use `print()` **CRITICAL ANTI-PATTERN**: `api_client.py` uses `print()` instead of logging (11 instances). ## CRITICAL Anti-Pattern: print() Instead of Logging **File**: `api_client.py` **Evidence**: Lines with `print(f"...")` instead of `_logger.info(...)` **Broken code**: ```python def get_motions(self, ...): try: # ... print(f"Fetched {len(voting_records)} voting records from API") # BAD print(f"Processed into {len(motions)} unique motions") # BAD except Exception as e: print(f"Error fetching motions from API: {e}") # BAD - no traceback ``` **Fix**: ```python import logging _logger = logging.getLogger(__name__) def get_motions(self, ...): try: _logger.info("Fetched %d voting records from API", len(voting_records)) _logger.info("Processed into %d unique motions", len(motions)) except Exception as e: _logger.exception("Error fetching motions from API: %s", e) return [] ``` ## Logger Initialization Get logger at module level: ```python # GOOD: Use logging.getLogger(__name__) import logging _logger = logging.getLogger(__name__) def some_function(): _logger.info("Processing started") _logger.debug("Detail: %s", detail) ``` ## Logger Naming Use `__name__` for automatic module path: ```python # In database.py - logger will be "database" _logger = logging.getLogger(__name__) # In pipeline/svd_pipeline.py - logger will be "pipeline.svd_pipeline" _logger = logging.getLogger(__name__) ``` **INCONSISTENCY WARNING**: 16 files use `logger`, 17 files use `_logger`. Choose one convention. **Recommendation**: Use `_logger` (with underscore) for module-level loggers to distinguish from class-level loggers. ## Log Levels | Level | When to Use | |-------|-------------| | DEBUG | Detailed diagnostic info (dev only) | | INFO | Normal operation milestones | | WARNING | Unexpected but handled (fallbacks) | | ERROR | Operation failed, may need attention | | CRITICAL | Fatal error, program may crash | ## Exception Logging Use `_logger.exception()` for caught exceptions (includes traceback): ```python try: result = risky_operation() except Exception as exc: _logger.exception("Operation failed: %s", exc) return fallback_value ``` ## Anti-Patterns ### Debug Prints in Production Code ```python # BAD print(f"[TRAJ DEBUG] processing window {wid}") # GOOD _logger.debug("Processing window %s", wid) ``` ### Inconsistent Logger Names ```python # BAD - mixing _logger and logger _logger = logging.getLogger(__name__) logger = logging.getLogger("other") # Inconsistent ``` ## Sensitive Data Never log sensitive information: - API keys - User votes - Session IDs (if tied to user data) - Personal information ```python # BAD _logger.info("User %s voted %s", user_id, vote) # GOOD - log aggregates, not individual votes _logger.info("Vote recorded for session %s", session_id[:8]) ```