from dataclasses import dataclass, field from datetime import datetime from typing import Any MODULES = {"api", "bot", "ocr", "ai", "db", "capture", "audit", "error"} DOMAIN_MODULES = {"api", "bot", "ocr", "ai", "db", "capture"} ALLOWED_EVENTS = { "api.bot.status", "api.bot.start", "api.bot.stop", "api.messages.receive", "audit.decision", "bot.chat_analyze", "bot.chat_snapshot", "bot.loop", "bot.session_scan", "bot.session_service.init", "bot.session_title", "bot.submit", "bot.unread.detect", "bot.unread.scan", "ocr.baidu.token", "ocr.baidu.recognize", "ocr.rapid.init", "ocr.rapid.recognize", "ocr.fallback", "ocr.session_name", "ocr.session_title", "ocr.generic", "capture.contact_list", "capture.session_title", "capture.chat_area", "ai.request", "ai.response", "db.init", "db.error", "db.rule.query", "db.rule.match", } def normalize_event(module: str, event: str) -> str: e = str(event or "").strip().lower() m = str(module or "").strip().lower() if e in ALLOWED_EVENTS: return e if "." in e: prefix = e.split(".", 1)[0] if prefix in DOMAIN_MODULES: return e if m in DOMAIN_MODULES: return f"{m}.unknown" return "api.unknown" @dataclass class LogEvent: level: str module: str event: str trace_id: str stage: str status: str message: str reason: str = "" extra: dict[str, Any] = field(default_factory=dict) ts: str = "" def to_dict(self) -> dict[str, Any]: ts = self.ts or datetime.now().astimezone().isoformat(timespec="milliseconds") module = self.module if self.module in MODULES else "api" event = normalize_event(module, self.event) return { "ts": ts, "level": (self.level or "INFO").upper(), "module": module, "event": event, "trace_id": self.trace_id or "-", "stage": self.stage or "-", "status": self.status or "ok", "reason": self.reason or "", "message": self.message or "", "extra": self.extra or {}, }