Module jumpscale.tools.errorhandler.errorhandler

Expand source code
import inspect
import sys
import traceback

from jumpscale.loader import j


class ErrorHandler:
    def __init__(self):
        self.handlers = []

    def _format_lines(self, lines):
        return "".join(lines).strip()

    def _construct_stacktrace(self, frame):
        stacktrace = []
        while frame:
            frame_info = inspect.getframeinfo(frame)

            if frame_info.code_context:
                code_context = frame_info.code_context[0].strip()
            else:
                code_context = ""

            stacktrace.append(
                {
                    "filename": j.sals.fs.basename(frame_info.filename),
                    "filepath": frame_info.filename,
                    "context": frame_info.function,
                    "linenr": frame_info.lineno,
                    "code": code_context,
                }
            )
            frame = frame.tb_next
        return stacktrace

    def get_traceback(self, exc_info=None):
        """Get a trackback information as a dict, suitable to used with error/alert handlers

        if `exe_info` is not passed, `sys.exc_info()` will be used instead.

        Example traceback information:

        ```
        {
            'process_id': 20840,
            'raw': 'Traceback (most recent call last):\n  File "<stdin>", line 1, in <module>\nValueError: a is not valid',
            'straceback': [
                {
                    'code': '',
                    'context': '<module>',
                    'filename': '<stdin>',
                    'filepath': '<stdin>',
                    'linenr': 1
                }
            ]
        }
        ```

        Args:
            exc_info (tuple, optional): exception information as a tuple (ttype, tvalue, tb). Defaults to None.

        Returns:
            dict: raw and stacktrace information as a dict, alongside process id
        """
        if exc_info:
            ttype, tvalue, tb = exc_info
        else:
            ttype, tvalue, tb = sys.exc_info()

        stacktrace = self._construct_stacktrace(tb)
        traceback_text = self._format_lines(traceback.format_exception(ttype, tvalue, tb))

        return {"raw": traceback_text, "stacktrace": stacktrace, "process_id": j.application.process_id}

    def _handle_exception(self, ttype, tvalue, tb, level=40, die=False, log=True, category="", data=None):
        exc_info = (ttype, tvalue, tb)
        timestamp = j.data.time.now().timestamp
        message = self._format_lines(traceback.format_exception_only(ttype, tvalue))

        err_dict = {
            "app_name": j.logger.default_app_name,
            "level": level,
            "message": message,
            "timestamp": timestamp,
            "category": category or "exception",
            "data": data,
            "traceback": self.get_traceback(exc_info),
        }

        if log:
            exception = exc_info
            j.logger.exception(message=message, category=category, data=data, level=level, exception=exception)

        for handler_func, handler_level in self.handlers:
            if level >= handler_level:
                handler_func(**err_dict)

        if die:
            sys.exit(1)

    def handle_exception(
        self,
        exception: Exception,
        level: int = 40,
        die: bool = False,
        log: bool = True,
        category: str = "",
        data: dict = None,
    ):
        """Hndler exception

        Arguments:
            exception {Exception} -- the exception object to handle

        Keyword Arguments:
            level {int} -- exception level (default: {40})
            die {bool} -- optional flag to exit after handling the exception (default: {True})
            log {bool} -- option flag to log the exception (default: {True})
            category {str} -- category (default: {""})
        """
        ttype, _, tb = sys.exc_info()
        self._handle_exception(ttype, exception, tb, die=die, log=log, category=category, data=data)

    def register_handler(self, handler: callable, level: int = 40):
        """Register new error handler

        Arguments:
            handler {callable} -- error handler callable

        Keyword Arguments:
            level {int} -- exception level (default: {40})
        """
        if (handler, level) not in self.handlers:
            self.handlers.append((handler, level))

    def excepthook(self, ttype, tvalue, tb):
        """exception hook handler"""
        self._handle_exception(ttype, tvalue, tb)

Classes

class ErrorHandler
Expand source code
class ErrorHandler:
    def __init__(self):
        self.handlers = []

    def _format_lines(self, lines):
        return "".join(lines).strip()

    def _construct_stacktrace(self, frame):
        stacktrace = []
        while frame:
            frame_info = inspect.getframeinfo(frame)

            if frame_info.code_context:
                code_context = frame_info.code_context[0].strip()
            else:
                code_context = ""

            stacktrace.append(
                {
                    "filename": j.sals.fs.basename(frame_info.filename),
                    "filepath": frame_info.filename,
                    "context": frame_info.function,
                    "linenr": frame_info.lineno,
                    "code": code_context,
                }
            )
            frame = frame.tb_next
        return stacktrace

    def get_traceback(self, exc_info=None):
        """Get a trackback information as a dict, suitable to used with error/alert handlers

        if `exe_info` is not passed, `sys.exc_info()` will be used instead.

        Example traceback information:

        ```
        {
            'process_id': 20840,
            'raw': 'Traceback (most recent call last):\n  File "<stdin>", line 1, in <module>\nValueError: a is not valid',
            'straceback': [
                {
                    'code': '',
                    'context': '<module>',
                    'filename': '<stdin>',
                    'filepath': '<stdin>',
                    'linenr': 1
                }
            ]
        }
        ```

        Args:
            exc_info (tuple, optional): exception information as a tuple (ttype, tvalue, tb). Defaults to None.

        Returns:
            dict: raw and stacktrace information as a dict, alongside process id
        """
        if exc_info:
            ttype, tvalue, tb = exc_info
        else:
            ttype, tvalue, tb = sys.exc_info()

        stacktrace = self._construct_stacktrace(tb)
        traceback_text = self._format_lines(traceback.format_exception(ttype, tvalue, tb))

        return {"raw": traceback_text, "stacktrace": stacktrace, "process_id": j.application.process_id}

    def _handle_exception(self, ttype, tvalue, tb, level=40, die=False, log=True, category="", data=None):
        exc_info = (ttype, tvalue, tb)
        timestamp = j.data.time.now().timestamp
        message = self._format_lines(traceback.format_exception_only(ttype, tvalue))

        err_dict = {
            "app_name": j.logger.default_app_name,
            "level": level,
            "message": message,
            "timestamp": timestamp,
            "category": category or "exception",
            "data": data,
            "traceback": self.get_traceback(exc_info),
        }

        if log:
            exception = exc_info
            j.logger.exception(message=message, category=category, data=data, level=level, exception=exception)

        for handler_func, handler_level in self.handlers:
            if level >= handler_level:
                handler_func(**err_dict)

        if die:
            sys.exit(1)

    def handle_exception(
        self,
        exception: Exception,
        level: int = 40,
        die: bool = False,
        log: bool = True,
        category: str = "",
        data: dict = None,
    ):
        """Hndler exception

        Arguments:
            exception {Exception} -- the exception object to handle

        Keyword Arguments:
            level {int} -- exception level (default: {40})
            die {bool} -- optional flag to exit after handling the exception (default: {True})
            log {bool} -- option flag to log the exception (default: {True})
            category {str} -- category (default: {""})
        """
        ttype, _, tb = sys.exc_info()
        self._handle_exception(ttype, exception, tb, die=die, log=log, category=category, data=data)

    def register_handler(self, handler: callable, level: int = 40):
        """Register new error handler

        Arguments:
            handler {callable} -- error handler callable

        Keyword Arguments:
            level {int} -- exception level (default: {40})
        """
        if (handler, level) not in self.handlers:
            self.handlers.append((handler, level))

    def excepthook(self, ttype, tvalue, tb):
        """exception hook handler"""
        self._handle_exception(ttype, tvalue, tb)

Methods

def excepthook(self, ttype, tvalue, tb)

exception hook handler

Expand source code
def excepthook(self, ttype, tvalue, tb):
    """exception hook handler"""
    self._handle_exception(ttype, tvalue, tb)
def get_traceback(self, exc_info=None)

Get a trackback information as a dict, suitable to used with error/alert handlers

    if <code>exe\_info</code> is not passed, <code>sys.exc\_info()</code> will be used instead.

    Example traceback information:

    ```
    {
        'process_id': 20840,
        'raw': 'Traceback (most recent call last):

File "", line 1, in ValueError: a is not valid', 'straceback': [ { 'code': '', 'context': '', 'filename': '', 'filepath': '', 'linenr': 1 } ] } ```

    Args:
        exc_info (tuple, optional): exception information as a tuple (ttype, tvalue, tb). Defaults to None.

    Returns:
        dict: raw and stacktrace information as a dict, alongside process id
Expand source code
def get_traceback(self, exc_info=None):
    """Get a trackback information as a dict, suitable to used with error/alert handlers

    if `exe_info` is not passed, `sys.exc_info()` will be used instead.

    Example traceback information:

    ```
    {
        'process_id': 20840,
        'raw': 'Traceback (most recent call last):\n  File "<stdin>", line 1, in <module>\nValueError: a is not valid',
        'straceback': [
            {
                'code': '',
                'context': '<module>',
                'filename': '<stdin>',
                'filepath': '<stdin>',
                'linenr': 1
            }
        ]
    }
    ```

    Args:
        exc_info (tuple, optional): exception information as a tuple (ttype, tvalue, tb). Defaults to None.

    Returns:
        dict: raw and stacktrace information as a dict, alongside process id
    """
    if exc_info:
        ttype, tvalue, tb = exc_info
    else:
        ttype, tvalue, tb = sys.exc_info()

    stacktrace = self._construct_stacktrace(tb)
    traceback_text = self._format_lines(traceback.format_exception(ttype, tvalue, tb))

    return {"raw": traceback_text, "stacktrace": stacktrace, "process_id": j.application.process_id}
def handle_exception(self, exception: Exception, level: int = 40, die: bool = False, log: bool = True, category: str = '', data: dict = None)

Hndler exception

Arguments

exception {Exception} – the exception object to handle

Keyword Arguments: level {int} – exception level (default: {40}) die {bool} – optional flag to exit after handling the exception (default: {True}) log {bool} – option flag to log the exception (default: {True}) category {str} – category (default: {""})

Expand source code
def handle_exception(
    self,
    exception: Exception,
    level: int = 40,
    die: bool = False,
    log: bool = True,
    category: str = "",
    data: dict = None,
):
    """Hndler exception

    Arguments:
        exception {Exception} -- the exception object to handle

    Keyword Arguments:
        level {int} -- exception level (default: {40})
        die {bool} -- optional flag to exit after handling the exception (default: {True})
        log {bool} -- option flag to log the exception (default: {True})
        category {str} -- category (default: {""})
    """
    ttype, _, tb = sys.exc_info()
    self._handle_exception(ttype, exception, tb, die=die, log=log, category=category, data=data)
def register_handler(self, handler: , level: int = 40)

Register new error handler

Arguments

handler {callable} – error handler callable

Keyword Arguments: level {int} – exception level (default: {40})

Expand source code
def register_handler(self, handler: callable, level: int = 40):
    """Register new error handler

    Arguments:
        handler {callable} -- error handler callable

    Keyword Arguments:
        level {int} -- exception level (default: {40})
    """
    if (handler, level) not in self.handlers:
        self.handlers.append((handler, level))