# #region CotLoggerModule [C:4] [TYPE Module] [SEMANTICS logging, cot, json, trace, structured] # @BRIEF Structured JSON logger implementing the molecular CoT (Chain-of-Thought) logging protocol. # Uses ContextVar for trace_id and span_id propagation across async contexts. # Provides log(), MarkerLogger, seed_trace_id(), push_span(), pop_span(). # @LAYER: Core # @RELATION CALLED_BY -> [TraceContextMiddleware] # @RELATION CALLED_BY -> [All C4+ service and route modules] # @PRE: Python 3.7+ (ContextVar available). # @POST: JSON log records written to the 'cot' logger at appropriate levels. # @SIDE_EFFECT: Writes structured JSON to the 'cot' Python logger. # @DATA_CONTRACT: Log call -> Single-line JSON to logging.StreamHandler/file. import json import logging import uuid from contextvars import ContextVar from datetime import datetime, timezone from typing import Any, Dict, Optional # #region cot_trace_context [C:1] [TYPE Data] [SEMANTICS contextvar, trace_id, span_id, propagation] # @BRIEF ContextVars for trace ID and span ID propagation across async boundaries. _trace_id: ContextVar[str] = ContextVar("_trace_id", default="") _span_id: ContextVar[str] = ContextVar("_span_id", default="") # #endregion cot_trace_context # #region cot_logger_instance [C:1] [TYPE Data] [SEMANTICS logger, instance] # @BRIEF Dedicated Python logger for all CoT (molecular) log output. cot_logger = logging.getLogger("cot") # #endregion cot_logger_instance __all__ = [ "seed_trace_id", "set_trace_id", "get_trace_id", "push_span", "pop_span", "log", "MarkerLogger", ] # #region seed_trace_id [C:1] [TYPE Function] [SEMANTICS trace_id, uuid, contextvar, set] # @BRIEF Generate a new UUID4 trace_id, set it in ContextVar, and return it. def seed_trace_id() -> str: """Generate a new UUID4 trace ID and store it in the thread-local ContextVar. Returns: str: The newly generated trace ID. """ trace_id = str(uuid.uuid4()) _trace_id.set(trace_id) return trace_id # #endregion seed_trace_id # #region set_trace_id [C:1] [TYPE Function] [SEMANTICS trace_id, contextvar, set, public] # @BRIEF Set an explicit trace_id into the ContextVar (e.g. from an incoming header). def set_trace_id(trace_id: str) -> None: """Set a specific trace_id into the ContextVar. This is used by TraceContextMiddleware when an ``X-Trace-ID`` header is present, enabling cross-service trace chaining. Args: trace_id: The trace ID to set. """ _trace_id.set(trace_id) # #endregion set_trace_id # #region get_trace_id [C:1] [TYPE Function] [SEMANTICS trace_id, contextvar, get, public] # @BRIEF Get the current trace_id from ContextVar. def get_trace_id() -> str: """Get the current trace_id from the thread-local ContextVar. Returns: str: The current trace ID, or empty string if none set. """ return _trace_id.get() # #endregion get_trace_id # #region push_span [C:1] [TYPE Function] [SEMANTICS span_id, contextvar, stack] # @BRIEF Set a new span_id in ContextVar and return the previous span_id for later restoration. def push_span(span: str) -> str: """Push a new span ID onto the context and return the previous span ID. Args: span: The new span identifier (e.g. function or operation name). Returns: str: The previous span ID, suitable for passing to pop_span(). """ prev = _span_id.get() _span_id.set(span) return prev # #endregion push_span # #region pop_span [C:1] [TYPE Function] [SEMANTICS span_id, contextvar, restore] # @BRIEF Restore a previous span_id into the ContextVar. def pop_span(prev: str) -> None: """Restore a previous span ID into the ContextVar. Args: prev: The span ID to restore (previously returned by push_span). """ _span_id.set(prev) # #endregion pop_span # #region cot_log_function [C:2] [TYPE Function] [SEMANTICS log, json, structured, marker] # @BRIEF Core structured logging function that emits a single-line JSON record. def log( src: str, marker: str, intent: str, payload: Optional[Dict[str, Any]] = None, error: Optional[str] = None, level: Optional[str] = None, ) -> None: """Emit a single-line structured JSON log record through the 'cot' logger. Args: src: Qualified function or component name (e.g. 'AuthRepository.get_user'). marker: Protocol marker — one of 'REASON', 'REFLECT', 'EXPLORE'. intent: Short one-line description of the intent or action. payload: Optional structured data dict to include in the record. error: Required for EXPLORE markers; describes the violated assumption. level: Log level override. Auto-inferred from marker if omitted (REASON/REFLECT -> INFO, EXPLORE -> WARNING). Side effects: Writes a single-line JSON string to the 'cot' Python logger. """ if level is None: level = "WARNING" if marker == "EXPLORE" else "INFO" # Build structured extra data for the LogRecord. # CotJsonFormatter will read these attributes to produce the final JSON output, # consistent with the main superset_tools_app logger. extra: Dict[str, Any] = { "marker": marker, "intent": intent, "src": src, } if payload is not None: extra["payload"] = payload if error is not None: extra["error"] = error log_func = { "WARNING": cot_logger.warning, "ERROR": cot_logger.error, "DEBUG": cot_logger.debug, }.get(level, cot_logger.info) log_func(intent, extra=extra) # #endregion cot_log_function # #region MarkerLogger [C:2] [TYPE Class] [SEMANTICS logger, proxy, marker, syntactic-sugar] # @BRIEF Thin proxy class providing .reason(), .reflect(), .explore() convenience methods. class MarkerLogger: """Thin proxy over the cot_logger.log() function. Usage:: log = MarkerLogger("AuthService") log.reason("Validating credentials", payload={"user_id": "..."}) log.reflect("Validation complete", payload={"result": "ok"}) log.explore("Token expired", error="JWT expired, attempting refresh") Each method delegates to :func:`log` with the corresponding marker. """ # #region MarkerLogger.__init__ [TYPE Function] # @BRIEF Store the module/component name used as the 'src' field in all log calls. def __init__(self, module_name: str) -> None: """Initialise the MarkerLogger with a module or component name. Args: module_name: The value used for the 'src' field (e.g. 'AuthService'). """ self._module_name = module_name # #endregion MarkerLogger.__init__ # #region MarkerLogger.reason [TYPE Function] # @BRIEF Log a REASON marker — strict deduction, core logic. def reason( self, intent: str, *, payload: Optional[Dict[str, Any]] = None ) -> None: """Log a REASON marker (INFO level).""" log(self._module_name, "REASON", intent, payload=payload) # #endregion MarkerLogger.reason # #region MarkerLogger.reflect [TYPE Function] # @BRIEF Log a REFLECT marker — self-check, structural validation. def reflect( self, intent: str, *, payload: Optional[Dict[str, Any]] = None ) -> None: """Log a REFLECT marker (INFO level).""" log(self._module_name, "REFLECT", intent, payload=payload) # #endregion MarkerLogger.reflect # #region MarkerLogger.explore [TYPE Function] # @BRIEF Log an EXPLORE marker — searching, alternatives, violated assumptions. def explore( self, intent: str, *, payload: Optional[Dict[str, Any]] = None, error: Optional[str] = None, ) -> None: """Log an EXPLORE marker (WARNING level). Args: intent: Short description of what was being attempted. payload: Optional structured data. error: Describes the violated assumption or error context. """ log(self._module_name, "EXPLORE", intent, payload=payload, error=error) # #endregion MarkerLogger.explore # #endregion MarkerLogger # #endregion CotLoggerModule