मैं डिबग जानकारी के साथ पायथन त्रुटि कैसे दर्ज करूं?


468

मैं एक लॉग फ़ाइल के साथ पायथन अपवाद संदेशों को मुद्रित कर रहा हूं logging.error:

import logging
try:
    1/0
except ZeroDivisionError as e:
    logging.error(e)  # ERROR:root:division by zero

क्या अपवाद और कोड के बारे में अधिक विस्तृत जानकारी मुद्रित करना संभव है जो इसे अपवाद स्ट्रिंग की तुलना में उत्पन्न करता है? लाइन नंबर या स्टैक के निशान जैसी चीजें बहुत अच्छी होंगी।

जवाबों:


733

logger.exception त्रुटि संदेश के साथ एक स्टैक ट्रेस आउटपुट करेगा।

उदाहरण के लिए:

import logging
try:
    1/0
except ZeroDivisionError as e:
    logging.exception("message")

आउटपुट:

ERROR:root:message
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: integer division or modulo by zero

@ पाओलो चेक नोट, "ध्यान रखें कि पायथन 3 में आपको logging.exceptionकेवल exceptभाग के अंदर विधि को कॉल करना होगा । यदि आप इस विधि को मनमाने स्थान पर कहते हैं तो आपको एक विचित्र अपवाद मिल सकता है। डॉक्स इस बारे में सतर्क हो जाते हैं।"


131
exceptionविधि बस कॉल error(message, exc_info=1)। जैसे ही आप exc_infoकिसी अपवाद संदर्भ से लॉगिंग विधियों में से किसी के पास जाते हैं , आपको एक ट्रेसबैक मिलेगा।
हेल्मुट ग्रोने

16
आप अपने सभी कोड को कोशिश / अपवाद में लपेटने से बचने के लिए sys.excepthook( यहां देखें ) भी सेट कर सकते हैं ।
जुल

23
आप सिर्फ except Exception:इसलिए लिख सकते हैं क्योंकि आप eकिसी भी तरह से उपयोग नहीं कर रहे हैं ;)
मार्को फेरारी

21
eअपने कोड को अंतःक्रियात्मक रूप से डीबग करने का प्रयास करते समय आप बहुत अच्छी तरह से निरीक्षण कर सकते हैं। :) यही कारण है कि मैं हमेशा इसे शामिल करता हूं।
विकी लैडलर

4
अगर मैं गलत हूं तो मुझे सुधारें, इस मामले में, अपवाद की कोई वास्तविक हैंडलिंग नहीं है और इसलिए यह गुंजाइश raiseके अंत में जोड़ने के लिए समझ में आता है except। अन्यथा, दौड़ना जारी रहेगा जैसे कि सब कुछ ठीक था।
Dr

184

logging.exceptionउस के बारे में एक अच्छी बात यह है कि सिग्गीफ का जवाब यह नहीं है कि आप एक मनमाने संदेश में पास हो सकते हैं, और लॉगिंग अभी भी सभी अपवाद विवरणों के साथ पूर्ण ट्रेसबैक दिखाएगा:

import logging
try:
    1/0
except ZeroDivisionError:
    logging.exception("Deliberate divide by zero traceback")

डिफ़ॉल्ट (हाल के संस्करणों में) केवल मुद्रण त्रुटियों के लॉगिंग व्यवहार के साथ sys.stderr, यह इस तरह दिखता है:

>>> import logging
>>> try:
...     1/0
... except ZeroDivisionError:
...     logging.exception("Deliberate divide by zero traceback")
... 
ERROR:root:Deliberate divide by zero traceback
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: integer division or modulo by zero

क्या संदेश प्रदान किए बिना एक अपवाद लॉग इन किया जा सकता है?
Stevoisiak

@StevenVascellaro - मैं आपको सुझाव दूंगा कि ''यदि आप वास्तव में संदेश टाइप नहीं करना चाहते हैं ... तो फ़ंक्शन को कम से कम एक तर्क के बिना नहीं बुलाया जा सकता है, इसलिए आपको इसे कुछ देना होगा।
आर्टऑफवर्फ

147

exc_infoविकल्पों का उपयोग करना बेहतर हो सकता है, जिससे आप त्रुटि स्तर चुन सकते हैं (यदि आप उपयोग करते हैं exception, तो यह हमेशा errorस्तर पर रहेगा ):

try:
    # do something here
except Exception as e:
    logging.critical(e, exc_info=True)  # log exception info at CRITICAL log level

@ नागरिक: मैं वास्तव में अन्य संपादन या पोस्ट इंट्रो को नहीं देखता था; उस परिचय को तीसरे पक्ष के संपादक द्वारा भी जोड़ा गया था। मुझे हटाए गए टिप्पणियों में कहीं भी ऐसा नहीं दिखता है, जो कभी इरादा था, लेकिन मैं अपने संपादन को भी पूर्ववत कर सकता हूं और टिप्पणियों को हटा सकता हूं, यहां मतदान के लिए संपादित संस्करण के अलावा किसी अन्य चीज के लिए बहुत लंबा समय हो गया है ।
मार्टिन पीटर्स

है logging.fatalलॉगिंग पुस्तकालय में एक विधि? मैं ही देखता हूं critical
इयान

1
@ अगर यह एक उपनाम है critical, जैसे warnहै warning
0xc0de

35

का हवाला देते हुए

क्या होगा यदि आपका एप्लिकेशन किसी अन्य तरीके से लॉगिंग करता है - loggingमॉड्यूल का उपयोग नहीं कर रहा है ?

अब, tracebackयहाँ इस्तेमाल किया जा सकता है।

import traceback

def log_traceback(ex, ex_traceback=None):
    if ex_traceback is None:
        ex_traceback = ex.__traceback__
    tb_lines = [ line.rstrip('\n') for line in
                 traceback.format_exception(ex.__class__, ex, ex_traceback)]
    exception_logger.log(tb_lines)
  • अजगर 2 में इसका इस्तेमाल करें :

    try:
        # your function call is here
    except Exception as ex:
        _, _, ex_traceback = sys.exc_info()
        log_traceback(ex, ex_traceback)
  • इसे पायथन 3 में उपयोग करें :

    try:
        x = get_number()
    except Exception as ex:
        log_traceback(ex)

आपने फ़ंक्शन log_traceback के बाहर "_, _, ex_traceback = sys.exc_info ()" क्यों रखा और फिर इसे एक तर्क के रूप में पास किया? सीधे फ़ंक्शन के अंदर इसका उपयोग क्यों नहीं करें?
तुलसी मूसा

@BasilMusa, आपके सवाल संक्षेप में, संगत करने के लिए अजगर 3 के साथ, जवाब देने के लिए है, क्योंकि ex_tracebackसे है ex.__traceback__अजगर 3 के तहत है, लेकिन ex_tracebackसे है sys.exc_info()पायथन 2. तहत
zangw

12

यदि आप सादे लॉग का उपयोग करते हैं - आपके सभी लॉग रिकॉर्ड को इस नियम के अनुरूप होना चाहिए one record = one line:। इस नियम का पालन करके आप grepअपनी लॉग फाइल को संसाधित करने के लिए अन्य उपकरणों का उपयोग कर सकते हैं ।

लेकिन ट्रेसबैक जानकारी मल्टी-लाइन है। तो मेरा जवाब इस धागे में ऊपर zangw द्वारा प्रस्तावित समाधान का एक विस्तारित संस्करण है । समस्या यह है कि ट्रेसबैक लाइनें \nअंदर हो सकती हैं , इसलिए हमें इस लाइन के अंत से छुटकारा पाने के लिए एक अतिरिक्त काम करने की आवश्यकता है:

import logging


logger = logging.getLogger('your_logger_here')

def log_app_error(e: BaseException, level=logging.ERROR) -> None:
    e_traceback = traceback.format_exception(e.__class__, e, e.__traceback__)
    traceback_lines = []
    for line in [line.rstrip('\n') for line in e_traceback]:
        traceback_lines.extend(line.splitlines())
    logger.log(level, traceback_lines.__str__())

उसके बाद (जब आप अपने लॉग का विश्लेषण कर रहे होंगे) आप अपनी लॉग फ़ाइल से आवश्यक ट्रेसबैक लाइनों को कॉपी / पेस्ट कर सकते हैं और यह करें:

ex_traceback = ['line 1', 'line 2', ...]
for line in ex_traceback:
    print(line)

फायदा!


9

यह उत्तर उपरोक्त उत्कृष्ट लोगों से बनता है।

अधिकांश अनुप्रयोगों में, आप सीधे logging.exception (e) को कॉल नहीं करेंगे। सबसे अधिक संभावना है कि आपने इस तरह से अपने एप्लिकेशन या मॉड्यूल के लिए विशिष्ट कस्टम लकड़हारा परिभाषित किया है:

# Set the name of the app or module
my_logger = logging.getLogger('NEM Sequencer')
# Set the log level
my_logger.setLevel(logging.INFO)

# Let's say we want to be fancy and log to a graylog2 log server
graylog_handler = graypy.GELFHandler('some_server_ip', 12201)
graylog_handler.setLevel(logging.INFO)
my_logger.addHandler(graylog_handler)

इस मामले में, केवल इस तरह के अपवाद (ई) को कॉल करने के लिए लकड़हारे का उपयोग करें:

try:
    1/0
except ZeroDivisionError, e:
    my_logger.exception(e)

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

7

आप एक अपवाद के बिना स्टैक ट्रेस लॉग कर सकते हैं।

https://docs.python.org/3/library/logging.html#logging.Logger.debug

दूसरा वैकल्पिक कीवर्ड तर्क है stack_info, जो फाल्स को डिफॉल्ट करता है। यदि सही है, तो लॉगिंग संदेश में स्टैक जानकारी जोड़ी जाती है, जिसमें वास्तविक लॉगिंग कॉल भी शामिल है। ध्यान दें कि यह वही स्टैक जानकारी नहीं है जो कि exc_info को निर्दिष्ट करने के माध्यम से प्रदर्शित होती है: पूर्व स्टैक के नीचे से स्टैक फ्रेम है जो वर्तमान थ्रेड में लॉगिंग कॉल तक है, जबकि बाद वाले स्टैक फ्रेम के बारे में जानकारी है जो कि निराधार है, अपवाद संचालकों की खोज करते हुए, एक अपवाद का पालन करना।

उदाहरण:

>>> import logging
>>> logging.basicConfig(level=logging.DEBUG)
>>> logging.getLogger().info('This prints the stack', stack_info=True)
INFO:root:This prints the stack
Stack (most recent call last):
  File "<stdin>", line 1, in <module>
>>>

5

थोड़ा सा डेकोरेटर ट्रीटमेंट (शायद बहुत अच्छे से प्रेरित होकर मोनाड और लिफ्टिंग)। आप सुरक्षित रूप से पायथन 3.6 प्रकार के एनोटेशन को हटा सकते हैं और पुराने संदेश स्वरूपण शैली का उपयोग कर सकते हैं।

fallible.py

from functools import wraps
from typing import Callable, TypeVar, Optional
import logging


A = TypeVar('A')


def fallible(*exceptions, logger=None) \
        -> Callable[[Callable[..., A]], Callable[..., Optional[A]]]:
    """
    :param exceptions: a list of exceptions to catch
    :param logger: pass a custom logger; None means the default logger, 
                   False disables logging altogether.
    """
    def fwrap(f: Callable[..., A]) -> Callable[..., Optional[A]]:

        @wraps(f)
        def wrapped(*args, **kwargs):
            try:
                return f(*args, **kwargs)
            except exceptions:
                message = f'called {f} with *args={args} and **kwargs={kwargs}'
                if logger:
                    logger.exception(message)
                if logger is None:
                    logging.exception(message)
                return None

        return wrapped

    return fwrap

डेमो:

In [1] from fallible import fallible

In [2]: @fallible(ArithmeticError)
    ...: def div(a, b):
    ...:     return a / b
    ...: 
    ...: 

In [3]: div(1, 2)
Out[3]: 0.5

In [4]: res = div(1, 0)
ERROR:root:called <function div at 0x10d3c6ae8> with *args=(1, 0) and **kwargs={}
Traceback (most recent call last):
  File "/Users/user/fallible.py", line 17, in wrapped
    return f(*args, **kwargs)
  File "<ipython-input-17-e056bd886b5c>", line 3, in div
    return a / b

In [5]: repr(res)
'None'

आप इस समाधान को संशोधित कर सकते हैं Noneकि exceptभाग की तुलना में कुछ अधिक वापस लौटाएं (या इस fallibleतर्क में इस रिटर्न वैल्यू को निर्दिष्ट करके समाधान को सामान्य बना दें )।


0

अपने लॉगिंग मॉड्यूल (यदि कस्टम मॉड्यूल) में केवल stack_info सक्षम करें।

api_logger.exceptionLog("*Input your Custom error message*",stack_info=True)

-1

यदि आप अतिरिक्त निर्भरता का सामना कर सकते हैं, तो twisted.log का उपयोग करें, आपको स्पष्ट रूप से त्रुटियों को लॉग इन करने की आवश्यकता नहीं है और यह फ़ाइल या स्ट्रीम में संपूर्ण ट्रेसबैक और समय भी लौटाता है।


8
शायद twistedएक अच्छी सिफारिश है, लेकिन यह जवाब वास्तव में ज्यादा योगदान नहीं देता है। यह नहीं कहता है कि कैसे उपयोग करें twisted.log, न ही loggingमानक पुस्तकालय से मॉड्यूल पर इसके क्या फायदे हैं , और न ही यह बताएं कि "आपको स्पष्ट रूप से लॉग त्रुटियों के लिए क्या नहीं करना है"
मार्क अमेरी

-8

इसका उपयोग करने का एक साफ तरीका format_exc()और प्रासंगिक भाग प्राप्त करने के लिए आउटपुट को पार्स करना:

from traceback import format_exc

try:
    1/0
except Exception:
    print 'the relevant part is: '+format_exc().split('\n')[-2]

सादर


4
है ना? वह "प्रासंगिक भाग" क्यों है ? सभी जानकारी के परिणाम से लाइन नंबर और ट्रेसबैक .split('\n')[-2]को फेंक दिया जाता है format_exc()- उपयोगी जानकारी जो आप सामान्य रूप से चाहते हैं! क्या अधिक है, यह उस का एक अच्छा काम भी नहीं करता है ; यदि आपके अपवाद संदेश में एक नई पंक्ति है, तो यह दृष्टिकोण केवल अपवाद संदेश की अंतिम पंक्ति को प्रिंट करेगा - जिसका अर्थ है कि आप अपवाद वर्ग को खो देते हैं और अधिकांश अपवाद संदेश को ट्रेसबैक खोने के शीर्ष पर छोड़ देते हैं। -1।
मार्क अमेरी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.