# default_exp debug_utils
<ipython-input-3-7e79a1338067>:5: DeprecationWarning: Importing display from IPython.core.display is deprecated since IPython 7.14, please import from IPython display
  from IPython.core.display import display

Debug tools

Output

It’s necessary to have a output to where show the log. To use the default logging lib with ipywidgets, one could use the OutputWidgetHandler class.

# example of logger configuration
example_logger = logging.getLogger(__name__)
example_handler = OutputWidgetHandler()
example_handler.setFormatter(logging.Formatter('%(asctime)s  - [%(levelname)s] %(message)s'))
example_logger.addHandler(example_handler)
example_logger.setLevel(logging.INFO)

Debug tools

#export

class IpyLogger:
    """
    Redirects logging and pubsub messages (if subscribed) to output widget.

    Use `@subscribe` class decorator or `subscribe_to_states` method to listen pubsub events.
    """

    def __init__(self, class_name: str, log_level=logging.INFO):
        self._class_name = class_name

        # config the logger/output
        logger = logging.getLogger(__name__)
        handler = OutputWidgetHandler()
        handler.setFormatter(logging.Formatter('%(asctime)s - %(message)s'))
        logger.addHandler(handler)
        logger.setLevel(log_level)
        self._logger = logger
        self._handler = handler

    def debug(self, msg, *args, **kwargs):
        self._logger.debug(msg, *args, **kwargs)

    def info(self, msg, *args, **kwargs):
        self._logger.info(msg, *args, **kwargs)

    def warning(self, msg, *args, **kwargs):
        self._logger.warning(msg, *args, **kwargs)

    def error(self, msg, *args, **kwargs):
        self._logger.error(msg, *args, **kwargs)

    def critical(self, msg, *args, **kwargs):
        self._logger.critical(msg, *args, **kwargs)

    def subscribe(self, states):
        def wrapper(cls):
            def inside_wrapper(*args, **kwargs):
                self.subscribe_to_states(states=states)
                return cls(*args, **kwargs)
            return inside_wrapper
        return wrapper

    def show_logs(self):
        return self._handler.show_logs()

    def clear_logs(self):
        return self._handler.clear_logs()

    def subscribe_to_states(self, states: List[Any]):
        states = self._validate_states(states)
        for state in states:
            pub.subscribe(self._pub_handler, state)

    def _pub_handler(self, topic_obj=pub.AUTO_TOPIC, *args, **kwargs):
        self._logger.info(f"[{self._class_name} - {topic_obj.getName()}] : {kwargs}")

    @staticmethod
    def _validate_states(states):
        """Avoids errors where string is handled as list"""
        if isinstance(states, str):
            states = [states]
        return states
logger = IpyLogger("mylogger", log_level=logging.DEBUG)
logger.show_logs()
from pubsub import pub


def test_listener(a1, a2=None):
    print('listener:')
    print('a1 =', a1)
    print('a2 =', a2)


pub.subscribe(test_listener, 'rootTopic')

logger.subscribe_to_states(['rootTopic'])
pub.sendMessage('rootTopic', a1=123, a2=dict(a=456, b='abc'))
listener:
a1 = 123
a2 = {'a': 456, 'b': 'abc'}
pub.sendMessage('rootTopic', a1=122, a2=334)
listener:
a1 = 122
a2 = 334
# l.info("Hey info", stack_info=True)
logger.debug("Hey debug")