Skip to content

Logging

configure_logging is a top-level convenience for the package logger (emotional_memory.*). Engine modules log pipeline events at DEBUG; warnings.warn is reserved for user-visible degradation.

See the observability tutorial for structured logs plus OpenTelemetry spans.

from emotional_memory import configure_logging

configure_logging(level="DEBUG")
configure_logging(level="INFO", json_format=True)

With no argument, the level comes from EMOTIONAL_MEMORY_LOG_LEVEL (default WARNING).

emotional_memory.logging_config.configure_logging(level: str | int | None = None, *, json_format: bool = False) -> None

Configure the root emotional_memory logger.

Parameters:

Name Type Description Default
level str | int | None

Log level. When None (default), uses EMOTIONAL_MEMORY_LOG_LEVEL, falling back to WARNING.

None
json_format bool

When True, emit single-line JSON objects with timestamp, level, logger, and message fields.

False
Source code in src/emotional_memory/logging_config.py
def configure_logging(
    level: str | int | None = None,
    *,
    json_format: bool = False,
) -> None:
    """Configure the root ``emotional_memory`` logger.

    Args:
        level: Log level. When ``None`` (default), uses
            ``EMOTIONAL_MEMORY_LOG_LEVEL``, falling back to ``WARNING``.
        json_format: When ``True``, emit single-line JSON objects with
            ``timestamp``, ``level``, ``logger``, and ``message`` fields.
    """
    if level is None:
        level = os.environ.get("EMOTIONAL_MEMORY_LOG_LEVEL", "WARNING")
    if isinstance(level, str):
        numeric_level: int = int(getattr(logging, level.upper(), logging.WARNING))
    else:
        numeric_level = level

    handler = logging.StreamHandler(sys.stdout)
    if json_format:
        import json

        class _JsonFormatter(logging.Formatter):
            def format(self, record: logging.LogRecord) -> str:
                payload = {
                    "timestamp": self.formatTime(record),
                    "level": record.levelname,
                    "logger": record.name,
                    "message": record.getMessage(),
                }
                if record.exc_info:
                    payload["exc_info"] = self.formatException(record.exc_info)
                return json.dumps(payload, default=str)

        handler.setFormatter(_JsonFormatter())
    else:
        handler.setFormatter(
            logging.Formatter(
                fmt="%(asctime)s | %(name)s | %(levelname)s | %(message)s",
                datefmt="%Y-%m-%d %H:%M:%S",
            )
        )

    logger = logging.getLogger("emotional_memory")
    logger.setLevel(numeric_level)
    # Avoid duplicate handlers if configure_logging is called twice.
    if not any(isinstance(h, logging.StreamHandler) for h in logger.handlers):
        logger.addHandler(handler)