अपवाद विवरण और स्टैक ट्रेस प्राप्त करें, जो एक अपवाद का कारण बनता है, सभी एक स्ट्रिंग के रूप में


423

मैंने पायथन में स्टैक ट्रेस और अपवादों के बारे में बहुत सारी पोस्ट देखी हैं। लेकिन मुझे जो चाहिए वो नहीं मिला।

मेरे पास पायथन 2.7 कोड का एक हिस्सा है जो एक अपवाद को बढ़ा सकता है। मैं इसे पकड़ना चाहता हूं और एक स्ट्रिंग को इसके पूर्ण विवरण और स्टैक ट्रेस को असाइन करता हूं जो त्रुटि का कारण बनता है (बस हम सभी कंसोल पर देखने के लिए उपयोग करते हैं)। मुझे इस स्ट्रिंग को GUI में एक टेक्स्ट बॉक्स पर प्रिंट करने की आवश्यकता है।

कुछ इस तरह:

try:
    method_that_can_raise_an_exception(params)
except Exception as e:
    print_to_textbox(complete_exception_description(e))

समस्या यह है: कार्य क्या है complete_exception_description?

जवाबों:


615

tracebackमॉड्यूल देखें , विशेष रूप से format_exc()फ़ंक्शन। यहाँ

import traceback

try:
    raise ValueError
except ValueError:
    tb = traceback.format_exc()
else:
    tb = "No error"
finally:
    print tb

2
क्या यह केवल अंतिम त्रुटि के साथ काम करता है? यदि आप कोड के अन्य बिट्स के आसपास त्रुटि पारित करना शुरू करते हैं तो क्या होगा? मैं एक log_error(err)फ़ंक्शन लिख रहा हूं ।
अन्नानफे

यह उस त्रुटि के साथ काम करता है जिसे पकड़ा और संभाला गया था।
किंडल

74

आइए हम एक पूरी तरह से जटिल स्टैकट्रेस बनाएं, ताकि यह प्रदर्शित हो सके कि हमें पूर्ण स्टैकट्रेस मिलती है:

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

def do_something_that_might_error():
    raise_error()

पूर्ण स्टैकट्रेस लॉगिंग

अपने मॉड्यूल के लिए एक लकड़हारा स्थापित करना सबसे अच्छा अभ्यास है। यह मॉड्यूल का नाम पता करेगा और स्तरों को बदलने में सक्षम होगा (अन्य विशेषताओं के बीच, जैसे हैंडलर)

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

और हम त्रुटि प्राप्त करने के लिए इस लकड़हारे का उपयोग कर सकते हैं:

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

कौन सा लॉग:

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!

और इसलिए जब हमें कोई त्रुटि होती है तो हमें वही आउटपुट मिलता है:

>>> 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!

सिर्फ स्ट्रिंग हो रही है

यदि आप वास्तव में सिर्फ स्ट्रिंग चाहते हैं, तो स्ट्रिंग को traceback.format_excलॉग करने का प्रदर्शन करते हुए, इसके बजाय फ़ंक्शन का उपयोग करें:

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

कौन सा लॉग:

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!

1
क्या पायथन 3 का उपयोग करते समय यह सबसे अच्छी विधि है (उदाहरण के लिए नीचे दिए गए कुछ उत्तरों की तुलना में)?
युनती

1
@Yunti मेरा मानना है कि इस एपीआई अजगर 2 और 3 पर एक जैसी कर दिया गया है
हारून हॉल

इस उत्तर के प्रारूपण पर मेटा: meta.stackoverflow.com/questions/386477/… पर चर्चा की गई ।
लुंडिन

मैंने निम्नलिखित को एक संपादन भेजा, लेकिन अनाम के रूप में प्रदर्शित होने में लॉग इन नहीं किया गया था: except Exception as e: logger.exception("<<clearly and distinctly describe what failed here>>", exc_info=e)
arntg

@arntg मैं सराहना करता हूं कि आप मदद करने की कोशिश कर रहे हैं, लेकिन वह संपादन एक हानिकारक बदलाव होगा। कृपया भविष्य में आपके द्वारा उपयोग किए जा रहे एपीआई को पूरी तरह से समझने के लिए अधिक सावधान रहें। इस मामले में, exc_infoतर्क एक "अपवाद टपल" की अपेक्षा करता है जबकि वस्तु (या उपवर्ग) errorका एक उदाहरण है Exception, और इसे बदलने की कोई आवश्यकता नहीं errorहै e
हारून हॉल

39

पायथन 3 के साथ, निम्नलिखित कोड एक Exceptionवस्तु को ठीक उसी तरह प्रारूपित करेगा जैसा कि प्रयोग करके प्राप्त किया जाएगा traceback.format_exc():

import traceback

try: 
    method_that_can_raise_an_exception(params)
except Exception as ex:
    print(''.join(traceback.format_exception(etype=type(ex), value=ex, tb=ex.__traceback__)))

लाभ यह है कि केवल Exceptionऑब्जेक्ट की आवश्यकता है (रिकॉर्ड की गई __traceback__विशेषता के लिए धन्यवाद ), और इसलिए आगे की प्रक्रिया के लिए एक और फ़ंक्शन के तर्क के रूप में अधिक आसानी से पारित किया जा सकता है।


1
यह sys.exc_info () से बेहतर है जो अच्छी OO शैली नहीं है और वैश्विक चर का उपयोग करती है।
वेईचिंग Wei 煒 C

यह विशेष रूप से पूछता है कि अपवाद वस्तु से ट्रेसबैक कैसे प्राप्त करें जैसा कि आपने यहां किया है: stackoverflow.com/questions/11414894/…
Ciro Santilli 郝海东 get get 事件 ''

बिना उपयोग किए बिना एक सरल Python3 तरीका है .__traceback__और type, stackoverflow.com/a/58764987/5717886
don_vanchos

34
>>> 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

मॉड्यूल में जानकारी और फ़ंक्शन को एकत्रित करने के लिए आप sys.exc_info () का उपयोग tracebackकरते हैं। इसे प्रारूपित करने के कुछ उदाहरण यहां दिए गए हैं।

संपूर्ण अपवाद स्ट्रिंग यहां है:

>>> 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']

9

पायथन -3 का उपयोग करने वालों के लिए

tracebackमॉड्यूल का उपयोग करना और exception.__traceback__एक स्टैक ट्रेस को निम्नानुसार निकाल सकते हैं:

  • वर्तमान स्टैक-ट्रेस का उपयोग करके पकड़ोtraceback.extract_stack()
  • पिछले तीन तत्वों को हटा दें (जैसा कि स्टैक में प्रविष्टियां हैं जो मुझे मेरे डिबग फ़ंक्शन में मिली हैं)
  • __traceback__का उपयोग कर अपवाद वस्तु से जोड़ेंtraceback.extract_tb()
  • पूरी चीज़ का उपयोग करके प्रारूपित करें traceback.format_list()
import traceback
def exception_to_string(excp):
   stack = traceback.extract_stack()[:-3] + traceback.extract_tb(excp.__traceback__)  # add limit=?? 
   pretty = traceback.format_list(stack)
   return ''.join(pretty) + '\n  {} {}'.format(excp.__class__,excp)

एक साधारण प्रदर्शन:

def foo():
    try:
        something_invalid()
    except Exception as e:
        print(exception_to_string(e))

def bar():
    return foo()

जब हम कॉल करते हैं तो हमें निम्न आउटपुट मिलते हैं bar():

  File "./test.py", line 57, in <module>
    bar()
  File "./test.py", line 55, in bar
    return foo()
  File "./test.py", line 50, in foo
    something_invalid()

  <class 'NameError'> name 'something_invalid' is not defined

यह एक अपठनीय जटिल कोड की तरह दिखता है। में अजगर 3.5+ एक और अधिक सुंदर और सरल तरीका है: stackoverflow.com/a/58764987/5717886
don_vanchos

6

तुम भी कुछ वास्तव में अच्छा, अच्छी तरह से स्वरूपित अपवाद जानकारी प्राप्त करने के लिए स्थानीय चर मान, स्रोत कोड संदर्भ, फ़ंक्शन मापदंडों आदि सहित प्राप्त करने के लिए अंतर्निहित पायथन मॉड्यूल, साइज़बट का उपयोग करने पर विचार कर सकते हैं ।

इस कोड के लिए उदाहरण के लिए ...

import cgitb
cgitb.enable(format='text')

def func2(a, divisor):
    return a / divisor

def func1(a, b):
    c = b - 5
    return func2(a, c)

func1(1, 5)

हम इस अपवाद उत्पादन मिलता है ...

ZeroDivisionError
Python 3.4.2: C:\tools\python\python.exe
Tue Sep 22 15:29:33 2015

A problem occurred in a Python script.  Here is the sequence of
function calls leading up to the error, in the order they occurred.

 c:\TEMP\cgittest2.py in <module>()
    7 def func1(a, b):
    8   c = b - 5
    9   return func2(a, c)
   10
   11 func1(1, 5)
func1 = <function func1>

 c:\TEMP\cgittest2.py in func1(a=1, b=5)
    7 def func1(a, b):
    8   c = b - 5
    9   return func2(a, c)
   10
   11 func1(1, 5)
global func2 = <function func2>
a = 1
c = 0

 c:\TEMP\cgittest2.py in func2(a=1, divisor=0)
    3
    4 def func2(a, divisor):
    5   return a / divisor
    6
    7 def func1(a, b):
a = 1
divisor = 0
ZeroDivisionError: division by zero
    __cause__ = None
    __class__ = <class 'ZeroDivisionError'>
    __context__ = None
    __delattr__ = <method-wrapper '__delattr__' of ZeroDivisionError object>
    __dict__ = {}
    __dir__ = <built-in method __dir__ of ZeroDivisionError object>
    __doc__ = 'Second argument to a division or modulo operation was zero.'
    __eq__ = <method-wrapper '__eq__' of ZeroDivisionError object>
    __format__ = <built-in method __format__ of ZeroDivisionError object>
    __ge__ = <method-wrapper '__ge__' of ZeroDivisionError object>
    __getattribute__ = <method-wrapper '__getattribute__' of ZeroDivisionError object>
    __gt__ = <method-wrapper '__gt__' of ZeroDivisionError object>
    __hash__ = <method-wrapper '__hash__' of ZeroDivisionError object>
    __init__ = <method-wrapper '__init__' of ZeroDivisionError object>
    __le__ = <method-wrapper '__le__' of ZeroDivisionError object>
    __lt__ = <method-wrapper '__lt__' of ZeroDivisionError object>
    __ne__ = <method-wrapper '__ne__' of ZeroDivisionError object>
    __new__ = <built-in method __new__ of type object>
    __reduce__ = <built-in method __reduce__ of ZeroDivisionError object>
    __reduce_ex__ = <built-in method __reduce_ex__ of ZeroDivisionError object>
    __repr__ = <method-wrapper '__repr__' of ZeroDivisionError object>
    __setattr__ = <method-wrapper '__setattr__' of ZeroDivisionError object>
    __setstate__ = <built-in method __setstate__ of ZeroDivisionError object>
    __sizeof__ = <built-in method __sizeof__ of ZeroDivisionError object>
    __str__ = <method-wrapper '__str__' of ZeroDivisionError object>
    __subclasshook__ = <built-in method __subclasshook__ of type object>
    __suppress_context__ = False
    __traceback__ = <traceback object>
    args = ('division by zero',)
    with_traceback = <built-in method with_traceback of ZeroDivisionError object>

The above is a description of an error in a Python program.  Here is
the original traceback:

Traceback (most recent call last):
  File "cgittest2.py", line 11, in <module>
    func1(1, 5)
  File "cgittest2.py", line 9, in func1
    return func2(a, c)
  File "cgittest2.py", line 5, in func2
    return a / divisor
ZeroDivisionError: division by zero

5

यदि आप एक ही जानकारी प्राप्त करना चाहते हैं जब एक अपवाद को नियंत्रित नहीं किया जाता है तो आप ऐसा कुछ कर सकते हैं। करो import tracebackऔर फिर:

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

मैं पायथन 3.7 का उपयोग कर रहा हूं।


3

के लिये अजगर 3.5+ :

तो, आप स्टैकट्रेस को अपने अपवाद से किसी अन्य अपवाद के रूप में प्राप्त कर सकते हैं। traceback.TracebackExceptionइसके लिए उपयोग करें (बस बदलेंex अपने अपवाद के साथ ):

print("".join(traceback.TracebackException.from_exception(ex).format())

ऐसा करने के लिए एक विस्तारित उदाहरण और अन्य विशेषताएं:

import traceback

try:
    1/0
except Exception as ex:
    print("".join(traceback.TracebackException.from_exception(ex).format()) == traceback.format_exc() == "".join(traceback.format_exception(type(ex), ex, ex.__traceback__))) # This is True !!
    print("".join(traceback.TracebackException.from_exception(ex).format()))

आउटपुट कुछ इस तरह होगा:

True
Traceback (most recent call last):
  File "untidsfsdfsdftled.py", line 29, in <module>
    1/0
ZeroDivisionError: division by zero


1

यदि आपका लक्ष्य अपवाद और स्टैकट्रेस संदेश को ठीक वैसा ही बनाना है, जब अजगर एक त्रुटि फेंकता है, तो निम्न दोनों अजगर 2 + 3 में काम करता है:

import sys, traceback


def format_stacktrace():
    parts = ["Traceback (most recent call last):\n"]
    parts.extend(traceback.format_stack(limit=25)[:-2])
    parts.extend(traceback.format_exception(*sys.exc_info())[1:])
    return "".join(parts)

# EXAMPLE BELOW...

def a():
    b()


def b():
    c()


def c():
    d()


def d():
    assert False, "Noooh don't do it."


print("THIS IS THE FORMATTED STRING")
print("============================\n")

try:
    a()
except:
    stacktrace = format_stacktrace()
    print(stacktrace)

print("THIS IS HOW PYTHON DOES IT")
print("==========================\n")
a()

यह format_stacktrace()स्टैक से अंतिम कॉल को हटाने और बाकी में शामिल होने से काम करता है । जब चलाया जाता है, तो ऊपर दिया गया उदाहरण निम्नलिखित आउटपुट देता है:

THIS IS THE FORMATTED STRING
============================

Traceback (most recent call last):
  File "test.py", line 31, in <module>
    a()
  File "test.py", line 12, in a
    b()
  File "test.py", line 16, in b
    c()
  File "test.py", line 20, in c
    d()
  File "test.py", line 24, in d
    assert False, "Noooh don't do it."
AssertionError: Noooh don't do it.

THIS IS HOW PYTHON DOES IT
==========================

Traceback (most recent call last):
  File "test.py", line 38, in <module>
    a()
  File "test.py", line 12, in a
    b()
  File "test.py", line 16, in b
    c()
  File "test.py", line 20, in c
    d()
  File "test.py", line 24, in d
    assert False, "Noooh don't do it."
AssertionError: Noooh don't do it.

0

मैंने निम्न सहायक वर्ग को परिभाषित किया:

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

जिसे मैं बाद में इस तरह से उपयोग कर सकता हूं:

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

और बाद में इस तरह से इसका सेवन कर सकते हैं:

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

(पृष्ठभूमि: मैं Promises के साथ s का उपयोग करने के कारण निराश था Exception, जो दुर्भाग्य से अपवादों को एक जगह से उठाकर दूसरी जगह पर on_rejected हैंडलर को पार कर जाता है, और इस प्रकार मूल स्थान से ट्रेसबैक प्राप्त करना मुश्किल है)

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.