MED-001: Enhanced typing indicator - Persistent typing loop (_maintain_typing method) - Loops every 8s to maintain indicator for long operations (30s-5min) - 8 comprehensive tests covering all lifecycle scenarios - 27/27 bot tests passing MED-002: Structured logging and error reporting - logging_config.py (371 lines) - JSONFormatter, ErrorTracker, format_error_for_discord - RotatingFileHandler (10MB max, 5 backups) - Unique 8-char error IDs for support tracking - Privacy-safe Discord error messages (7 error types) - Enhanced bot.py with structured logging throughout - 15/15 logging tests passing MED-005: Comprehensive test suite - Total: 156/157 tests passing (99.4%) - test_session_manager.py: 27 tests - test_claude_runner.py: 11 tests - test_config.py: 25 tests - test_response_formatter.py: 26 tests - test_bot.py: 27 tests - test_commands.py: 18 tests - test_concurrency.py: 7 tests - test_logging.py: 15 tests Total: 13/18 tasks complete (72.2%) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
137 lines
4.3 KiB
Python
Executable File
137 lines
4.3 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Manual test script to verify logging configuration."""
|
|
|
|
import logging
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
from claude_coordinator.logging_config import (
|
|
setup_logging,
|
|
format_error_for_discord,
|
|
log_and_format_error,
|
|
ErrorTracker
|
|
)
|
|
|
|
def test_basic_logging():
|
|
"""Test basic logging setup and output."""
|
|
print("Testing basic logging setup...")
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
log_file = Path(tmpdir) / "test.log"
|
|
|
|
# Setup logging
|
|
setup_logging(
|
|
log_level="DEBUG",
|
|
log_file=str(log_file),
|
|
json_logs=True
|
|
)
|
|
|
|
# Create logger and log some messages
|
|
logger = logging.getLogger(__name__)
|
|
|
|
logger.debug("Debug message", extra={'test_field': 'debug_value'})
|
|
logger.info("Info message", extra={'channel_id': '12345'})
|
|
logger.warning("Warning message")
|
|
logger.error("Error message", extra={'error_code': 500})
|
|
|
|
# Try exception logging
|
|
try:
|
|
raise ValueError("Test exception")
|
|
except ValueError as e:
|
|
logger.exception("Exception occurred", extra={'context': 'test'})
|
|
|
|
# Read log file and verify JSON format
|
|
log_content = log_file.read_text()
|
|
print("\n--- Log File Contents ---")
|
|
print(log_content)
|
|
print("--- End Log Contents ---\n")
|
|
|
|
# Verify it's JSON
|
|
import json
|
|
for line in log_content.strip().split('\n'):
|
|
try:
|
|
parsed = json.loads(line)
|
|
assert 'timestamp' in parsed
|
|
assert 'level' in parsed
|
|
assert 'message' in parsed
|
|
print(f"✓ Valid JSON log entry: {parsed['level']} - {parsed['message']}")
|
|
except json.JSONDecodeError as e:
|
|
print(f"✗ Invalid JSON: {line[:100]}")
|
|
raise
|
|
|
|
def test_error_tracking():
|
|
"""Test error tracking and Discord message formatting."""
|
|
print("\nTesting error tracking...")
|
|
|
|
logger = logging.getLogger('error_test')
|
|
|
|
# Test error ID generation
|
|
error_id1 = ErrorTracker.generate_error_id()
|
|
error_id2 = ErrorTracker.generate_error_id()
|
|
assert error_id1 != error_id2
|
|
print(f"✓ Generated unique error IDs: {error_id1}, {error_id2}")
|
|
|
|
# Test Discord error formatting
|
|
msg = format_error_for_discord(
|
|
error_type="timeout",
|
|
error_id="abc12345"
|
|
)
|
|
assert "⏱️" in msg
|
|
assert "abc12345" in msg
|
|
print(f"✓ Formatted Discord error message:\n{msg}\n")
|
|
|
|
# Test combined logging and formatting
|
|
error_id, discord_msg = log_and_format_error(
|
|
logger,
|
|
error_type="claude_error",
|
|
message="Test error message",
|
|
channel_id="67890",
|
|
session_id="test-session"
|
|
)
|
|
assert len(error_id) == 8
|
|
assert error_id in discord_msg
|
|
print(f"✓ Combined log and format with error_id: {error_id}")
|
|
|
|
def test_log_rotation():
|
|
"""Test log rotation configuration."""
|
|
print("\nTesting log rotation configuration...")
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
log_file = Path(tmpdir) / "rotate_test.log"
|
|
|
|
# Setup with small file size for testing
|
|
setup_logging(
|
|
log_level="INFO",
|
|
log_file=str(log_file),
|
|
json_logs=True,
|
|
max_bytes=1000, # Small size to trigger rotation
|
|
backup_count=3
|
|
)
|
|
|
|
logger = logging.getLogger('rotation_test')
|
|
|
|
# Write many log entries to trigger rotation
|
|
for i in range(100):
|
|
logger.info(f"Log entry {i} with some padding to increase size" * 5)
|
|
|
|
# Check if rotation occurred
|
|
log_files = list(Path(tmpdir).glob("rotate_test.log*"))
|
|
print(f"✓ Log rotation: {len(log_files)} files created")
|
|
for lf in log_files:
|
|
print(f" - {lf.name} ({lf.stat().st_size} bytes)")
|
|
|
|
if __name__ == "__main__":
|
|
print("=== Manual Logging Tests ===\n")
|
|
|
|
try:
|
|
test_basic_logging()
|
|
test_error_tracking()
|
|
test_log_rotation()
|
|
|
|
print("\n=== All Manual Tests Passed ===")
|
|
except Exception as e:
|
|
print(f"\n✗ Test failed: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
exit(1)
|