You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

167 lines
3.5 KiB

# Logging Constraints
## Core Rule
**Use `logging.getLogger(__name__)` - never use `print()`**
## 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__)
```
## 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 |
## Examples
### Good Logging Practice
```python
_logger.info("Pipeline run: %s → %s (%s windows)", start, end, count)
_logger.debug("Batch embedding attempt %d failed: %s", attempt, exc)
_logger.warning("Fallback used for motion %d: %s", motion_id, reason)
_logger.error("Query failed: %s", exc)
```
### Bad: Using print()
```python
# BAD - don't use print
print(f"Fetched {len(voting_records)} voting records from API")
print(f"Error fetching motions from API: {e}")
```
### Good: Using logger
```python
# GOOD - use logger
_logger.info("Fetched %d voting records from API", len(voting_records))
_logger.error("Error fetching motions from API: %s", e)
```
## 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
```
Use `_logger.error()` with explicit exception for controlled errors:
```python
try:
result = risky_operation()
except Exception as exc:
_logger.error("Operation failed: %s", exc)
return fallback_value
```
## Configuration
Ensure logging is configured in entry points:
```python
# pipeline/run_pipeline.py
def run(args):
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)s %(name)s: %(message)s",
)
# ... rest of pipeline
```
## 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
# GOOD - use single consistent pattern
_logger = logging.getLogger(__name__)
```
### Missing Logger Initialization
```python
# BAD - no logger defined
def some_function():
logging.getLogger(__name__).info("...") # Redundant calls
# GOOD - define once at module level
_logger = logging.getLogger(__name__)
def some_function():
_logger.info("...")
```
## 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])
```
## Structured Logging
For complex data, use structured logging:
```python
_logger.info(
"Motion processed",
extra={
"motion_id": motion_id,
"policy_area": policy_area,
"processing_time_ms": elapsed_ms,
}
)
```