कार्यक्रम को रोकने के बिना पूर्ण ट्रेसबैक कैसे प्रिंट करें?


777

मैं एक प्रोग्राम लिख रहा हूं जो 10 वेबसाइटों को पार्स करता है, डेटा फ़ाइलों का पता लगाता है, फ़ाइलों को सहेजता है, और फिर उन्हें डेटा बनाने के लिए पार्स करता है जो आसानी से NumPy लाइब्रेरी में उपयोग किया जा सकता है। कर रहे हैं टन बुरा लिंक, खराब गठित XML, लापता प्रविष्टियों, और अन्य चीजें मैं अभी तक वर्गीकृत करने के लिए है के माध्यम से इस फाइल मुठभेड़ों त्रुटियों की। मैंने शुरू में इस तरह की त्रुटियों को संभालने के लिए यह कार्यक्रम बनाया था:

try:
    do_stuff()
except:
    pass

लेकिन अब मैं त्रुटियों को लॉग इन करना चाहता हूं:

try:
    do_stuff()
except Exception, err:
    print Exception, err

ध्यान दें कि यह बाद की समीक्षा के लिए एक लॉग फ़ाइल में मुद्रण कर रहा है। यह आमतौर पर बहुत बेकार डेटा प्रिंट करता है। जब मैं चाहता हूं कि प्रिंट की गई समान पंक्तियों को प्रिंट किया जाए, जब त्रुटि बिना ट्रिगर के प्रयास को छोड़कर अपवाद को रोकती है, लेकिन मैं अपने कार्यक्रम को रोकना नहीं चाहता क्योंकि यह छोरों की एक श्रृंखला में नेस्टेड है जिसे मैं पसंद करूंगा पूरा करने के लिए देखें।

जवाबों:


579

कुछ अन्य उत्तर ट्रेसबैक मॉड्यूल को पहले ही बता चुके हैं

कृपया ध्यान दें कि print_excकुछ कोने के मामलों में, आप वह नहीं प्राप्त करेंगे जो आप उम्मीद करेंगे। पायथन में 2.x:

import traceback

try:
    raise TypeError("Oups!")
except Exception, err:
    try:
        raise TypeError("Again !?!")
    except:
        pass

    traceback.print_exc()

... अंतिम अपवाद का ट्रेसबैक प्रदर्शित करेगा :

Traceback (most recent call last):
  File "e.py", line 7, in <module>
    raise TypeError("Again !?!")
TypeError: Again !?!

यदि आपको वास्तव में मूल ट्रेसबैक का उपयोग करने की आवश्यकता है, तो एक समाधान एक स्थानीय चर में से लौटाए गए इन्फोस को कैश करने के लिए हैexc_info और इसका उपयोग करके प्रदर्शित करें print_exception:

import traceback
import sys

try:
    raise TypeError("Oups!")
except Exception, err:
    try:
        exc_info = sys.exc_info()

        # do you usefull stuff here
        # (potentially raising an exception)
        try:
            raise TypeError("Again !?!")
        except:
            pass
        # end of useful stuff


    finally:
        # Display the *original* exception
        traceback.print_exception(*exc_info)
        del exc_info

उत्पादन:

Traceback (most recent call last):
  File "t.py", line 6, in <module>
    raise TypeError("Oups!")
TypeError: Oups!

हालांकि इसके साथ कुछ नुकसान:

  • के डॉक्टर से sys_info:

    ट्रेसबैक रिटर्न मान को एक समारोह में एक स्थानीय चर में निर्दिष्ट करना जो एक अपवाद को संभाल रहा है, एक परिपत्र संदर्भ का कारण होगा । यह एक स्थानीय फ़ंक्शन द्वारा संदर्भित किसी भी चीज को एक ही फ़ंक्शन में या ट्रेसबैक द्वारा एकत्र किए जाने वाले कचरे को एकत्र करने से रोक देगा। [...] यदि आपको ट्रेसबैक की आवश्यकता है, तो उपयोग के बाद इसे हटाना सुनिश्चित करें (सबसे अच्छा एक प्रयास के साथ ... अंत में बयान)

  • लेकिन, उसी डॉक्टर से:

    पायथन 2.2 के साथ शुरुआत करते हुए, ऐसे चक्रों को स्वचालित रूप से पुनः प्राप्त किया जाता है जब कचरा संग्रह सक्षम होता है और वे पहुंच से बाहर हो जाते हैं, लेकिन चक्र बनाने से बचने के लिए यह अधिक कुशल रहता है।


दूसरी ओर, आपको अपवाद के साथ जुड़े ट्रेसबैक तक पहुंचने की अनुमति देकर , पायथन 3 एक कम आश्चर्यजनक परिणाम उत्पन्न करता है:

import traceback

try:
    raise TypeError("Oups!")
except Exception as err:
    try:
        raise TypeError("Again !?!")
    except:
        pass

    traceback.print_tb(err.__traceback__)

... प्रदर्शित होगा:

  File "e3.py", line 4, in <module>
    raise TypeError("Oups!")

707

traceback.format_exc()या sys.exc_info()यदि आप चाहते हैं तो अधिक जानकारी प्राप्त होगी।

import traceback
import sys

try:
    do_stuff()
except Exception:
    print(traceback.format_exc())
    # or
    print(sys.exc_info()[2])

1
print(sys.exc_info()[0]प्रिंट करता है <class 'Exception'>
weberc2

2
exc का उपयोग न करें ... ट्रेसबैक में सभी जानकारी stackoverflow.com/questions/4564559/… शामिल हैं
qrtLs

258

यदि आप डिबगिंग कर रहे हैं और केवल वर्तमान स्टैक ट्रेस देखना चाहते हैं, तो आप बस कॉल कर सकते हैं:

traceback.print_stack()

इसे फिर से पकड़ने के लिए मैन्युअल रूप से अपवाद को बढ़ाने की कोई आवश्यकता नहीं है।


9
ट्रेसबैक मॉड्यूल ठीक यही करता है - एक अपवाद को बढ़ाएं और पकड़ें।
19

3
आउटपुट डिफ़ॉल्ट BTW द्वारा STDERR को जाता है। मेरे लॉग में दिखाई नहीं दे रहा था क्योंकि इसे कहीं और रीडायरेक्ट किया जा रहा था।
एमपीएन

101

कार्यक्रम को रोकने के बिना पूर्ण ट्रेसबैक कैसे प्रिंट करें?

जब आप किसी त्रुटि पर अपने कार्यक्रम को रोकना नहीं चाहते हैं, तो आपको उस त्रुटि को एक कोशिश / छोड़कर संभालना होगा:

try:
    do_something_that_might_error()
except Exception as error:
    handle_the_error(error)

पूर्ण ट्रेसबैक निकालने के लिए, हम tracebackमानक पुस्तकालय से मॉड्यूल का उपयोग करेंगे :

import traceback

और यह दिखाने के लिए कि हम पूर्ण स्टैकट्रेस प्राप्त करते हैं, एक जटिल जटिल स्टैट्रेस बनाने के लिए:

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

def do_something_that_might_error():
    raise_error()

मुद्रण

पूर्ण ट्रेसबैक प्रिंट करने के लिए, traceback.print_excविधि का उपयोग करें :

try:
    do_something_that_might_error()
except Exception as error:
    traceback.print_exc()

कौन सा प्रिंट:

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!

मुद्रण से बेहतर, लॉगिंग:

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

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

किस मामले में, आप logger.exceptionइसके बजाय फ़ंक्शन चाहते हैं :

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!

या शायद आप सिर्फ स्ट्रिंग चाहते हैं, जिस स्थिति में, आप traceback.format_excइसके बजाय फ़ंक्शन चाहते हैं :

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

कौन सा लॉग:

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!

निष्कर्ष

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

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

2
जैसा कि ऊपर और मेरे लिए भी कहा गया है, traceback.print_exc()केवल अंतिम कॉल लौटाता है: आप स्टैक के कई स्तर (और संभवतः सभी लेवेले एस?) को वापस करने में कैसे सफल होते हैं
हर्वे-गुएरिन

@geekobi मुझे यकीन नहीं है कि आप यहाँ क्या पूछ रहे हैं। मैं प्रदर्शित करता हूं कि हमें कार्यक्रम / दुभाषिया के प्रवेश बिंदु तक ट्रेसबैक मिलता है। आप किस पर स्पष्ट नहीं हैं?
हारून हॉल

1
@Geekobi क्या कह रहा है यदि आप पकड़ते हैं और फिर से उठाते हैं, तो ट्रेसबैक.प्रिंट_exc () सिर्फ री-स्टैक स्टैक लौटाएगा, मूल स्टैक नहीं।
fizloki

@fizloki आप कैसे "शेखीबाज़ी" कर रहे हैं? क्या आप एक नंगे raiseया अपवाद का पीछा कर रहे हैं, या आप मूल ट्रेसबैक छिपा रहे हैं? देख stackoverflow.com/questions/2052390/...
हारून हॉल

21

सबसे पहले, printलॉगिंग के लिए एस का उपयोग न करें, ऐसा करने के लिए आश्चर्यजनक, सिद्ध और सुविचारित stdlib मॉड्यूल है logging:। आपको निश्चित रूप से इसके बजाय इसका उपयोग करना चाहिए

मूल और सरल दृष्टिकोण होने पर, असंबंधित उपकरणों के साथ एक गड़बड़ करने के लिए प्रलोभन न करें । यह रहा:

log = logging.getLogger(__name__)

try:
    call_code_that_fails()
except MyError:
    log.exception('Any extra info you want to see in your logs')

बस। अब तुम हो गए।

कोई भी व्यक्ति जो हुड के नीचे काम करता है में रुचि रखता है के लिए स्पष्टीकरण

log.exceptionवास्तव में क्या कर रहा है log.error(तो, स्तर के साथ लॉग घटना ERROR) और फिर ट्रेसबैक प्रिंट करने के लिए एक कॉल है ।

यह बेहतर क्यों है?

खैर, यहाँ कुछ विचार है:

  • यह सही है ;
  • यह सीधा है;
  • यह आसान है।

किसी को भी लकड़हारे का उपयोग tracebackया कॉल नहीं करना चाहिए exc_info=Trueया उसके साथ अपने हाथों को गंदा नहीं करना चाहिए sys.exc_info?

खैर, सिर्फ इसलिए! वे सभी विभिन्न उद्देश्यों के लिए मौजूद हैं। उदाहरण के लिए, traceback.print_excदुभाषिया द्वारा उत्पादित ट्रेसबैक से थोड़ा अलग है। यदि आप इसका उपयोग करते हैं, तो आप किसी को भी भ्रमित करेंगे जो आपके लॉग पढ़ता है, वे उनके खिलाफ अपने सिर को पीटेंगे।

पासिंग exc_info=Trueकॉल लॉग इन करने की सिर्फ अनुचित है। लेकिन , वसूली योग्य त्रुटियों को पकड़ते समय यह उपयोगी है और आप उन्हें INFOट्रेसबैक के साथ ( साथ ही, उदाहरण के लिए ) का उपयोग करके लॉग इन करना चाहते हैं , क्योंकि log.exceptionकेवल एक स्तर के लॉग का उत्पादन होता है - ERROR

और आपको निश्चित sys.exc_infoरूप से जितना हो सके उतना खिलवाड़ करने से बचना चाहिए । यह सिर्फ एक सार्वजनिक इंटरफ़ेस नहीं है, यह एक आंतरिक है - आप इसका उपयोग कर सकते हैं यदि आप निश्चित रूप से जानते हैं कि आप क्या कर रहे हैं। यह सिर्फ मुद्रण अपवादों के लिए अभिप्रेत नहीं है।


4
यह भी काम नहीं करता है। यह वह नहीं है। मैं अभी नहीं कर रहा हूँ: यह जवाब सिर्फ समय बर्बाद करता है।
ए। रैगर

मैं यह भी जोड़ूंगा कि आप बस कर सकते हैं logging.exception()। जब तक आपको विशेष आवश्यकता न हो, लॉग की आवृत्ति बनाने की आवश्यकता नहीं है।
शीतल शाह

9

यदि आप लॉगिंग कर रहे हैं, तो @Aaron हॉल के उत्तर के अलावा, लेकिन इसका उपयोग नहीं करना चाहते logging.exception()(चूंकि यह ERROR स्तर पर लॉग होता है), आप निम्न स्तर और पास का उपयोग कर सकते हैं exc_info=True। जैसे

try:
    do_something_that_might_error()
except Exception:
    logger.info('General exception noted.', exc_info=True)

7

सटीक स्टैक ट्रेस प्राप्त करने के लिए , एक स्ट्रिंग के रूप में, जो उठाया जाता अगर कोई प्रयास नहीं होता है / इसके अलावा उस पर कदम रखने के लिए, बस इसे अपवाद ब्लॉक में रखें जो आपत्तिजनक अपवाद को पकड़ता है।

desired_trace = traceback.format_exc(sys.exc_info())

इसका उपयोग कैसे करें (यह flaky_funcपरिभाषित किया गया है, और logअपने पसंदीदा लॉगिंग सिस्टम को कॉल करें):

import traceback
import sys

try:
    flaky_func()
except KeyboardInterrupt:
    raise
except Exception:
    desired_trace = traceback.format_exc(sys.exc_info())
    log(desired_trace)

एस को पकड़ना और फिर से उठाना एक अच्छा विचार है KeyboardInterrupt, ताकि आप अभी भी Ctrl-C का उपयोग करके प्रोग्राम को मार सकें। लॉगिंग प्रश्न के दायरे से बाहर है, लेकिन एक अच्छा विकल्प लॉगिंग हैSys और ट्रेसबैक मॉड्यूल के लिए प्रलेखन ।


4
यह पायथन 3 में काम नहीं करता है और इसे बदलने की आवश्यकता है desired_trace = traceback.format_exc()। पासिंग sys.exc_info()तर्क के रूप में करने के लिए सही बात कभी नहीं था, लेकिन चुपचाप (वैसे भी 3.6.4)-लेकिन 2 अजगर 3 में नहीं पायथन में नजरअंदाज कर दिया जाता है।
मार्टिउ

2
KeyboardInterrupt(प्रत्यक्ष या अप्रत्यक्ष रूप से) व्युत्पन्न नहीं है Exception। (दोनों से व्युत्पन्न हैं BaseException।) इसका मतलब except Exception:कभी भी पकड़ नहीं होगा KeyboardInterrupt, और इस except KeyboardInterrupt: raiseतरह पूरी तरह से अनावश्यक है।
AJNeufeld

traceback.format_exc(sys.exc_info())अजगर के साथ मेरे लिए काम नहीं कर रहा है 3.6.10
नाम जी वीयू

6

आपको सबसे अधिक इनरलूप के अंदर प्रयास को छोड़ना होगा / जहां त्रुटि हो सकती है, अर्थात

for i in something:
    for j in somethingelse:
        for k in whatever:
            try:
                something_complex(i, j, k)
            except Exception, e:
                print e
        try:
            something_less_complex(i, j)
        except Exception, e:
            print e

... और इसी तरह

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


6

इस जवाब के बारे में एक टिप्पणी : print(traceback.format_exc())मेरे लिए एक बेहतर काम करता है traceback.print_exc()। उत्तरार्द्ध के helloसाथ, ट्रेसबैक टेक्स्ट के साथ कभी-कभी अजीब तरह से "मिश्रित" किया जाता है, जैसे कि यदि दोनों एक ही समय में स्टडआउट या स्टेडर को लिखना चाहते हैं, तो अजीब आउटपुट का उत्पादन करते हैं (कम से कम जब एक टेक्स्ट एडिटर के अंदर से निर्माण करते हैं और आउटपुट को देखते हैं "बिल्ड रिजल्ट्स" पैनल)।

ट्रेसबैक (सबसे हालिया कॉल अंतिम):
फ़ाइल "C: \ Users \ User \ Desktop \ test.py", पंक्ति 7,
नरक में do_stuff ()
फ़ाइल "C: \ Users \ User \ Desktop \ test.py", पंक्ति 4 , do_stuff में
1/0
ZeroDivisionError: पूर्णांक विभाजन या शून्य से सापेक्ष

[0.1s में समाप्त]

इसलिए मैं उपयोग करता हूं:

import traceback, sys

def do_stuff():
    1/0

try:
    do_stuff()
except Exception:
    print(traceback.format_exc())
    print('hello')

5

मैं किसी भी अन्य उत्तर में इसका उल्लेख नहीं देखता हूं। यदि आप किसी भी कारण से अपवाद वस्तु के आसपास से गुजर रहे हैं ...

पायथन 3.5+ में आप ट्रेसबैक.ग्रेसबैकएक्स अपवाद .from_exception () का उपयोग करके अपवाद वस्तु से एक ट्रेस प्राप्त कर सकते हैं । उदाहरण के लिए:

import traceback


def stack_lvl_3():
    raise Exception('a1', 'b2', 'c3')


def stack_lvl_2():
    try:
        stack_lvl_3()
    except Exception as e:
        # raise
        return e


def stack_lvl_1():
    e = stack_lvl_2()
    return e

e = stack_lvl_1()

tb1 = traceback.TracebackException.from_exception(e)
print(''.join(tb1.format()))

हालाँकि, उपरोक्त कोड में परिणाम है:

Traceback (most recent call last):
  File "exc.py", line 10, in stack_lvl_2
    stack_lvl_3()
  File "exc.py", line 5, in stack_lvl_3
    raise Exception('a1', 'b2', 'c3')
Exception: ('a1', 'b2', 'c3')

यह स्टैक का केवल दो स्तर है, जैसा कि स्क्रीन पर मुद्रित किया गया था, इसका विरोध किया गया था stack_lvl_2()और इसमें अवरोध नहीं उठाया गया था (असहजता# raise लाइन को )।

जैसा कि मैंने इसे समझा, ऐसा इसलिए है क्योंकि एक अपवाद केवल स्टैक के वर्तमान स्तर को रिकॉर्ड करता है जब इसे उठाया जाता है, stack_lvl_3() इस मामले में । जैसा कि यह स्टैक के माध्यम से वापस पारित हो गया है, इसके और अधिक स्तर जोड़े जा रहे हैं __traceback__। लेकिन हमने इसे इंटरसेप्ट किया stack_lvl_2(), जिसका अर्थ है कि यह सब रिकॉर्ड करने के लिए स्तर 3 और 2 था। पूरा पता लगाने के लिए जैसा कि स्टडआउट पर छपा हुआ है, हमें इसे उच्चतम (सबसे कम?) स्तर पर पकड़ना होगा:

import traceback


def stack_lvl_3():
    raise Exception('a1', 'b2', 'c3')


def stack_lvl_2():
    stack_lvl_3()


def stack_lvl_1():
    stack_lvl_2()


try:
    stack_lvl_1()
except Exception as exc:
    tb = traceback.TracebackException.from_exception(exc)

print('Handled at stack lvl 0')
print(''.join(tb.stack.format()))

जिसके परिणामस्वरूप:

Handled at stack lvl 0
  File "exc.py", line 17, in <module>
    stack_lvl_1()
  File "exc.py", line 13, in stack_lvl_1
    stack_lvl_2()
  File "exc.py", line 9, in stack_lvl_2
    stack_lvl_3()
  File "exc.py", line 5, in stack_lvl_3
    raise Exception('a1', 'b2', 'c3')

ध्यान दें कि स्टैक प्रिंट अलग है, पहली और आखिरी लाइनें गायब हैं। क्योंकि यह ए अलग हैformat()

उस बिंदु से दूर अपवाद को रोकना जहां यह संभव के रूप में उठाया गया था और अधिक जानकारी देते हुए सरल कोड के लिए बनाता है।


यह पिछली विधि (यों) की तुलना में बहुत बेहतर है, लेकिन अभी भी हास्यास्पद रूप से केवल एक स्टैकट्रेस को प्रिंट करने के लिए जटिल है। Java कम FGS कोड लेता है।
elhefe

3

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


3

अपवाद ऑब्जेक्ट से स्ट्रिंग के रूप में पूर्ण ट्रेसबैक प्राप्त करें traceback.format_exception

यदि आपके पास केवल अपवाद वस्तु है, तो आप पायथन 3 में कोड के किसी भी बिंदु से स्ट्रिंग के रूप में ट्रेसबैक प्राप्त कर सकते हैं:

import traceback

''.join(traceback.format_exception(None, exc_obj, exc_obj.__traceback__))

पूर्ण उदाहरण:

#!/usr/bin/env python3

import traceback

def f():
    g()

def g():
    raise Exception('asdf')

try:
    g()
except Exception as e:
    exc = e

tb_str = ''.join(traceback.format_exception(None, exc_obj, exc_obj.__traceback__))
print(tb_str)

आउटपुट:

Traceback (most recent call last):
  File "./main.py", line 12, in <module>
    g()
  File "./main.py", line 9, in g
    raise Exception('asdf')
Exception: asdf

प्रलेखन: https://docs.python.org/3.7/library/traceback.html#traceback.format_exception

इसे भी देखें: एक अपवाद ऑब्जेक्ट से ट्रेसबैक जानकारी निकालें

पायथन 3.7.3 में परीक्षण किया गया।


2

यदि आपके पास पहले से कोई त्रुटि वस्तु है, और आप पूरी बात प्रिंट करना चाहते हैं, तो आपको यह थोड़ा अजीब कॉल करने की आवश्यकता है:

import traceback
traceback.print_exception(type(err), err, err.__traceback__)

यह सही है, तीनprint_exception लेता है स्थैतिक तर्क है: अपवाद का प्रकार, वास्तविक अपवाद वस्तु, और अपवाद का अपना आंतरिक ट्रेसबैक गुण।

अजगर 3.5 में या बाद में, type(err)वैकल्पिक है ... लेकिन यह एक तर्कपूर्ण तर्क है, इसलिए आपको अभी भी इसके स्थान पर कोई भी स्पष्ट रूप से पारित नहीं करना है।

traceback.print_exception(None, err, err.__traceback__)

मुझे पता नहीं क्यों यह सब सिर्फ नहीं है traceback.print_exception(err)। आप कभी भी एक त्रुटि का प्रिंट आउट क्यों लेना चाहेंगे, एक ट्रेसबैक के अलावा जो उस त्रुटि से संबंधित है, वह मेरे से परे है।

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