Spaces:
Sleeping
Sleeping
anoderb
Modernisasi Forecast Dashboard: Glassmorphism UI, SARIMA Model, and Backend Refactor
bdef324 | # logger.py — In-memory log handler for realtime log streaming | |
| # Ported from Daily Scrapper architecture | |
| import logging | |
| from datetime import datetime | |
| from typing import List, Dict, Optional | |
| class MemoryLogHandler(logging.Handler): | |
| """Stores log entries in memory for API consumption (realtime streaming).""" | |
| def __init__(self, capacity: int = 500): | |
| super().__init__() | |
| self.capacity = capacity | |
| self.logs: List[Dict] = [] | |
| def emit(self, record): | |
| try: | |
| msg = record.getMessage() | |
| log_entry = { | |
| "timestamp": datetime.fromtimestamp(record.created).isoformat(), | |
| "level": record.levelname, | |
| "source": record.name.split(".")[-1], | |
| "message": msg, | |
| } | |
| self.logs.append(log_entry) | |
| if len(self.logs) > self.capacity: | |
| self.logs.pop(0) | |
| except Exception: | |
| self.handleError(record) | |
| def get_logs( | |
| self, limit: int = 100, level: Optional[str] = None | |
| ) -> List[Dict]: | |
| filtered = self.logs | |
| if level and level.upper() != "ALL": | |
| filtered = [l for l in filtered if l["level"] == level.upper()] | |
| return filtered[-limit:] | |
| def clear_logs(self): | |
| self.logs.clear() | |
| # Singleton handler shared across all modules | |
| memory_handler = MemoryLogHandler() | |
| def get_app_logger(name: str) -> logging.Logger: | |
| """Get a named logger that writes to both console and memory buffer.""" | |
| logger = logging.getLogger(f"app.{name}") | |
| logger.setLevel(logging.INFO) | |
| # Ensure memory handler is added only once | |
| if not any(isinstance(h, MemoryLogHandler) for h in logger.handlers): | |
| logger.addHandler(memory_handler) | |
| # Also add console handler for local debugging | |
| if not any(isinstance(h, logging.StreamHandler) and not isinstance(h, MemoryLogHandler) for h in logger.handlers): | |
| console = logging.StreamHandler() | |
| console.setLevel(logging.INFO) | |
| console.setFormatter(logging.Formatter("%(asctime)s [%(levelname)s] %(name)s: %(message)s")) | |
| logger.addHandler(console) | |
| return logger | |