| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- import csv
- import os
- import json
- from typing import List, Dict, Any, Optional
- from datetime import datetime
- from logging import getLogger
- from enum import Enum
- from models.sales import OrderWeb, ItemWeb
- logger = getLogger(__name__)
- class LogLevel(Enum):
- """Log levels for structured logging"""
- DEBUG = "DEBUG"
- INFO = "INFO"
- WARNING = "WARNING"
- ERROR = "ERROR"
- CRITICAL = "CRITICAL"
- class LogCategory(Enum):
- """Categories for different types of logs"""
- ORDER = "ORDER"
- USER = "USER"
- PAYMENT = "PAYMENT"
- SECURITY = "SECURITY"
- API = "API"
- DATABASE = "DATABASE"
- EMAIL = "EMAIL"
- PRINT = "PRINT"
- CHAT = "CHAT"
- SYSTEM = "SYSTEM"
- class StructuredLogger:
- """Enhanced logging service with structured logging capabilities"""
-
- def __init__(self):
- self.logger = getLogger(__name__)
- self.logs_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'logs')
- self._ensure_logs_directory()
-
- def _ensure_logs_directory(self):
- """Ensure logs directory exists"""
- if not os.path.exists(self.logs_dir):
- os.makedirs(self.logs_dir)
- self.logger.info(f"Created logs directory: {self.logs_dir}")
-
- def _write_structured_log(self, category: LogCategory, level: LogLevel,
- message: str, data: Optional[Dict[str, Any]] = None,
- user_id: Optional[int] = None, user_email: Optional[str] = None):
- """Write structured log entry"""
- log_entry = {
- "timestamp": datetime.now().isoformat(),
- "category": category.value,
- "level": level.value,
- "message": message,
- "user_id": user_id,
- "user_email": user_email,
- "data": data or {}
- }
-
- # Write to category-specific log file
- log_file = os.path.join(self.logs_dir, f"{category.value.lower()}.log")
- try:
- with open(log_file, 'a', encoding='utf-8') as f:
- f.write(json.dumps(log_entry, ensure_ascii=False) + '\n')
- except Exception as e:
- self.logger.error(f"Failed to write structured log: {e}")
-
- def log_order_event(self, message: str, level: LogLevel = LogLevel.INFO,
- order_data: Optional[Dict] = None, user_id: Optional[int] = None,
- user_email: Optional[str] = None):
- """Log order-related events"""
- self._write_structured_log(LogCategory.ORDER, level, message, order_data, user_id, user_email)
-
- # Also log to main logger
- getattr(self.logger, level.value.lower())(
- f"[ORDER] {message} - User: {user_email or user_id or 'N/A'}"
- )
-
- def log_user_event(self, message: str, level: LogLevel = LogLevel.INFO,
- user_data: Optional[Dict] = None, user_id: Optional[int] = None,
- user_email: Optional[str] = None):
- """Log user-related events"""
- self._write_structured_log(LogCategory.USER, level, message, user_data, user_id, user_email)
-
- # Also log to main logger
- getattr(self.logger, level.value.lower())(
- f"[USER] {message} - User: {user_email or user_id or 'N/A'}"
- )
-
- def log_security_event(self, message: str, level: LogLevel = LogLevel.WARNING,
- security_data: Optional[Dict] = None, user_id: Optional[int] = None,
- user_email: Optional[str] = None):
- """Log security-related events"""
- self._write_structured_log(LogCategory.SECURITY, level, message, security_data, user_id, user_email)
-
- # Security events should always be logged to main logger
- getattr(self.logger, level.value.lower())(
- f"[SECURITY] {message} - User: {user_email or user_id or 'N/A'}"
- )
-
- def log_api_event(self, message: str, level: LogLevel = LogLevel.INFO,
- api_data: Optional[Dict] = None, user_id: Optional[int] = None,
- user_email: Optional[str] = None):
- """Log API-related events"""
- self._write_structured_log(LogCategory.API, level, message, api_data, user_id, user_email)
-
- getattr(self.logger, level.value.lower())(
- f"[API] {message} - User: {user_email or user_id or 'N/A'}"
- )
-
- def log_database_event(self, message: str, level: LogLevel = LogLevel.INFO,
- db_data: Optional[Dict] = None, user_id: Optional[int] = None,
- user_email: Optional[str] = None):
- """Log database-related events"""
- self._write_structured_log(LogCategory.DATABASE, level, message, db_data, user_id, user_email)
-
- getattr(self.logger, level.value.lower())(
- f"[DATABASE] {message} - User: {user_email or user_id or 'N/A'}"
- )
-
- def log_email_event(self, message: str, level: LogLevel = LogLevel.INFO,
- email_data: Optional[Dict] = None, user_id: Optional[int] = None,
- user_email: Optional[str] = None):
- """Log email-related events"""
- self._write_structured_log(LogCategory.EMAIL, level, message, email_data, user_id, user_email)
-
- getattr(self.logger, level.value.lower())(
- f"[EMAIL] {message} - User: {user_email or user_id or 'N/A'}"
- )
-
- def log_print_event(self, message: str, level: LogLevel = LogLevel.INFO,
- print_data: Optional[Dict] = None, user_id: Optional[int] = None,
- user_email: Optional[str] = None):
- """Log printer-related events"""
- self._write_structured_log(LogCategory.PRINT, level, message, print_data, user_id, user_email)
-
- getattr(self.logger, level.value.lower())(
- f"[PRINT] {message} - User: {user_email or user_id or 'N/A'}"
- )
-
- def log_chat_event(self, message: str, level: LogLevel = LogLevel.INFO,
- chat_data: Optional[Dict] = None, user_id: Optional[int] = None,
- user_email: Optional[str] = None):
- """Log chat/LLM-related events"""
- self._write_structured_log(LogCategory.CHAT, level, message, chat_data, user_id, user_email)
-
- getattr(self.logger, level.value.lower())(
- f"[CHAT] {message} - User: {user_email or user_id or 'N/A'}"
- )
-
- def log_system_event(self, message: str, level: LogLevel = LogLevel.INFO,
- system_data: Optional[Dict] = None):
- """Log system-related events"""
- self._write_structured_log(LogCategory.SYSTEM, level, message, system_data)
-
- getattr(self.logger, level.value.lower())(f"[SYSTEM] {message}")
- # Global instance
- structured_logger = StructuredLogger()
- # Legacy functions for backward compatibility
- def log_order(username, table, order_date, items: List[str]):
- """Log order information to CSV file (legacy function)"""
- try:
- structured_logger.log_order_event(
- f"Order placed for table {table}",
- LogLevel.INFO,
- {
- "username": username,
- "table": table,
- "order_date": order_date,
- "items": items,
- "item_count": len(items) if isinstance(items, list) else 1
- },
- user_email=username
- )
-
- # Still maintain CSV for backward compatibility
- csv_file = os.path.join(structured_logger.logs_dir, 'orders.csv')
- if not os.path.exists(csv_file):
- with open(csv_file, 'w', newline='', encoding='utf-8') as f:
- writer = csv.writer(f)
- writer.writerow(['userName', 'table', 'orderDate', 'items'])
-
- with open(csv_file, 'a', newline='', encoding='utf-8') as f:
- writer = csv.writer(f)
- writer.writerow([username, table, order_date, items])
-
- except Exception as e:
- logger.error(f"Failed to log order: {e}")
- def log_llm_response(user: str, response: str):
- """Log LLM response to file (legacy function)"""
- try:
- structured_logger.log_chat_event(
- f"LLM response generated for user {user}",
- LogLevel.INFO,
- {
- "response_length": len(response),
- "response_preview": response[:100] + "..." if len(response) > 100 else response
- },
- user_email=user
- )
-
- # Still maintain text file for backward compatibility
- llm_log_file = os.path.join(structured_logger.logs_dir, 'llm_responses.txt')
- file_mode = "a" if os.path.exists(llm_log_file) else "w"
- with open(llm_log_file, file_mode, encoding='utf-8') as f:
- f.write(f"{datetime.now().isoformat()} - {user}: {response}\n")
-
- except Exception as e:
- logger.error(f"Failed to log LLM response: {e}")
|