Get exception description and stack trace which caused an exception, all as a string

前端 未结 11 1797
旧巷少年郎
旧巷少年郎 2020-11-30 16:22

I\'ve seen a lot of posts about stack trace and exceptions in Python. But haven\'t found what I need.

I have a chunk of Python 2.7 code that may raise an exception.

相关标签:
11条回答
  • 2020-11-30 16:46

    Let's create a decently complicated stacktrace, in order to demonstrate that we get the full stacktrace:

    def raise_error():
        raise RuntimeError('something bad happened!')
    
    def do_something_that_might_error():
        raise_error()
    

    Logging the full stacktrace

    A best practice is to have a logger set up for your module. It will know the name of the module and be able to change levels (among other attributes, such as handlers)

    import logging
    logging.basicConfig(level=logging.DEBUG)
    logger = logging.getLogger(__name__)
    

    And we can use this logger to get the error:

    try:
        do_something_that_might_error()
    except Exception as error:
        logger.exception(error)
    

    Which logs:

    ERROR:__main__:something bad happened!
    Traceback (most recent call last):
      File "<stdin>", line 2, in <module>
      File "<stdin>", line 2, in do_something_that_might_error
      File "<stdin>", line 2, in raise_error
    RuntimeError: something bad happened!
    

    And so we get the same output as when we have an error:

    >>> do_something_that_might_error()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 2, in do_something_that_might_error
      File "<stdin>", line 2, in raise_error
    RuntimeError: something bad happened!
    

    Getting just the string

    If you really just want the string, use the traceback.format_exc function instead, demonstrating logging the string here:

    import traceback
    try:
        do_something_that_might_error()
    except Exception as error:
        just_the_string = traceback.format_exc()
        logger.debug(just_the_string)
    

    Which logs:

    DEBUG:__main__:Traceback (most recent call last):
      File "<stdin>", line 2, in <module>
      File "<stdin>", line 2, in do_something_that_might_error
      File "<stdin>", line 2, in raise_error
    RuntimeError: something bad happened!
    
    0 讨论(0)
  • 2020-11-30 16:46

    I defined following helper class:

    import traceback
    class TracedExeptions(object):
        def __init__(self):
            pass
        def __enter__(self):
            pass
    
        def __exit__(self, etype, value, tb):
          if value :
            if not hasattr(value, 'traceString'):
              value.traceString = "\n".join(traceback.format_exception(etype, value, tb))
            return False
          return True
    

    Which I can later use like this:

    with TracedExeptions():
      #some-code-which-might-throw-any-exception
    

    And later can consume it like this:

    def log_err(ex):
      if hasattr(ex, 'traceString'):
        print("ERROR:{}".format(ex.traceString));
      else:
        print("ERROR:{}".format(ex));
    

    (Background: I was frustraded because of using Promises together with Exceptions, which unfortunately passes exceptions raised in one place to a on_rejected handler in another place, and thus it is difficult to get the traceback from original location)

    0 讨论(0)
  • 2020-11-30 16:53

    See the traceback module, specifically the format_exc() function. Here.

    import traceback
    
    try:
        raise ValueError
    except ValueError:
        tb = traceback.format_exc()
    else:
        tb = "No error"
    finally:
        print tb
    
    0 讨论(0)
  • 2020-11-30 16:54
    >>> import sys
    >>> import traceback
    >>> try:
    ...   5 / 0
    ... except ZeroDivisionError as e:
    ...   type_, value_, traceback_ = sys.exc_info()
    >>> traceback.format_tb(traceback_)
    ['  File "<stdin>", line 2, in <module>\n']
    >>> value_
    ZeroDivisionError('integer division or modulo by zero',)
    >>> type_
    <type 'exceptions.ZeroDivisionError'>
    >>>
    >>> 5 / 0
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ZeroDivisionError: integer division or modulo by zero
    

    You use sys.exc_info() to collect the information and the functions in the traceback module to format it. Here are some examples for formatting it.

    The whole exception string is at:

    >>> ex = traceback.format_exception(type_, value_, traceback_)
    >>> ex
    ['Traceback (most recent call last):\n', '  File "<stdin>", line 2, in <module>\n', 'ZeroDivisionError: integer division or modulo by zero\n']
    
    0 讨论(0)
  • 2020-11-30 16:57

    If you would like to get the same information given when an exception isn't handled you can do something like this. Do import traceback and then:

    try:
        ...
    except Exception as e:
        print(traceback.print_tb(e.__traceback__))
    

    I'm using Python 3.7.

    0 讨论(0)
提交回复
热议问题