Spaces:
Running
Running
| """ | |
| Centralized Logging Utility for Invoice Processing System | |
| Provides structured logging with different levels and formatters | |
| """ | |
| import logging | |
| import sys | |
| from datetime import datetime | |
| from typing import Optional | |
| from pathlib import Path | |
| class ColoredFormatter(logging.Formatter): | |
| """Custom formatter with colors for console output""" | |
| # Color codes | |
| COLORS = { | |
| 'DEBUG': '\033[36m', # Cyan | |
| 'INFO': '\033[32m', # Green | |
| 'WARNING': '\033[33m', # Yellow | |
| 'ERROR': '\033[31m', # Red | |
| 'CRITICAL': '\033[35m', # Magenta | |
| 'RESET': '\033[0m' # Reset | |
| } | |
| def format(self, record): | |
| # Add color to levelname | |
| if record.levelname in self.COLORS: | |
| record.levelname = ( | |
| f"{self.COLORS[record.levelname]}{record.levelname}" | |
| f"{self.COLORS['RESET']}" | |
| ) | |
| return super().format(record) | |
| def setup_logging(log_level: str = "INFO", log_file: Optional[str] = None): | |
| """ | |
| Setup centralized logging configuration | |
| Args: | |
| log_level: Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL) | |
| log_file: Optional log file path | |
| """ | |
| # Create logs directory if it doesn't exist | |
| if log_file: | |
| log_path = Path(log_file) | |
| log_path.parent.mkdir(parents=True, exist_ok=True) | |
| # Configure root logger | |
| root_logger = logging.getLogger() | |
| root_logger.setLevel(getattr(logging, log_level.upper())) | |
| # Clear existing handlers | |
| root_logger.handlers.clear() | |
| # Console handler with colors | |
| console_handler = logging.StreamHandler(sys.stdout) | |
| console_formatter = ColoredFormatter( | |
| fmt='%(asctime)s | %(levelname)-8s | %(name)-20s | %(message)s', | |
| datefmt='%Y-%m-%d %H:%M:%S' | |
| ) | |
| console_handler.setFormatter(console_formatter) | |
| root_logger.addHandler(console_handler) | |
| # File handler (if specified) | |
| if log_file: | |
| file_handler = logging.FileHandler(log_file) | |
| file_formatter = logging.Formatter( | |
| fmt='%(asctime)s | %(levelname)-8s | %(name)-20s | %(funcName)-15s | %(message)s', | |
| datefmt='%Y-%m-%d %H:%M:%S' | |
| ) | |
| file_handler.setFormatter(file_formatter) | |
| root_logger.addHandler(file_handler) | |
| # Set specific logger levels | |
| logging.getLogger("httpx").setLevel(logging.WARNING) | |
| logging.getLogger("urllib3").setLevel(logging.WARNING) | |
| logging.getLogger("requests").setLevel(logging.WARNING) | |
| def get_logger(name: str) -> logging.Logger: | |
| """ | |
| Get a logger instance with the specified name | |
| Args: | |
| name: Logger name (typically module or class name) | |
| Returns: | |
| Configured logger instance | |
| """ | |
| return logging.getLogger(name) | |
| class StructuredLogger: | |
| """ | |
| Structured logger for agent operations with consistent formatting | |
| """ | |
| def __init__(self, name: str): | |
| self.logger = get_logger(name) | |
| self.name = name | |
| def log_agent_start(self, agent_name: str, process_id: str, **kwargs): | |
| """Log agent execution start""" | |
| self.logger.info( | |
| f"[START] Agent {agent_name} started for process {process_id}", | |
| extra={"agent": agent_name, "process_id": process_id, **kwargs} | |
| ) | |
| def log_agent_complete(self, agent_name: str, process_id: str, | |
| duration_ms: int, **kwargs): | |
| """Log agent execution completion""" | |
| self.logger.info( | |
| f"[COMPLETE] Agent {agent_name} completed for process {process_id} " | |
| f"in {duration_ms}ms", | |
| extra={ | |
| "agent": agent_name, | |
| "process_id": process_id, | |
| "duration_ms": duration_ms, | |
| **kwargs | |
| } | |
| ) | |
| def log_agent_error(self, agent_name: str, process_id: str, | |
| error: Exception, **kwargs): | |
| """Log agent execution error""" | |
| self.logger.error( | |
| f"[ERROR] Agent {agent_name} failed for process {process_id}: {str(error)}", | |
| extra={ | |
| "agent": agent_name, | |
| "process_id": process_id, | |
| "error_type": type(error).__name__, | |
| "error_message": str(error), | |
| **kwargs | |
| }, | |
| exc_info=True | |
| ) | |
| def log_decision(self, agent_name: str, process_id: str, | |
| decision: str, reasoning: str, confidence: float = None): | |
| """Log agent decision""" | |
| message = f"[DECISION] Agent {agent_name} decided: {decision} - {reasoning}" | |
| if confidence: | |
| message += f" (confidence: {confidence:.2f})" | |
| self.logger.info( | |
| message, | |
| extra={ | |
| "agent": agent_name, | |
| "process_id": process_id, | |
| "decision": decision, | |
| "reasoning": reasoning, | |
| "confidence": confidence | |
| } | |
| ) | |
| def log_escalation(self, agent_name: str, process_id: str, | |
| reason: str, **kwargs): | |
| """Log escalation event""" | |
| self.logger.warning( | |
| f"[ESCALATION] Agent {agent_name} escalating process {process_id}: {reason}", | |
| extra={ | |
| "agent": agent_name, | |
| "process_id": process_id, | |
| "escalation_reason": reason, | |
| **kwargs | |
| } | |
| ) | |
| def log_workflow_start(self, workflow_type: str, process_id: str, **kwargs): | |
| """Log workflow start""" | |
| self.logger.info( | |
| f"[WORKFLOW] Starting {workflow_type} workflow for process {process_id}", | |
| extra={ | |
| "workflow_type": workflow_type, | |
| "process_id": process_id, | |
| **kwargs | |
| } | |
| ) | |
| def log_workflow_complete(self, workflow_type: str, process_id: str, | |
| duration_ms: int, **kwargs): | |
| """Log workflow completion""" | |
| self.logger.info( | |
| f"[WORKFLOW_COMPLETE] Completed {workflow_type} workflow for process {process_id} " | |
| f"in {duration_ms}ms", | |
| extra={ | |
| "workflow_type": workflow_type, | |
| "process_id": process_id, | |
| "duration_ms": duration_ms, | |
| **kwargs | |
| } | |
| ) | |
| def log_metric(self, metric_name: str, value: float, **kwargs): | |
| """Log metric value""" | |
| self.logger.info( | |
| f"[METRIC] {metric_name}: {value}", | |
| extra={ | |
| "metric_name": metric_name, | |
| "metric_value": value, | |
| **kwargs | |
| } | |
| ) | |
| # Initialize default logging | |
| setup_logging() | |
| # Create default structured logger | |
| default_logger = StructuredLogger("invoice_system") |