पायथन में अपवाद नहीं छोड़ना


181

आप loggingमॉड्यूल के बजाय आउटपुट के लिए अनकैप्ड अपवाद का कारण कैसे बनते हैं stderr?

मुझे यह करने का सबसे अच्छा तरीका है:

try:
    raise Exception, 'Throwing a boring exception'
except Exception, e:
    logging.exception(e)

लेकिन मेरी स्थिति ऐसी है कि जब भी कोई अपवाद नहीं पकड़ा जाता है तो यह अपने आप लागू हो जाता है तो यह वास्तव में अच्छा होगा logging.exception(...)



जवाबों:


143

जैसा कि नेड ने बताया है, sys.excepthookहर बार एक अपवाद को उठाया जाता है और अनकहा किया जाता है। इसका व्यावहारिक निहितार्थ यह है कि आपके कोड में आप sys.excepthookजो कुछ भी चाहते हैं उसे करने के लिए डिफ़ॉल्ट व्यवहार को ओवरराइड कर सकते हैं (उपयोग करने सहित logging.exception)।

पुआल आदमी उदाहरण के रूप में:

>>> import sys
>>> def foo(exctype, value, tb):
...     print 'My Error Information'
...     print 'Type:', exctype
...     print 'Value:', value
...     print 'Traceback:', tb
... 

ओवरराइड sys.excepthook:

>>> sys.excepthook = foo

स्पष्ट वाक्यविन्यास त्रुटि (बृहदान्त्र को छोड़ दें) और कस्टम त्रुटि जानकारी प्राप्त करें:

>>> def bar(a, b)
My Error Information
Type: <type 'exceptions.SyntaxError'>
Value: invalid syntax (<stdin>, line 1)
Traceback: None

डॉक्स के बारे में अधिक जानकारी के लिए sys.excepthook, पढ़ें ।


4
@Codemonkey यह एक आरक्षित खोजशब्द नहीं है, यह एक पूर्ववर्ती प्रकार का नाम है। आप typeएक फ़ंक्शन तर्क के रूप में उपयोग कर सकते हैं , हालांकि आईडीई वैश्विक छिपाने के बारे में शिकायत करेगा type(जैसा var self = thisकि जावास्क्रिप्ट में उपयोग करना पसंद है)। जब तक आपको typeअपने फ़ंक्शन के अंदर ऑब्जेक्ट तक पहुंचने की आवश्यकता नहीं है, तब तक कोई फर्क नहीं पड़ता , जिस स्थिति में आप type_इसके बजाय तर्क के रूप में उपयोग कर सकते हैं ।
रयान पी

3
वाक्यांश "हर बार" यहां भ्रामक है: "sys.excepthook को हर बार एक अपवाद के रूप में उठाया और अनकहाया गया है" ... क्योंकि एक कार्यक्रम में, वास्तव में एक "अनकहा" अपवाद हो सकता है । इसके अलावा, sys.excepthookयह नहीं कहा जाता है जब एक अपवाद "उठाया" है। इसे तब कहा जाता है जब एक अनकहा अपवाद के कारण कार्यक्रम समाप्त होने जा रहा है, जो एक से अधिक बार नहीं हो सकता है।
नवाज

2
@Nawaz: यह एक आरईपीएल में एक बार से अधिक हो सकता है
JFS

2
@ नवाज़ कई बार ऐसा भी हो सकता है अगर प्रोग्राम थ्रेड्स का उपयोग कर रहा है। मुझे भी लगता है कि GUI इवेंट लूप्स (जैसे क्यूटी) चलते रहते हैं, भले ही अपवाद ने इसे sys.excepthook पर बना दिया हो
three_pineapples

1
कोई भी उपरोक्त कोड का परीक्षण करने की कोशिश कर रहा है, सुनिश्चित करें कि आप अपने फ़ंक्शन का परीक्षण करते समय एक ट्रेसबैक त्रुटि उत्पन्न करते हैं। SyntaxError को sys.excepthook द्वारा नियंत्रित नहीं किया जा रहा है। आप प्रिंट (1/0) का उपयोग कर सकते हैं और यह आपके द्वारा sys.excepthook
Parth Karia

177

यहाँ एक छोटा सा उदाहरण है जिसमें कुछ अन्य चालें भी शामिल हैं:

import sys
import logging
logger = logging.getLogger(__name__)
handler = logging.StreamHandler(stream=sys.stdout)
logger.addHandler(handler)

def handle_exception(exc_type, exc_value, exc_traceback):
    if issubclass(exc_type, KeyboardInterrupt):
        sys.__excepthook__(exc_type, exc_value, exc_traceback)
        return

    logger.error("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback))

sys.excepthook = handle_exception

if __name__ == "__main__":
    raise RuntimeError("Test unhandled")
  • KeyboardInterrupt को अनदेखा करें ताकि एक कंसोल अजगर प्रोग्राम Ctrl + C के साथ बाहर निकल सके।

  • पूरी तरह से अपवाद स्वरूपण के लिए अजगर के लॉगिंग मॉड्यूल पर पूरी तरह से।

  • उदाहरण हैंडलर के साथ एक कस्टम लॉगर का उपयोग करें। यह एक stderr के बजाय stdout में जाने के लिए बिना किसी अपवाद के अपवाद को बदलता है, लेकिन आप लकड़हारे ऑब्जेक्ट के लिए इस शैली में सभी प्रकार के हैंडलर जोड़ सकते हैं।


13
मैं logger.critical()excepthook हैंडलर के अंदर का उपयोग करेंगे , क्योंकि एक अनकहा अपवाद बहुत महत्वपूर्ण है जो मैं कहूंगा।
गीताकार

2
यह सबसे व्यावहारिक उत्तर IMO है।
डेविड मोरालेस

स्निपेट के लिए @gnu_lorien धन्यवाद। आप इसे किस फ़ाइल में डालेंगे?
स्टेलियोस

@chefarov मुख्य फ़ाइल जहां आप अन्य सभी लॉगिंग को आरंभ करते हैं
gnu_lorien

नमस्ते, हम इस जानकारी को डिबग की तरह फाइल करने के लिए कैसे लिख सकते हैं। मैं इसे लाइन जोड़ने की कोशिश करता हूं, logging.basicConfig(level=logging.DEBUG, filename="debug.log", format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')लेकिन मदद नहीं की।
गुरुचनगिन

26

sys.excepthookयदि कोई अपवाद छोड़ा गया है, तो विधि को आमंत्रित किया जाएगा: http://docs.python.org/library/sys.html#sys.excepthook

जब एक अपवाद को उठाया जाता है और अप्रकाशित किया जाता है, तो दुभाषिया sys.excepthook को तीन तर्कों, अपवाद वर्ग, अपवाद उदाहरण और ट्रेसबैक ऑब्जेक्ट के साथ कॉल करता है। एक संवादात्मक सत्र में नियंत्रण पर वापस लौटने से ठीक पहले ऐसा होता है; पायथन कार्यक्रम में यह कार्यक्रम से बाहर निकलने से ठीक पहले होता है। ऐसे शीर्ष-स्तरीय अपवादों की हैंडलिंग को sys.excepthook को तीन-तर्क फ़ंक्शन प्रदान करके अनुकूलित किया जा सकता है।


2
यह अपवाद वर्ग को क्यों भेजता है? क्या आप हमेशा typeउदाहरण पर कॉल करके नहीं मिल सकते हैं ?
नील जी

के मापदंडों का प्रकार क्या है sys.excepthook?
मार्टिन थोमा

23

क्यों नहीं:

import sys
import logging
import traceback

def log_except_hook(*exc_info):
    text = "".join(traceback.format_exception(*exc_info))
    logging.error("Unhandled exception: %s", text)

sys.excepthook = log_except_hook

None()

यहाँ जैसा कि sys.excepthookऊपर देखा गया है, इसका आउटपुट है:

$ python tb.py
ERROR:root:Unhandled exception: Traceback (most recent call last):
  File "tb.py", line 11, in <module>
    None()
TypeError: 'NoneType' object is not callable

यहाँ sys.excepthookटिप्पणी के साथ आउटपुट है:

$ python tb.py
Traceback (most recent call last):
  File "tb.py", line 11, in <module>
    None()
TypeError: 'NoneType' object is not callable

अंतर केवल इतना है कि पूर्व ERROR:root:Unhandled exception:की पहली पंक्ति की शुरुआत में है।


एक और अंतर यह है कि पूर्व लॉगिंग सिस्टम को ट्रेस लिखता है, इसलिए आपके द्वारा इंस्टॉल किए गए किसी भी हैंडलर और फॉर्मेटर्स को लागू किया जाता है। बाद वाले सीधे लिखते हैं sys.stderr
रेडिएफ

8

जैसिंडा के उत्तर पर निर्माण करने के लिए, लेकिन एक लकड़हारे वस्तु का उपयोग करना:

def catchException(logger, typ, value, traceback):
    logger.critical("My Error Information")
    logger.critical("Type: %s" % typ)
    logger.critical("Value: %s" % value)
    logger.critical("Traceback: %s" % traceback)

# Use a partially applied function
func = lambda typ, value, traceback: catchException(logger, typ, value, traceback)
sys.excepthook = func

2
functools.partial()लंबोदर के बजाय इसका उपयोग करना बेहतर होगा । देखें: docs.python.org/2/library/functools.html#functools.partial
Mariusz Jamro

@ मर्सिडीजजमरो क्यों?
davr

4

अपने ऐप एंट्री कॉल को एक try...exceptब्लॉक में लपेटें ताकि आप सभी अपवादित अपवादों को पकड़ सकें और लॉग इन कर सकें (और शायद फिर से बढ़ा सकें)। उदाहरण के बजाय:

if __name__ == '__main__':
    main()

यह करो:

if __name__ == '__main__':
    try:
        main()
    except Exception as e:
        logger.exception(e)
        raise

यह वह नहीं है जो सवाल पूछ रहा है। प्रश्न का इरादा यह पूछना है कि क्या करना है जब अपवाद कोड द्वारा नियंत्रित नहीं किया जाता है।
मयंक जायसवाल

1
खैर, पायथन एक प्रोग्रामिंग भाषा है, और इसका अर्थ है कि यह "स्वचालित रूप से" (जैसा कि ओपी चाहता है) चीजों को नहीं करता है, सिवाय अगर और जब आप इसे करने के लिए कहें। दूसरे शब्दों में, सभी अपवादों को "स्वचालित रूप से" लॉग करने का कोई तरीका नहीं है, जब तक कि आप इसके लिए कोड नहीं करते हैं - और यही मेरे जवाब में है।
flaviovs

1
ठीक है, अगर आप नेड बैचेलेडर के उत्तर को देखते हैं, तो अपवाद हुक के रूप में कुछ कहा जाता है। आपको अपने कोड में एक जगह पर परिभाषित करना होगा और आपके सभी अनकैप्ड अपवादों को संभालना होगा।
मयंक जायसवाल

1
अपवाद हुक इस तथ्य को नहीं बदलता है कि यह "स्वचालित" नहीं है (जिस अर्थ में ओपी चाहता है) - दूसरे शब्दों में, आपको अभी भी इसे कोड करना होगा। नेड का उत्तर (जो अपवाद हुक का उपयोग करता है) वास्तव में मूल प्रश्न को संबोधित करता है - यह सिर्फ मेरी राय में है , जिस तरह से यह करता है वह मेरी तुलना में बहुत कम पायथोनिक है।
flaviovs

1
यह बहुत अधिक आपके अपने उद्देश्यों पर निर्भर करता है। यदि आप आईडीई को खुश करने के लिए प्रोग्राम करते हैं, तो हाँ सभी अपवादों को पकड़ना एक विकल्प नहीं हो सकता है। लेकिन अगर आप त्रुटियों को इनायत से संभालना चाहते हैं, और उपयोगकर्ता को अच्छी प्रतिक्रिया दिखाना चाहते हैं, तो मुझे डर है कि आपको सभी अपवादों को पकड़ने की आवश्यकता होगी। ठीक है, पर्याप्त व्यंग्य :-) - यदि आप ध्यान से देखेंगे तो आप देखेंगे कि कोड अपवाद को रोक देता है, लेकिन फिर से बढ़ाता है, इसलिए जब तक आपका आईडीई कुछ "जादुई" नहीं कर रहा है, तब तक यह नहीं होना चाहिए, यह अभी भी मिलेगा अपवाद।
flaviovs

3

हो सकता है कि आप किसी मॉड्यूल के शीर्ष पर कुछ कर सकते हैं जो किसी फ़ाइल में stderr को पुनर्निर्देशित करता है, और फिर उस फ़ाइल को नीचे की तरफ लॉग करता है

sock = open('error.log', 'w')               
sys.stderr = sock

doSomething() #makes errors and they will log to error.log

logging.exception(open('error.log', 'r').read() )

3

हालाँकि @ gnu_lorien के उत्तर ने मुझे अच्छा शुरुआती बिंदु दिया, मेरा कार्यक्रम पहले अपवाद पर दुर्घटनाग्रस्त हो गया।

मैं एक अनुकूलित (और / या) बेहतर समाधान के साथ आया था, जो चुपचाप उन कार्यों के अपवादों को लॉग करता है जिन्हें सजाया जाता है @handle_error

import logging

__author__ = 'ahmed'
logging.basicConfig(filename='error.log', level=logging.DEBUG)


def handle_exception(exc_type, exc_value, exc_traceback):
    import sys
    if issubclass(exc_type, KeyboardInterrupt):
        sys.__excepthook__(exc_type, exc_value, exc_traceback)
        return
    logging.critical(exc_value.message, exc_info=(exc_type, exc_value, exc_traceback))


def handle_error(func):
    import sys

    def __inner(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except Exception, e:
            exc_type, exc_value, exc_tb = sys.exc_info()
            handle_exception(exc_type, exc_value, exc_tb)
        finally:
            print(e.message)
    return __inner


@handle_error
def main():
    raise RuntimeError("RuntimeError")


if __name__ == "__main__":
    for _ in xrange(1, 20):
        main()

2

स्वीकार किए गए उत्तर के टिप्पणी अनुभाग में चर्चा की गई श्रीज़ेउस से प्रश्न का उत्तर देने के लिए, मैं इसका उपयोग एक संवादात्मक कंसोल में अनकहा अपवाद लॉग करने के लिए करता हूं (पाइक्रोम 2018-2019 के साथ परीक्षण किया गया)। मुझे पता चला sys.excepthookकि एक अजगर खोल में काम नहीं करता है इसलिए मैंने गहराई से देखा और पाया कि मैं sys.exc_infoइसके बजाय उपयोग कर सकता हूं । हालाँकि, sys.exc_infoइसके विपरीत कोई तर्क नहीं है sys.excepthookजो 3 तर्क लेता है।

यहां, मैं दोनों का उपयोग करता हूं sys.excepthookऔर sys.exc_infoएक इंटरैक्टिव कंसोल में एक अपवाद और रैपर फ़ंक्शन के साथ स्क्रिप्ट दोनों को लॉग करने के लिए। दोनों फ़ंक्शन के लिए एक हुक फ़ंक्शन संलग्न करने के लिए, मेरे पास दो अलग-अलग इंटरफेस हैं जो कि तर्क दिए गए हैं या नहीं।

यहाँ कोड है:

def log_exception(exctype, value, traceback):
    logger.error("Uncaught exception occurred!",
                 exc_info=(exctype, value, traceback))


def attach_hook(hook_func, run_func):
    def inner(*args, **kwargs):
        if not (args or kwargs):
            # This condition is for sys.exc_info
            local_args = run_func()
            hook_func(*local_args)
        else:
            # This condition is for sys.excepthook
            hook_func(*args, **kwargs)
        return run_func(*args, **kwargs)
    return inner


sys.exc_info = attach_hook(log_exception, sys.exc_info)
sys.excepthook = attach_hook(log_exception, sys.excepthook)

लॉगिंग सेटअप gnu_lorien के उत्तर में पाया जा सकता है।


2

मेरे मामले में (उपयोग करते हुए python 3) @ जैसिंडा के उत्तर का उपयोग करते समय ट्रेसबैक की सामग्री मुद्रित नहीं की गई थी। इसके बजाय, यह सिर्फ वस्तु को प्रिंट करता है <traceback object at 0x7f90299b7b90>:।

इसके बजाय मैं करता हूं:

import sys
import logging
import traceback

def custom_excepthook(exc_type, exc_value, exc_traceback):
    # Do not print exception when user cancels the program
    if issubclass(exc_type, KeyboardInterrupt):
        sys.__excepthook__(exc_type, exc_value, exc_traceback)
        return

    logging.error("An uncaught exception occurred:")
    logging.error("Type: %s", exc_type)
    logging.error("Value: %s", exc_value)

    if exc_traceback:
        format_exception = traceback.format_tb(exc_traceback)
        for line in format_exception:
            logging.error(repr(line))

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