import logging
LOGGING_STATUS = 25
[docs]class NuRadioLogger(logging.Logger):
"""
Custom logging class for NuRadio modules and applications. It adds a custom log level STATUS,
which has level=`LOGGING_STATUS` as defined in `logging.py` (as of February 2024, its value is 25).
The associated `status()` call is also implemented.
"""
def __init__(self, name):
super().__init__(name)
# Add STATUS as the level name, to be used in message formatting
logging.addLevelName(LOGGING_STATUS, "STATUS")
[docs] def status(self, message, *args, **kwargs):
if self.isEnabledFor(LOGGING_STATUS):
self._log(LOGGING_STATUS, message, args, **kwargs)
[docs]def addLoggingLevel(levelName, levelNum, methodName=None):
"""
Comprehensively adds a new logging level to the `logging` module and the
currently configured logging class.
`levelName` becomes an attribute of the `logging` module with the value
`levelNum`. `methodName` becomes a convenience method for both `logging`
itself and the class returned by `logging.getLoggerClass()` (usually just
`logging.Logger`). If `methodName` is not specified, `levelName.lower()` is
used.
To avoid accidental clobberings of existing attributes, this method will
raise an `AttributeError` if the level name is already an attribute of the
`logging` module or if the method name is already present
Examples
--------
>>> addLoggingLevel('TRACE', logging.DEBUG - 5)
>>> logging.getLogger(__name__).setLevel("TRACE")
>>> logging.getLogger(__name__).trace('that worked')
>>> logging.trace('so did this')
>>> logging.TRACE
5
Notes
-----
This function was taken from
`this answer <https://stackoverflow.com/questions/2183233/how-to-add-a-custom-loglevel-to-pythons-logging-facility/35804945#35804945>`_
"""
if not methodName:
methodName = levelName.lower()
if hasattr(logging, levelName):
raise AttributeError('{} already defined in logging module'.format(levelName))
if hasattr(logging, methodName):
raise AttributeError('{} already defined in logging module'.format(methodName))
if hasattr(logging.getLoggerClass(), methodName):
raise AttributeError('{} already defined in logger class'.format(methodName))
# This method was inspired by the answers to Stack Overflow post
# http://stackoverflow.com/q/2183233/2988730, especially
# http://stackoverflow.com/a/13638084/2988730
def logForLevel(self, message, *args, **kwargs):
if self.isEnabledFor(levelNum):
self._log(levelNum, message, args, **kwargs)
def logToRoot(message, *args, **kwargs):
logging.log(levelNum, message, *args, **kwargs)
logging.addLevelName(levelNum, levelName)
setattr(logging, levelName, levelNum)
setattr(logging.getLoggerClass(), methodName, logForLevel)
setattr(logging, methodName, logToRoot)
def _setup_logger(name="NuRadioReco", level=None):
"""
Set up the parent logger which all module loggers should pass their logs on to. If this one already
exists, nothing is done and the logger is returned as is. Otherwise, a single new `logging.StreamHandler()`
with a custom formatter is added.
Notes
-----
This function is only meant to be called once, on import, as part of the `__init__.py` scripts of the base packages
NuRadioReco and NuRadioMC. It is not meant nor necessary to call this function from a module or user script.
Parameters
----------
name : str, default="NuRadioReco"
The name of the base logger
level : int, default=25
The logging level to use for the base logger
"""
logger = logging.getLogger(name)
if len(logger.handlers) > 0: # method hasHandlers() also checks parents -> ends up at root logger
# Don't change the logger if it already exists
logger.warning(f"Logger {name} already has handlers. Not changing anything, returning the existing logger...")
return logger
logger.propagate = False
# Create a StreamHandler with fancy formatter
handler = logging.StreamHandler()
handler.setFormatter(get_fancy_formatter())
handler.setLevel(1) # we want the handler to be accepting all records from child loggers
# Then add our custom handler to the logger
logger.addHandler(handler)
# Finally, set the logging level
if level is not None:
logger.setLevel(level=level)
else:
logger.setLevel(LOGGING_STATUS)
return logger
[docs]def set_general_log_level(level):
"""
Set the logging level of the NuRadioMC and NuRadioReco loggers to `level`.
Parameters
----------
level : int
The desired logging level
"""
nrr_logger = logging.getLogger("NuRadioReco")
nrr_logger.setLevel(level)
nrmc_logger = logging.getLogger("NuRadioMC")
nrmc_logger.setLevel(level)