Warnings fixed: - datetime.utcnow() → datetime.now(UTC) across 48+ files (src/ + tests/) - datetime.utcnow (callback ref) → lambda: datetime.now(UTC) in model fields (18 files) - Pydantic class Config → model_config = ConfigDict(...) (16 files) - Pydantic .dict() → .model_dump() (8 files) - ConfigDict(allow_population_by_field_name=True) → validate_by_name=True - SQLAlchemy declarative_base() import path updated - FastAPI on_event → lifespan context manager (app.py) - Import sorting (ruff I001) auto-fixed across all files - Fixed broken re-export chains that ruff F401 cleanup broke: _validate_bcp47: service.py now imports from dictionary_validation directly job_to_response: _job_routes.py and test imports from service_utils directly fetch_datasource_metadata: restored re-export in service.py - Added missing TranslateJobService import in _job_routes.py (was deleted by F401) - Added ConfigDict(protected_namespaces=()) for DashboardDatasetItem schema field - pytest.ini: replaced deprecated importmode with asyncio_mode All 440 tests pass with zero deprecation warnings.
71 lines
2.7 KiB
Python
71 lines
2.7 KiB
Python
# #region WsLogHandlerModule [C:3] [TYPE Module] [SEMANTICS pydantic, dto, log-entry]
|
|
# @BRIEF WebSocket log handler module providing LogEntry DTO and WebSocketLogHandler for buffered log streaming.
|
|
# @RELATION DEPENDS_ON -> [LogEntry]
|
|
# @RELATION DEPENDS_ON -> [CotJsonFormatter]
|
|
from collections import deque
|
|
from datetime import UTC, datetime
|
|
import logging
|
|
from typing import Any
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
|
|
# #region LogEntry [C:1] [TYPE Class] [SEMANTICS log,entry,record,pydantic]
|
|
class LogEntry(BaseModel):
|
|
timestamp: datetime = Field(default_factory=lambda: datetime.now(UTC))
|
|
level: str
|
|
message: str
|
|
context: dict[str, Any] | None = None
|
|
# #endregion LogEntry
|
|
|
|
|
|
# #region WebSocketLogHandler [C:3] [TYPE Class] [SEMANTICS logging,handler,websocket,buffer]
|
|
# @BRIEF Custom logging handler that captures log records into a fixed-capacity buffer for WebSocket streaming.
|
|
# @RELATION DEPENDS_ON -> [LogEntry]
|
|
# @RELATION DEPENDS_ON -> [CotJsonFormatter]
|
|
class WebSocketLogHandler(logging.Handler):
|
|
"""
|
|
A logging handler that stores log records and can be extended to send them
|
|
over WebSockets.
|
|
"""
|
|
|
|
# #region WebSocketLogHandler.__init__ [C:1] [TYPE Function] [SEMANTICS init,handler,buffer]
|
|
def __init__(self, capacity: int = 1000):
|
|
super().__init__()
|
|
self.log_buffer: deque[LogEntry] = deque(maxlen=capacity)
|
|
# #endregion WebSocketLogHandler.__init__
|
|
|
|
# #region WebSocketLogHandler.emit [C:2] [TYPE Function] [SEMANTICS log,capture,format,buffer]
|
|
# @BRIEF Captures a log record, formats it, and stores it in the buffer as a LogEntry.
|
|
def emit(self, record: logging.LogRecord):
|
|
try:
|
|
log_entry = LogEntry(
|
|
level=record.levelname,
|
|
message=self.format(record),
|
|
context={
|
|
"name": record.name,
|
|
"pathname": record.pathname,
|
|
"lineno": record.lineno,
|
|
"funcName": record.funcName,
|
|
"process": record.process,
|
|
"thread": record.thread,
|
|
}
|
|
)
|
|
self.log_buffer.append(log_entry)
|
|
except Exception:
|
|
self.handleError(record)
|
|
# #endregion WebSocketLogHandler.emit
|
|
|
|
# #region WebSocketLogHandler.get_recent_logs [C:2] [TYPE Function] [SEMANTICS log,retrieve,buffer]
|
|
# @BRIEF Returns a list of recent log entries from the buffer.
|
|
def get_recent_logs(self) -> list[LogEntry]:
|
|
"""
|
|
Returns a list of recent log entries from the buffer.
|
|
"""
|
|
return list(self.log_buffer)
|
|
# #endregion WebSocketLogHandler.get_recent_logs
|
|
|
|
|
|
# #endregion WebSocketLogHandler
|
|
# #endregion WsLogHandlerModule
|