Source code for bamengine.logging
"""
Custom logging configuration for BAM Engine.
Extends Python's standard logging with a custom TRACE level (5)
for very verbose debugging output. Provides BamLogger class with
per-event log level configuration support.
Log Levels
----------
- CRITICAL (50): Critical errors
- ERROR (40): Errors
- WARNING (30): Warnings
- INFO (20): Informational messages (default)
- DEBUG (10): Debug messages
- TRACE (5): Very verbose debug messages
Examples
--------
Use logger in events:
>>> from bamengine import logging
>>> logger = getLogger("bamengine.events.my_event")
>>> logger.info("Event executing")
>>> logger.debug("Detailed debug info")
>>> logger.trace("Very verbose output")
Set log level:
>>> import bamengine as be
>>> sim = be.Simulation.init(log_level="WARNING")
Configure per-event log levels (advanced):
>>> log_config = {
... "default_level": "INFO",
... "events": {"firms_adjust_price": "DEBUG", "labor_market_round": "WARNING"},
... }
>>> sim = be.Simulation.init(logging=log_config)
Check if logging level enabled:
>>> if logger.isEnabledFor(logging.DEBUG):
... expensive_stats = compute_expensive_stats()
... logger.debug("Stats: %s", expensive_stats)
See Also
--------
Event.get_logger : Get logger for specific event
"""
import logging
from typing import Any
(CRITICAL, ERROR, WARNING, INFO, DEBUG) = (
logging.CRITICAL,
logging.ERROR,
logging.WARNING,
logging.INFO,
logging.DEBUG,
)
TRACE = 5
logging.addLevelName(TRACE, "TRACE")
[docs]
class BamLogger(logging.Logger):
"""
Custom logger with TRACE level support.
Extends Python's Logger to add the `trace()` method for very verbose
debugging output (level 5).
Examples
--------
>>> logger = BamLogger("test")
>>> logger.setLevel(5) # TRACE
>>> logger.trace("Very verbose message")
See Also
--------
getLogger : Factory function for obtaining BamLogger instances
"""
[docs]
def trace(self, msg: str, *args: Any, **kwargs: Any) -> None:
"""
Log message at TRACE level (5).
Parameters
----------
msg : str
Message format string.
*args : Any
Arguments for message formatting.
**kwargs : Any
Additional logging kwargs.
"""
if self.isEnabledFor(TRACE):
self._log(TRACE, msg, args, **kwargs)
# Make the logging module hand out our subclass from now on
logging.setLoggerClass(BamLogger)
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
datefmt="%H:%M:%S",
)
# Library best practice: prevent "No handlers found" warnings when
# the application hasn't configured logging for bamengine.
logging.getLogger("bamengine").addHandler(logging.NullHandler())
[docs]
def getLogger(name: str = "bamengine") -> BamLogger:
"""
Get a BamLogger instance.
Convenience wrapper around logging.getLogger() that returns
a BamLogger instance with TRACE support.
Parameters
----------
name : str, optional, default="bamengine"
Logger name. If None, returns bamengine logger.
Returns
-------
BamLogger
Logger instance with trace() method.
Examples
--------
>>> from bamengine import logging
>>> logger = logging.getLogger("bamengine.events.my_event")
>>> logger.info("Message")
>>> logger.trace("Very verbose")
See Also
--------
BamLogger : Custom logger class
Event.get_logger : Get logger for specific event
"""
return logging.getLogger(name) # type: ignore[return-value]