Debugging Workflows and Modules
This guide shows you how to debug FuzzForge workflows and modules using Temporal's powerful debugging features.
Quick Debugging Checklist
When something goes wrong:
- Check worker logs -
docker-compose -f docker-compose.yml logs worker-rust -f - Check Temporal UI - http://localhost:8080 (visual execution history)
- Check MinIO console - http://localhost:9001 (inspect uploaded files)
- Check backend logs -
docker-compose -f docker-compose.yml logs fuzzforge-backend -f
Debugging Workflow Discovery
Problem: Workflow Not Found
Symptom: Worker logs show "No workflows found for vertical: rust"
Debug Steps:
-
Check if worker can see the workflow:
docker exec fuzzforge-worker-rust ls /app/toolbox/workflows/ -
Check metadata.yaml exists:
docker exec fuzzforge-worker-rust cat /app/toolbox/workflows/my_workflow/metadata.yaml -
Verify vertical field matches:
docker exec fuzzforge-worker-rust grep "vertical:" /app/toolbox/workflows/my_workflow/metadata.yamlShould output:
vertical: rust -
Check worker logs for discovery errors:
docker-compose -f docker-compose.yml logs worker-rust | grep "my_workflow"
Solution:
- Ensure
metadata.yamlhas correctverticalfield - Restart worker to reload:
docker-compose -f docker-compose.yml restart worker-rust - Check worker logs for discovery confirmation
Debugging Workflow Execution
Using Temporal Web UI
The Temporal UI at http://localhost:8080 is your primary debugging tool.
Navigate to a workflow:
- Open http://localhost:8080
- Click "Workflows" in left sidebar
- Find your workflow by
run_idor workflow name - Click to see detailed execution
What you can see:
- Execution timeline - When each activity started/completed
- Input/output - Exact parameters passed to workflow
- Activity results - Return values from each activity
- Error stack traces - Full Python tracebacks
- Retry history - All retry attempts with reasons
- Worker information - Which worker executed each activity
Example: Finding why an activity failed:
- Open workflow in Temporal UI
- Scroll to failed activity (marked in red)
- Click on the activity
- See full error message and stack trace
- Check "Input" tab to see what parameters were passed
Viewing Worker Logs
Real-time Monitoring
# Follow logs from rust worker
docker-compose -f docker-compose.yml logs worker-rust -f
# Follow logs from all workers
docker-compose -f docker-compose.yml logs worker-rust worker-android -f
# Show last 100 lines
docker-compose -f docker-compose.yml logs worker-rust --tail 100
What Worker Logs Show
On startup:
INFO: Scanning for workflows in: /app/toolbox/workflows
INFO: Importing workflow module: toolbox.workflows.security_assessment.workflow
INFO: ✓ Discovered workflow: SecurityAssessmentWorkflow from security_assessment (vertical: rust)
INFO: 🚀 Worker started for vertical 'rust'
During execution:
INFO: Starting SecurityAssessmentWorkflow (workflow_id=security_assessment-abc123, target_id=548193a1...)
INFO: Downloading target from MinIO: 548193a1-f73f-4ec1-8068-19ec2660b8e4
INFO: Executing activity: scan_files
INFO: Completed activity: scan_files (duration: 3.2s)
On errors:
ERROR: Failed to import workflow module toolbox.workflows.broken.workflow:
File "/app/toolbox/workflows/broken/workflow.py", line 42
def run(
IndentationError: expected an indented block
Filtering Logs
# Show only errors
docker-compose -f docker-compose.yml logs worker-rust | grep ERROR
# Show workflow discovery
docker-compose -f docker-compose.yml logs worker-rust | grep "Discovered workflow"
# Show specific workflow execution
docker-compose -f docker-compose.yml logs worker-rust | grep "security_assessment-abc123"
# Show activity execution
docker-compose -f docker-compose.yml logs worker-rust | grep "activity"
Debugging File Upload
Check if File Was Uploaded
Using MinIO Console:
- Open http://localhost:9001
- Login:
fuzzforge/fuzzforge123 - Click "Buckets" → "targets"
- Look for your
target_id(UUID format) - Click to download and inspect locally
Using CLI:
# Check MinIO status
curl http://localhost:9000
# List backend logs for upload
docker-compose -f docker-compose.yml logs fuzzforge-backend | grep "upload"
Check Worker Cache
# List cached targets
docker exec fuzzforge-worker-rust ls -lh /cache/
# Check specific target
docker exec fuzzforge-worker-rust ls -lh /cache/548193a1-f73f-4ec1-8068-19ec2660b8e4
Interactive Debugging
Access Running Worker
# Open shell in worker container
docker exec -it fuzzforge-worker-rust bash
# Now you can:
# - Check filesystem
ls -la /app/toolbox/workflows/
# - Test imports
python3 -c "from toolbox.workflows.my_workflow.workflow import MyWorkflow; print(MyWorkflow)"
# - Check environment variables
env | grep TEMPORAL
# - Test activities
cd /app/toolbox/workflows/my_workflow
python3 -c "from activities import my_activity; print(my_activity)"
# - Check cache
ls -lh /cache/
Test Module in Isolation
# Enter worker container
docker exec -it fuzzforge-worker-rust bash
# Navigate to module
cd /app/toolbox/modules/scanner
# Run module directly
python3 -c "
from file_scanner import FileScannerModule
scanner = FileScannerModule()
print(scanner.get_metadata())
"
Debugging Module Code
Edit and Reload
Since toolbox is mounted as a volume, you can edit code on your host and reload:
-
Edit module on host:
# On your host machine
vim backend/toolbox/modules/scanner/file_scanner.py -
Restart worker to reload:
docker-compose -f docker-compose.yml restart worker-rust -
Check discovery logs:
docker-compose -f docker-compose.yml logs worker-rust | tail -50
Add Debug Logging
Add logging to your workflow or module:
import logging
logger = logging.getLogger(__name__)
@workflow.defn
class MyWorkflow:
@workflow.run
async def run(self, target_id: str):
workflow.logger.info(f"Starting with target_id: {target_id}") # Shows in Temporal UI
logger.info("Processing step 1") # Shows in worker logs
logger.debug(f"Debug info: {some_variable}") # Shows if LOG_LEVEL=DEBUG
try:
result = await some_activity()
logger.info(f"Activity result: {result}")
except Exception as e:
logger.error(f"Activity failed: {e}", exc_info=True) # Full stack trace
raise
Set debug logging:
# Edit docker-compose.yml
services:
worker-rust:
environment:
LOG_LEVEL: DEBUG # Change from INFO to DEBUG
# Restart
docker-compose -f docker-compose.yml restart worker-rust
Common Issues and Solutions
Issue: Workflow stuck in "Running" state
Debug:
- Check Temporal UI for last completed activity
- Check worker logs for errors
- Check if worker is still running:
docker-compose -f docker-compose.yml ps worker-rust
Solution:
- Worker may have crashed - restart it
- Activity may be hanging - check for infinite loops or stuck network calls
- Check worker resource limits:
docker stats fuzzforge-worker-rust
Issue: Import errors in workflow
Debug:
- Check worker logs for full error trace
- Check if module file exists:
docker exec fuzzforge-worker-rust ls /app/toolbox/modules/my_module/
Solution:
- Ensure module is in correct directory
- Check for syntax errors:
docker exec fuzzforge-worker-rust python3 -m py_compile /app/toolbox/modules/my_module/my_module.py - Verify imports are correct
Issue: Target file not found in worker
Debug:
- Check if target exists in MinIO console
- Check worker logs for download errors
- Verify target_id is correct
Solution:
- Re-upload file via CLI
- Check MinIO is running:
docker-compose -f docker-compose.yml ps minio - Check MinIO credentials in worker environment
Performance Debugging
Check Activity Duration
In Temporal UI:
- Open workflow execution
- Scroll through activities
- Each shows duration (e.g., "3.2s")
- Identify slow activities
Monitor Resource Usage
# Monitor worker resource usage
docker stats fuzzforge-worker-rust
# Check worker logs for memory warnings
docker-compose -f docker-compose.yml logs worker-rust | grep -i "memory\|oom"
Profile Workflow Execution
Add timing to your workflow:
import time
@workflow.defn
class MyWorkflow:
@workflow.run
async def run(self, target_id: str):
start = time.time()
result1 = await activity1()
workflow.logger.info(f"Activity1 took: {time.time() - start:.2f}s")
start = time.time()
result2 = await activity2()
workflow.logger.info(f"Activity2 took: {time.time() - start:.2f}s")
Advanced Debugging
Enable Temporal Worker Debug Logs
# Edit docker-compose.yml
services:
worker-rust:
environment:
TEMPORAL_LOG_LEVEL: DEBUG
LOG_LEVEL: DEBUG
# Restart
docker-compose -f docker-compose.yml restart worker-rust
Inspect Temporal Workflows via CLI
# Install Temporal CLI
docker exec fuzzforge-temporal tctl
# List workflows
docker exec fuzzforge-temporal tctl workflow list
# Describe workflow
docker exec fuzzforge-temporal tctl workflow describe -w security_assessment-abc123
# Show workflow history
docker exec fuzzforge-temporal tctl workflow show -w security_assessment-abc123
Check Network Connectivity
# From worker to Temporal
docker exec fuzzforge-worker-rust ping temporal
# From worker to MinIO
docker exec fuzzforge-worker-rust curl http://minio:9000
# From host to services
curl http://localhost:8080 # Temporal UI
curl http://localhost:9000 # MinIO
curl http://localhost:8000/health # Backend
Debugging Best Practices
- Always check Temporal UI first - It shows the most complete execution history
- Use structured logging - Include workflow_id, target_id in log messages
- Log at decision points - Before/after each major operation
- Keep worker logs - They persist across workflow runs
- Test modules in isolation - Use
docker execto test before integrating - Use debug builds - Enable DEBUG logging during development
- Monitor resources - Use
docker statsto catch resource issues
Getting Help
If you're still stuck:
-
Collect diagnostic info:
# Save all logs
docker-compose -f docker-compose.yml logs > fuzzforge-logs.txt
# Check service status
docker-compose -f docker-compose.yml ps > service-status.txt -
Check Temporal UI and take screenshots of:
- Workflow execution timeline
- Failed activity details
- Error messages
-
Report issue with:
- Workflow name and run_id
- Error messages from logs
- Screenshots from Temporal UI
- Steps to reproduce
Happy debugging! 🐛🔍