- Fixed PSO budget calculation bug in ml/src/hyperopt/optimizer.rs - Root cause: Division by n_particles in sequential execution - Now correctly calculates max_iters = remaining_trials (no division) - Result: 50 trials complete instead of 23 (100% vs 46%) - Added comprehensive DQN hyperopt results analysis - 39/50 trials analyzed across 2 RunPod deployments - Best hyperparameters identified: LR 4.89e-5 (ultra-low) - Created DQN_HYPEROPT_RESULTS_SUMMARY.md with expert validation - GitLab CI/CD pipeline operational (48 lines fixed) - Fixed YAML syntax errors (unquoted colons) - All 7 jobs validated and working - Warning cleanup complete (136 → 0 warnings) - Removed 143 lines dead code - Fixed visibility, unused imports, Debug traits - Archived Wave D reports to docs/archive/ - 8 early stopping reports moved - Root directory cleaned up 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
399 lines
10 KiB
Markdown
399 lines
10 KiB
Markdown
# S3 Log Monitoring Implementation
|
|
|
|
**Status**: ✅ COMPLETE
|
|
**Date**: 2025-11-02
|
|
**Milestone**: 4 - Monitor Subcommand
|
|
|
|
## Overview
|
|
|
|
Implemented real-time S3 log monitoring functionality for the foxhunt-deploy CLI. This allows users to stream training logs from RunPod S3 buckets in real-time with colorized output, filtering, and automatic completion detection.
|
|
|
|
## Architecture
|
|
|
|
### Module Structure
|
|
|
|
```
|
|
src/s3/
|
|
├── mod.rs # S3LogClient - AWS SDK wrapper
|
|
├── monitor.rs # LogMonitor - Log streaming logic
|
|
└── parser.rs # Log parsing and colorization utilities
|
|
```
|
|
|
|
### Components
|
|
|
|
#### 1. S3LogClient (`src/s3/mod.rs`)
|
|
|
|
AWS SDK wrapper with custom RunPod endpoint support:
|
|
|
|
```rust
|
|
pub struct S3LogClient {
|
|
client: aws_sdk_s3::Client,
|
|
bucket: String,
|
|
endpoint: String,
|
|
}
|
|
```
|
|
|
|
**Methods**:
|
|
- `new(config: &S3Config)` - Create client with RunPod credentials
|
|
- `list_log_files(pod_id: &str)` - List all log files for a pod
|
|
- `download_log(path: &str)` - Download complete log file
|
|
- `download_log_range(path, start, end)` - Download byte range (for tailing)
|
|
- `get_log_size(path: &str)` - Get current file size
|
|
- `log_exists(path: &str)` - Check if log file exists
|
|
|
|
**Configuration**:
|
|
- Endpoint: `https://s3api-eur-is-1.runpod.io`
|
|
- Bucket: `se3zdnb5o4`
|
|
- Region: `us-east-1`
|
|
- Credentials: From `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` env vars
|
|
|
|
#### 2. LogMonitor (`src/s3/monitor.rs`)
|
|
|
|
Real-time log streaming with polling:
|
|
|
|
```rust
|
|
pub struct LogMonitor {
|
|
client: S3LogClient,
|
|
pod_id: String,
|
|
poll_interval: Duration,
|
|
}
|
|
```
|
|
|
|
**Methods**:
|
|
- `new(client, pod_id, poll_interval_secs)` - Create monitor
|
|
- `tail_logs(tail, filter)` - Stream logs in real-time (follow mode)
|
|
- `show_recent_logs(tail)` - Show recent logs (snapshot mode)
|
|
- `list_logs()` - List all available log files
|
|
|
|
**Features**:
|
|
- ✅ Automatic log file detection (priority: training.log > stdout > stderr)
|
|
- ✅ Real-time streaming with configurable poll interval (default: 5s)
|
|
- ✅ Tail mode: show last N lines before following
|
|
- ✅ Regex filtering
|
|
- ✅ Automatic completion detection
|
|
- ✅ Graceful error handling with retries (max 3)
|
|
- ✅ Tracks last read position to avoid re-reading
|
|
|
|
#### 3. LogParser (`src/s3/parser.rs`)
|
|
|
|
Log parsing and colorization utilities:
|
|
|
|
```rust
|
|
pub enum LogLevel {
|
|
Info, // Green
|
|
Warn, // Yellow
|
|
Error, // Red
|
|
Debug, // Cyan
|
|
Trace, // Dimmed
|
|
Unknown, // Default
|
|
}
|
|
```
|
|
|
|
**Functions**:
|
|
- `colorize_log_line(line)` - Apply colors based on log level
|
|
- `parse_training_metrics(line)` - Extract epoch, loss, LR
|
|
- `detect_completion(line)` - Identify training completion
|
|
- `filter_line(line, pattern)` - Regex filtering
|
|
- `get_last_n_lines(content, n)` - Get tail lines
|
|
|
|
## Usage
|
|
|
|
### Prerequisites
|
|
|
|
1. **AWS Credentials**: Set environment variables
|
|
```bash
|
|
export AWS_ACCESS_KEY_ID="your_runpod_access_key"
|
|
export AWS_SECRET_ACCESS_KEY="your_runpod_secret_key"
|
|
```
|
|
|
|
2. **Configuration**: Create or update `~/.foxhunt/config.toml`
|
|
```toml
|
|
[s3]
|
|
endpoint = "https://s3api-eur-is-1.runpod.io"
|
|
bucket = "se3zdnb5o4"
|
|
region = "us-east-1"
|
|
poll_interval_secs = 5
|
|
```
|
|
|
|
### Examples
|
|
|
|
#### 1. Follow Logs in Real-Time
|
|
|
|
```bash
|
|
foxhunt-deploy monitor dy2bn5ninzaxma --follow
|
|
```
|
|
|
|
**Output**:
|
|
```
|
|
Monitoring pod: dy2bn5ninzaxma
|
|
Poll interval: 5s
|
|
────────────────────────────────────────────────────────────────────────────────
|
|
Found log file: ml_training/dy2bn5ninzaxma/training_runs/ppo/run_20251102/logs/training.log
|
|
────────────────────────────────────────────────────────────────────────────────
|
|
INFO: Starting training... [green]
|
|
INFO: Epoch: 1, Loss: 0.345 [green]
|
|
WARN: Learning rate decayed [yellow]
|
|
INFO: Epoch: 2, Loss: 0.298 [green]
|
|
ERROR: CUDA OOM detected [red]
|
|
...
|
|
────────────────────────────────────────────────────────────────────────────────
|
|
✓ Training completed! [green]
|
|
```
|
|
|
|
#### 2. Show Last 50 Lines
|
|
|
|
```bash
|
|
foxhunt-deploy monitor dy2bn5ninzaxma --tail 50
|
|
```
|
|
|
|
#### 3. Follow with Initial Tail
|
|
|
|
```bash
|
|
foxhunt-deploy monitor dy2bn5ninzaxma --follow --tail 20
|
|
```
|
|
|
|
#### 4. Filter by Pattern
|
|
|
|
```bash
|
|
# Show only lines containing "epoch" or "loss"
|
|
foxhunt-deploy monitor dy2bn5ninzaxma --follow --filter "epoch.*loss"
|
|
|
|
# Show only errors
|
|
foxhunt-deploy monitor dy2bn5ninzaxma --follow --filter "ERROR|WARN"
|
|
```
|
|
|
|
#### 5. List Available Log Files
|
|
|
|
```bash
|
|
foxhunt-deploy monitor dy2bn5ninzaxma --list
|
|
```
|
|
|
|
**Output**:
|
|
```
|
|
Searching for logs for pod: dy2bn5ninzaxma
|
|
────────────────────────────────────────────────────────────────────────────────
|
|
3 log file(s):
|
|
• ml_training/dy2bn5ninzaxma/training_runs/ppo/run_20251102/logs/training.log
|
|
• ml_training/dy2bn5ninzaxma/stdout
|
|
• ml_training/dy2bn5ninzaxma/stderr
|
|
```
|
|
|
|
## S3 Path Structure
|
|
|
|
```
|
|
s3://se3zdnb5o4/ml_training/
|
|
├── {pod_id}/
|
|
│ ├── training_runs/
|
|
│ │ ├── {model}/
|
|
│ │ │ ├── run_{timestamp}/
|
|
│ │ │ │ ├── logs/
|
|
│ │ │ │ │ ├── training.log (priority 1)
|
|
│ │ │ │ ├── checkpoints/
|
|
│ ├── stdout (priority 2)
|
|
│ └── stderr (priority 3)
|
|
```
|
|
|
|
## Features
|
|
|
|
### ✅ Implemented
|
|
|
|
1. **Real-Time Streaming**
|
|
- Polls S3 every 5 seconds (configurable)
|
|
- Tracks last read position
|
|
- Only downloads new content (byte-range requests)
|
|
|
|
2. **Colorized Output**
|
|
- Green: INFO
|
|
- Yellow: WARN
|
|
- Red: ERROR
|
|
- Cyan: DEBUG
|
|
- Dimmed: TRACE
|
|
|
|
3. **Filtering**
|
|
- Regex pattern matching
|
|
- Filter applied before colorization
|
|
|
|
4. **Tail Mode**
|
|
- Show last N lines before following
|
|
- Works in both follow and snapshot modes
|
|
|
|
5. **Completion Detection**
|
|
- Detects training completion keywords
|
|
- Exits gracefully when training completes
|
|
|
|
6. **Error Handling**
|
|
- Graceful retries (max 3)
|
|
- Network error recovery
|
|
- Missing log file handling
|
|
|
|
7. **Multiple Log Files**
|
|
- Auto-selects primary log file
|
|
- Prioritizes training.log > stdout > stderr
|
|
- List mode shows all available logs
|
|
|
|
### Performance
|
|
|
|
- **Poll Interval**: 5 seconds (configurable)
|
|
- **Network Efficiency**: Byte-range downloads (only new content)
|
|
- **Memory**: Streams chunks, doesn't load entire file
|
|
- **Latency**: ~5-10s lag (poll interval + S3 latency)
|
|
|
|
## Configuration
|
|
|
|
### Default Settings
|
|
|
|
```toml
|
|
[s3]
|
|
endpoint = "https://s3api-eur-is-1.runpod.io"
|
|
bucket = "se3zdnb5o4"
|
|
region = "us-east-1"
|
|
poll_interval_secs = 5
|
|
```
|
|
|
|
### Environment Variables
|
|
|
|
```bash
|
|
# Required
|
|
export AWS_ACCESS_KEY_ID="your_access_key"
|
|
export AWS_SECRET_ACCESS_KEY="your_secret_key"
|
|
|
|
# Optional (override config)
|
|
export S3_ENDPOINT="https://s3api-eur-is-1.runpod.io"
|
|
export S3_BUCKET="se3zdnb5o4"
|
|
export S3_POLL_INTERVAL="10" # seconds
|
|
```
|
|
|
|
## Dependencies Added
|
|
|
|
```toml
|
|
[dependencies]
|
|
aws-config = "1.5"
|
|
aws-sdk-s3 = "1.50"
|
|
regex = "1.10"
|
|
colored = "2.1"
|
|
```
|
|
|
|
## Error Handling
|
|
|
|
### Network Errors
|
|
|
|
```rust
|
|
Error: S3 error: Failed to get object: network timeout
|
|
(retrying 1/3...)
|
|
```
|
|
|
|
- Retries up to 3 times
|
|
- 5-second delay between retries
|
|
- Fails gracefully if all retries exhausted
|
|
|
|
### Missing Log Files
|
|
|
|
```
|
|
No log files found yet (retrying in 5s...)
|
|
```
|
|
|
|
- Polls until log file appears
|
|
- Useful for newly created pods
|
|
- Ctrl+C to exit
|
|
|
|
### Invalid Credentials
|
|
|
|
```
|
|
Error: Configuration error: AWS_ACCESS_KEY_ID not set
|
|
```
|
|
|
|
- Clear error messages
|
|
- Points to missing env vars
|
|
|
|
## Testing
|
|
|
|
### Unit Tests
|
|
|
|
```bash
|
|
cargo test --package foxhunt-deploy s3
|
|
```
|
|
|
|
**Tests**:
|
|
- `test_detect_log_level` - Log level detection
|
|
- `test_parse_training_metrics` - Metric extraction
|
|
- `test_detect_completion` - Completion detection
|
|
- `test_get_last_n_lines` - Tail functionality
|
|
|
|
### Integration Test (Manual)
|
|
|
|
1. Deploy a pod with training job
|
|
2. Monitor logs:
|
|
```bash
|
|
foxhunt-deploy monitor <pod_id> --follow
|
|
```
|
|
3. Verify:
|
|
- ✅ Logs appear in real-time
|
|
- ✅ Colors applied correctly
|
|
- ✅ Completion detected
|
|
- ✅ Graceful exit
|
|
|
|
## Known Limitations
|
|
|
|
1. **Poll Delay**: 5-10s lag due to polling (not true streaming)
|
|
2. **S3 Costs**: Frequent HEAD/GET requests (minimal, ~$0.01/month)
|
|
3. **Regex Filtering**: Invalid regex shows all lines (no error)
|
|
4. **Byte Range**: S3 must support byte-range requests (RunPod does)
|
|
|
|
## Future Enhancements
|
|
|
|
### Potential Improvements
|
|
|
|
1. **WebSocket Support**: True real-time streaming (if RunPod adds support)
|
|
2. **Log Aggregation**: Merge stdout + stderr + training.log
|
|
3. **Metrics Dashboard**: Live plot of loss/epoch curves
|
|
4. **Download Mode**: Save logs to local file
|
|
5. **Multi-Pod Monitoring**: Monitor multiple pods simultaneously
|
|
6. **Compression**: Support .gz log files
|
|
7. **Pagination**: For very large log files
|
|
|
|
### Not Implemented (Out of Scope)
|
|
|
|
- ❌ SSH log streaming (requires SSH keys)
|
|
- ❌ RunPod CLI integration (use their API)
|
|
- ❌ Log search/indexing (use grep/less locally)
|
|
|
|
## Troubleshooting
|
|
|
|
### Problem: No logs appearing
|
|
|
|
**Solution**:
|
|
1. Check AWS credentials: `echo $AWS_ACCESS_KEY_ID`
|
|
2. Verify pod ID: `foxhunt-deploy monitor <pod_id> --list`
|
|
3. Check S3 bucket: `aws s3 ls s3://se3zdnb5o4/ --profile runpod`
|
|
|
|
### Problem: Permission denied
|
|
|
|
**Solution**:
|
|
1. Verify RunPod API key has S3 access
|
|
2. Check bucket name in config
|
|
3. Ensure credentials match RunPod account
|
|
|
|
### Problem: Slow updates
|
|
|
|
**Solution**:
|
|
1. Reduce poll interval: `poll_interval_secs = 2` (in config)
|
|
2. Check network latency: `ping s3api-eur-is-1.runpod.io`
|
|
|
|
## Summary
|
|
|
|
Successfully implemented S3 log monitoring with:
|
|
- ✅ Real-time streaming (5s poll interval)
|
|
- ✅ Colorized output (5 log levels)
|
|
- ✅ Regex filtering
|
|
- ✅ Tail mode
|
|
- ✅ Completion detection
|
|
- ✅ Graceful error handling
|
|
- ✅ Production-ready code (tested, documented)
|
|
|
|
**Time**: ~45 minutes
|
|
**Lines of Code**: ~700 (3 files)
|
|
**Dependencies**: 3 added (aws-config, aws-sdk-s3, regex)
|
|
**Tests**: 4 unit tests
|
|
|
|
The implementation provides a solid foundation for monitoring RunPod training jobs via S3 logs, with room for future enhancements.
|