Spaces:
Sleeping
Sleeping
File size: 2,166 Bytes
bdef324 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | # 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
|