# Standardized Logging Format

This document defines the mandatory logging format and utilities that all agents MUST use to ensure consistent, searchable, and debuggable logs across the system.

## Log Format Specification

All agents MUST use this exact format for all log entries:

```
[AGENT:{name}][SESSION:{id}][ACTION:{action}][LEVEL:{level}] {message}
```

### Components

- **AGENT**: The agent's name (e.g., `implementation-worker`, `pr-reviewer`)
- **SESSION**: Unique session identifier (use first 8 chars if long)
- **ACTION**: The current operation (e.g., `clone`, `test`, `review`, `merge`)
- **LEVEL**: Log level - `INFO`, `WARNING`, `ERROR`, `DEBUG`
- **Message**: Human-readable description of what happened

### Examples

```
[AGENT:implementation-worker][SESSION:abc123de][ACTION:clone][LEVEL:INFO] Cloning repository to /tmp/impl-123
[AGENT:pr-reviewer][SESSION:def456gh][ACTION:review][LEVEL:WARNING] Found 3 CONTRIBUTING.md violations
[AGENT:behave-tester][SESSION:ghi789jk][ACTION:test][LEVEL:ERROR] Test execution failed: 5 scenarios failed
```

## Python Implementation

```python
import json
import time
from datetime import datetime
from typing import Optional, Dict, Any

class AgentLogger:
    """Standardized logger for all CleverAgents agents."""
    
    def __init__(self, agent_name: str, session_id: str, 
                 session_state_issue: Optional[int] = None,
                 owner: Optional[str] = None, 
                 repo: Optional[str] = None):
        """
        Initialize the logger.
        
        Args:
            agent_name: Name of the agent
            session_id: Unique session identifier
            session_state_issue: Forgejo issue number for persistence
            owner: Repository owner (for Forgejo persistence)
            repo: Repository name (for Forgejo persistence)
        """
        self.agent_name = agent_name
        self.session_id = session_id[:8] if len(session_id) > 8 else session_id
        self.session_state_issue = session_state_issue
        self.owner = owner
        self.repo = repo
        self.current_action = "init"
        
    def set_action(self, action: str):
        """Set the current action context."""
        self.current_action = action
        
    def _format_log(self, level: str, message: str, action: Optional[str] = None) -> str:
        """Format a log entry according to standards."""
        action_str = action or self.current_action
        return f"[AGENT:{self.agent_name}][SESSION:{self.session_id}][ACTION:{action_str}][LEVEL:{level}] {message}"
    
    def _persist_critical(self, log_line: str):
        """Persist critical logs to Forgejo."""
        if self.session_state_issue and self.owner and self.repo:
            try:
                comment = f"[LOG] Critical Event\n```\n{log_line}\n```\n\n---\n**Automated by CleverAgents Bot**"
                forgejo_create_issue_comment(self.owner, self.repo, 
                                           self.session_state_issue, comment)
            except:
                pass  # Best effort
    
    def info(self, message: str, action: Optional[str] = None):
        """Log an informational message."""
        log_line = self._format_log("INFO", message, action)
        print(log_line)
        return log_line
    
    def warning(self, message: str, action: Optional[str] = None):
        """Log a warning message."""
        log_line = self._format_log("WARNING", message, action)
        print(log_line)
        return log_line
    
    def error(self, message: str, action: Optional[str] = None, persist: bool = True):
        """Log an error message."""
        log_line = self._format_log("ERROR", message, action)
        print(log_line)
        
        if persist:
            self._persist_critical(log_line)
        
        return log_line
    
    def debug(self, message: str, action: Optional[str] = None):
        """Log a debug message."""
        log_line = self._format_log("DEBUG", message, action)
        print(log_line)
        return log_line
        
    def structured(self, action: str, data: Dict[str, Any], level: str = "INFO"):
        """Log structured data for automated analysis."""
        entry = {
            "timestamp": datetime.utcnow().isoformat() + "Z",
            "agent": self.agent_name,
            "session": self.session_id,
            "action": action,
            "level": level,
            "data": data
        }
        
        # Standard format for visibility
        message = f"Structured data: {action}"
        self._format_log(level, message, action)
        
        # JSON format for parsing
        print(f"[STRUCTURED] {json.dumps(entry)}")
        
        # Persist if critical
        if level in ["ERROR", "CRITICAL"]:
            self._persist_critical(f"[STRUCTURED] {json.dumps(entry, indent=2)}")
        
        return entry
```

## Usage Examples

### Basic Usage

```python
# Initialize at agent start
logger = AgentLogger(
    agent_name="implementation-worker",
    session_id=session_id,
    session_state_issue=SESSION_STATE_ISSUE,
    owner=owner,
    repo=repo
)

# Log with current action context
logger.set_action("setup")
logger.info("Validating credentials")
logger.info("Loading reference materials")

# Log with specific action
logger.info("Repository cloned successfully", action="clone")

# Log warnings
logger.warning("Retry attempt 2 of 3", action="push")

# Log errors (automatically persisted)
logger.error("Failed to merge PR: CI checks failing", action="merge")

# Log debug info
logger.debug(f"Queue depth: {len(queue)}", action="dispatch")
```

### Structured Logging

```python
# Log complex data for analysis
logger.structured("worker_dispatched", {
    "issue_number": 123,
    "worker_session": worker_session_id,
    "priority": "high",
    "attempt": 1
})

# Log performance metrics
logger.structured("operation_complete", {
    "operation": "subtask_implementation",
    "duration_seconds": 145.3,
    "lines_changed": 230,
    "files_modified": 5
}, level="INFO")

# Log errors with context
logger.structured("merge_failed", {
    "pr_number": 456,
    "reason": "insufficient_approvals",
    "current_approvals": 1,
    "required_approvals": 2
}, level="ERROR")
```

### Integration with Error Handling

```python
from shared.error_handling import safe_operation_with_recovery
from shared.logging import AgentLogger

logger = AgentLogger("implementation-worker", session_id)

def clone_with_logging(repo_url, target_dir):
    logger.set_action("clone")
    
    def do_clone():
        logger.info(f"Starting clone of {repo_url}")
        result = git_clone(repo_url, target_dir)
        logger.info("Clone completed successfully")
        return result
    
    def recovery(error_type, error):
        logger.warning(f"Recovery attempt for {error_type}: {error}")
        # Recovery logic...
    
    try:
        return safe_operation_with_recovery(
            "clone repository",
            do_clone,
            recovery
        )
    except OperationFailedError as e:
        logger.error(f"Clone failed after all attempts: {e}")
        raise
```

### Context Manager for Actions

```python
class LoggedAction:
    """Context manager for action-scoped logging."""
    
    def __init__(self, logger: AgentLogger, action: str):
        self.logger = logger
        self.action = action
        self.previous_action = None
        
    def __enter__(self):
        self.previous_action = self.logger.current_action
        self.logger.set_action(self.action)
        self.logger.info(f"Starting {self.action}")
        return self
        
    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_type:
            self.logger.error(f"{self.action} failed: {exc_val}")
        else:
            self.logger.info(f"{self.action} completed")
        
        # Restore previous action
        self.logger.set_action(self.previous_action)
        
        # Don't suppress exceptions
        return False

# Usage
with LoggedAction(logger, "test_execution"):
    run_tests()  # Logs automatically scoped to this action
```

## Log Aggregation Patterns

### Health Signals

```python
def log_health_signal(logger: AgentLogger, metrics: Dict[str, Any]):
    """Log standardized health signal."""
    
    logger.structured("health_signal", {
        "cycle": metrics.get("cycle", 0),
        "active_workers": metrics.get("active_workers", 0),
        "queue_depth": metrics.get("queue_depth", 0),
        "failure_rate": metrics.get("failure_rate", 0),
        "status": "active"
    }, level="INFO")
```

### Operation Summaries

```python
def log_operation_summary(logger: AgentLogger, operation: str, 
                         start_time: float, success: bool, 
                         details: Optional[Dict] = None):
    """Log operation completion with timing."""
    
    duration = time.time() - start_time
    
    data = {
        "operation": operation,
        "duration_seconds": round(duration, 2),
        "success": success
    }
    
    if details:
        data.update(details)
    
    level = "INFO" if success else "ERROR"
    logger.structured(f"{operation}_complete", data, level=level)
```

## Best Practices

1. **Always initialize logger at agent start** - Don't create multiple instances
2. **Set action context** - Use `set_action()` for logical operation groups
3. **Be consistent with action names** - Use standard names across agents
4. **Log state changes** - Entry/exit of major operations
5. **Include relevant context** - But avoid logging sensitive data
6. **Use appropriate levels** - INFO for normal, WARNING for recoverable, ERROR for failures
7. **Structure complex data** - Use `structured()` for analysis-friendly logs

## Standard Action Names

Use these standardized action names for consistency:

- **init** - Agent initialization
- **setup** - Environment setup
- **clone** - Repository cloning
- **implement** - Code implementation
- **test** - Test execution
- **review** - Code review
- **merge** - PR merging  
- **dispatch** - Worker dispatch
- **monitor** - Health monitoring
- **cleanup** - Resource cleanup

## Anti-Patterns to Avoid

```python
# ❌ WRONG - Inconsistent format
print(f"Starting work on issue {issue_number}")

# ✓ CORRECT - Use logger
logger.info(f"Starting work on issue {issue_number}")

# ❌ WRONG - No action context
logger.info("Failed")  # Failed what?

# ✓ CORRECT - Clear action context
logger.error("Repository clone failed", action="clone")

# ❌ WRONG - Logging credentials
logger.info(f"Using PAT: {pat}")

# ✓ CORRECT - Log presence, not value
logger.info("Forgejo PAT validated")

# ❌ WRONG - Unstructured complex data
logger.info(f"Stats: workers={w}, queue={q}, failed={f}")

# ✓ CORRECT - Structured for parsing
logger.structured("pool_stats", {
    "workers": w,
    "queue_depth": q, 
    "failures": f
})
```

## Integration Requirements

All agents MUST:

1. Import and initialize AgentLogger at startup
2. Use ONLY the logger for output (no raw print statements)
3. Set appropriate action context  
4. Log all state transitions
5. Persist ERROR level logs to Forgejo
6. Use structured logging for metrics and complex data