# Universal Logging System

## Overview

The universal logging system provides consistent, rotated logging across all Media Downloader components with automatic cleanup of old logs.

## Features

- ✅ **Consistent Format**: All components use the same log format
- ✅ **Automatic Rotation**: Logs rotate daily at midnight
- ✅ **Automatic Cleanup**: Logs older than 7 days are automatically deleted
- ✅ **Separate Log Files**: Each component gets its own log file
- ✅ **Flexible Levels**: Support for DEBUG, INFO, WARNING, ERROR, CRITICAL, SUCCESS
- ✅ **Module Tagging**: Messages tagged with module name for easy filtering

## Log Format

```
2025-11-13 10:30:00 [MediaDownloader.ComponentName] [Module] [LEVEL] message
```

Example:
```
2025-11-13 10:30:00 [MediaDownloader.API] [Core] [INFO] Server started on port 8000
2025-11-13 10:30:05 [MediaDownloader.Scheduler] [Instagram] [SUCCESS] Downloaded 5 new items
```

## Usage

### Basic Usage

```python
from modules.universal_logger import get_logger

# Get logger for your component
logger = get_logger('ComponentName')

# Log messages
logger.info("Application started", module="Core")
logger.debug("Processing item", module="Instagram")
logger.warning("Retry attempt", module="Network")
logger.error("Failed to connect", module="API")
logger.success("Operation completed", module="Core")
```

### Component Examples

#### 1. API Server (api.py)

```python
from modules.universal_logger import get_logger

# Initialize logger
logger = get_logger('API')

# Log startup
logger.info("Starting API server", module="Core")

# Log requests
@app.post("/api/endpoint")
async def endpoint():
    logger.info(f"Processing request", module="Endpoint")
    try:
        # ... processing ...
        logger.success("Request completed", module="Endpoint")
        return {"success": True}
    except Exception as e:
        logger.error(f"Request failed: {e}", module="Endpoint")
        raise
```

#### 2. Scheduler (scheduler.py)

```python
from modules.universal_logger import get_logger

class DownloadScheduler:
    def __init__(self):
        # Replace log_callback with universal logger
        self.logger = get_logger('Scheduler')

    def run(self):
        self.logger.info("Scheduler started", module="Core")

        for task in self.tasks:
            self.logger.debug(f"Processing task: {task}", module="Task")
            # ... task processing ...
            self.logger.success(f"Task completed: {task}", module="Task")
```

#### 3. Download Modules (instagram_module.py, forum_module.py, etc.)

```python
from modules.universal_logger import get_logger

class InstagramModule:
    def __init__(self):
        self.logger = get_logger('Instagram')

    def download(self, username):
        self.logger.info(f"Starting download for {username}", module="Download")

        try:
            # ... download logic ...
            self.logger.success(f"Downloaded media for {username}", module="Download")
        except Exception as e:
            self.logger.error(f"Download failed: {e}", module="Download")
```

#### 4. Using with Existing log_callback Pattern

For modules that use `log_callback`, you can get a compatible callback:

```python
from modules.universal_logger import get_logger

logger = get_logger('MediaDownloader')

# Get callback compatible with existing signature
log_callback = logger.get_callback()

# Pass to modules expecting log_callback
scheduler = DownloadScheduler(log_callback=log_callback)
instagram = InstagramModule(log_callback=log_callback)
```

### Advanced Configuration

```python
from modules.universal_logger import get_logger

# Custom configuration
logger = get_logger(
    component_name='MyComponent',
    log_dir='/custom/log/path',      # Custom log directory
    retention_days=14,                # Keep logs for 14 days
    console_level='DEBUG',            # Show DEBUG on console
    file_level='DEBUG'                # Save DEBUG to file
)
```

### Multi-Module Logging

Within a single component, you can use different module tags:

```python
logger = get_logger('API')

# Different modules
logger.info("Server started", module="Core")
logger.info("User authenticated", module="Auth")
logger.info("Database connected", module="Database")
logger.info("Request received", module="HTTP")
```

## Log Files

### Location

All logs are stored in: `/opt/media-downloader/logs/`

### File Naming

- Current log: `{component}.log`
- Rotated logs: `{component}.log.{YYYYMMDD}`

Examples:
- `api.log` - Current API logs
- `api.log.20251113` - API logs from Nov 13, 2025
- `scheduler.log` - Current scheduler logs
- `mediadownloader.log` - Main application logs

### Rotation Schedule

- **When**: Daily at midnight (00:00)
- **Retention**: 7 days
- **Automatic Cleanup**: Logs older than 7 days are deleted automatically

## Component List

Recommended component names for consistency:

| Component | Name | Log File |
|-----------|------|----------|
| API Server | `API` | `api.log` |
| Frontend Dev Server | `Frontend` | `frontend.log` |
| Scheduler | `Scheduler` | `scheduler.log` |
| Main Downloader | `MediaDownloader` | `mediadownloader.log` |
| Face Recognition | `FaceRecognition` | `facerecognition.log` |
| Cache Builder | `CacheBuilder` | `cachebuilder.log` |
| Instagram Module | `Instagram` | `instagram.log` |
| TikTok Module | `TikTok` | `tiktok.log` |
| Forum Module | `Forum` | `forum.log` |

## Migration Guide

### Migrating from Old Logging

**Before:**
```python
import logging

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

fh = logging.FileHandler('my.log')
fh.setFormatter(logging.Formatter('%(asctime)s %(message)s'))
logger.addHandler(fh)

logger.info("Some message")
```

**After:**
```python
from modules.universal_logger import get_logger

logger = get_logger('MyComponent')

logger.info("Some message", module="Core")
```

### Migrating from log_callback Pattern

**Before:**
```python
def my_callback(message, level='INFO'):
    print(f"[{level}] {message}")

module = SomeModule(log_callback=my_callback)
```

**After:**
```python
from modules.universal_logger import get_logger

logger = get_logger('MyComponent')
module = SomeModule(log_callback=logger.get_callback())
```

## Log Cleanup

### Automatic Cleanup

Logs are automatically cleaned up on logger initialization. The system:
1. Checks for log files older than `retention_days`
2. Deletes old files automatically
3. Logs cleanup activity to DEBUG level

### Manual Cleanup

To manually clean all logs older than 7 days:

```bash
find /opt/media-downloader/logs -name "*.log.*" -mtime +7 -delete
```

### Cron Job (Optional)

Add daily cleanup cron job:

```bash
# Add to root crontab
0 0 * * * find /opt/media-downloader/logs -name "*.log.*" -mtime +7 -delete
```

## Troubleshooting

### Logs Not Rotating

**Issue**: Logs grow indefinitely
**Solution**: Check that logger is initialized with `get_logger()`, not raw `logging` module

### Old Logs Not Cleaning Up

**Issue**: Logs older than 7 days still present
**Solution**:
1. Check file permissions on log directory
2. Restart the component to trigger cleanup
3. Run manual cleanup command

### Missing Log Entries

**Issue**: Some messages not appearing in logs
**Solution**:
1. Check console_level and file_level settings
2. Ensure module tag is passed: `logger.info("msg", module="Name")`
3. Verify log file permissions

### Multiple Log Entries

**Issue**: Each log line appears multiple times
**Solution**: Logger instantiated multiple times. Use `get_logger()` singleton pattern

## Performance

- **Overhead**: Minimal (<1ms per log entry)
- **File I/O**: Buffered writes, minimal disk impact
- **Rotation**: Happens at midnight, zero runtime impact
- **Cleanup**: Only runs on logger initialization

## Best Practices

1. **Use Singleton**: Always use `get_logger()` not `UniversalLogger()`
2. **Module Tags**: Always specify module parameter
3. **Log Levels**:
   - DEBUG: Verbose debugging information
   - INFO: General informational messages
   - WARNING: Warning messages, recoverable issues
   - ERROR: Error messages, operation failed
   - CRITICAL: Critical errors, system may fail
   - SUCCESS: Successful operations (maps to INFO)
4. **Message Format**: Be concise but descriptive
5. **Sensitive Data**: Never log passwords, tokens, or PII

## Examples

### Complete API Integration

```python
#!/usr/bin/env python3
from fastapi import FastAPI
from modules.universal_logger import get_logger

# Initialize logger
logger = get_logger('API')

app = FastAPI()

@app.on_event("startup")
async def startup():
    logger.info("API server starting", module="Core")
    logger.info("Connecting to database", module="Database")
    # ... startup tasks ...
    logger.success("API server ready", module="Core")

@app.get("/api/data")
async def get_data():
    logger.debug("Processing data request", module="HTTP")
    try:
        data = fetch_data()
        logger.success(f"Returned {len(data)} items", module="HTTP")
        return data
    except Exception as e:
        logger.error(f"Data fetch failed: {e}", module="HTTP")
        raise

if __name__ == "__main__":
    import uvicorn
    logger.info("Starting uvicorn", module="Core")
    uvicorn.run(app, host="0.0.0.0", port=8000)
```

### Complete Scheduler Integration

```python
#!/usr/bin/env python3
from modules.universal_logger import get_logger
from modules.scheduler import DownloadScheduler

# Initialize logger
logger = get_logger('Scheduler')

# Create scheduler with logger callback
scheduler = DownloadScheduler(log_callback=logger.get_callback())

# Log scheduler activity
logger.info("Scheduler initialized", module="Core")

# Start scheduler
scheduler.start()
logger.success("Scheduler started successfully", module="Core")
```

## Version

- **Module**: modules/universal_logger.py
- **Added**: Version 6.27.0
- **Last Updated**: 2025-11-13
