"""
Logging utilities for simulation.
Provides structured logging for simulation events and debugging.
"""
from __future__ import annotations
import logging
import sys
from typing import TYPE_CHECKING, Any, Optional
if TYPE_CHECKING:
from simcraft.core.simulation import Simulation
[docs]
def setup_logging(
level: int = logging.INFO,
format_string: Optional[str] = None,
filename: Optional[str] = None,
) -> None:
"""
Set up logging for simulation.
Parameters
----------
level : int
Logging level
format_string : Optional[str]
Custom format string
filename : Optional[str]
Log file path
"""
if format_string is None:
format_string = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
handlers = []
# Console handler
console = logging.StreamHandler(sys.stdout)
console.setLevel(level)
console.setFormatter(logging.Formatter(format_string))
handlers.append(console)
# File handler
if filename:
file_handler = logging.FileHandler(filename)
file_handler.setLevel(level)
file_handler.setFormatter(logging.Formatter(format_string))
handlers.append(file_handler)
# Configure root logger
logging.basicConfig(level=level, handlers=handlers, format=format_string)
[docs]
class SimulationLogger:
"""
Logger for simulation events.
Provides structured logging with simulation time stamps.
Parameters
----------
sim : Simulation
Parent simulation
name : str
Logger name
level : int
Logging level
Examples
--------
>>> logger = SimulationLogger(sim, "MyModel")
>>> logger.info("Customer arrived")
>>> logger.debug("Queue length: %d", queue.length)
"""
[docs]
def __init__(
self,
sim: "Simulation",
name: str = "",
level: int = logging.INFO,
) -> None:
"""Initialize logger."""
self._sim = sim
self._name = name or "Simulation"
self._logger = logging.getLogger(f"simcraft.{self._name}")
self._logger.setLevel(level)
def _format_message(self, message: str) -> str:
"""Add simulation time to message."""
return f"[t={self._sim.now:.4f}] {message}"
[docs]
def debug(self, message: str, *args: Any, **kwargs: Any) -> None:
"""Log debug message."""
self._logger.debug(self._format_message(message), *args, **kwargs)
[docs]
def info(self, message: str, *args: Any, **kwargs: Any) -> None:
"""Log info message."""
self._logger.info(self._format_message(message), *args, **kwargs)
[docs]
def warning(self, message: str, *args: Any, **kwargs: Any) -> None:
"""Log warning message."""
self._logger.warning(self._format_message(message), *args, **kwargs)
[docs]
def error(self, message: str, *args: Any, **kwargs: Any) -> None:
"""Log error message."""
self._logger.error(self._format_message(message), *args, **kwargs)
[docs]
def event(
self,
event_type: str,
entity_id: Optional[str] = None,
**details: Any,
) -> None:
"""
Log a structured simulation event.
Parameters
----------
event_type : str
Type of event (e.g., "arrival", "departure")
entity_id : Optional[str]
Entity identifier
**details
Additional event details
"""
parts = [f"[t={self._sim.now:.4f}]", event_type]
if entity_id:
parts.append(f"entity={entity_id}")
for key, value in details.items():
parts.append(f"{key}={value}")
self._logger.info(" ".join(parts))
[docs]
def set_level(self, level: int) -> None:
"""Set logging level."""
self._logger.setLevel(level)