আমি কীভাবে ডিবাগ তথ্য দিয়ে পাইথন ত্রুটি লগ করব?


467

আমি পাইথন ব্যতিক্রম বার্তাগুলি একটি লগ ফাইলে এর সাথে মুদ্রণ করছি logging.error:

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

ব্যতিক্রম এবং কোড যা ব্যতিক্রম সম্পর্কিত স্ট্রিংয়ের চেয়ে এটিকে উত্পন্ন করেছিল সে সম্পর্কে আরও বিস্তারিত তথ্য মুদ্রণ করা সম্ভব? লাইন নম্বর বা স্ট্যাক ট্রেসগুলির মতো জিনিসগুলি দুর্দান্ত।

উত্তর:


732

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

@Paulo চেক করুন নোট, "জেনে রাখুন যে পাইথন 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। অন্যথায়, দৌড়াদৌড়ি চলতে থাকবে যেন সবকিছু ঠিক আছে।
ভয়ঙ্কর

184

প্রায় এক চমৎকার জিনিস logging.exceptionযে SiggyF এর উত্তর প্রদর্শন করা হয় না যে আপনার একটি অবাধ বার্তা মধ্যে পাস করতে পারেন, এবং লগিং এখনও পর্যন্ত সব ব্যতিক্রম বিবরণ দিয়ে পূর্ণ ট্রেসব্যাক দেখাবে হল:

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

কোনও বার্তা না দিয়ে কি ব্যতিক্রম লগ করা যায়?
স্টিভয়েসিয়াক

@ স্টিভেনভ্যাসেলেলারো - আমি আপনাকে পরামর্শ দিচ্ছি যে আপনি ''যদি সত্যিই কোনও বার্তা টাইপ করতে না চান তবে আপনি পাস করবেন ... যদিও কমপক্ষে একটি যুক্তি ছাড়া ফাংশনটি বলা যাবে না, সুতরাং আপনাকে এটির কিছু দিতে হবে।
আর্টঅফ ওয়ারফেয়ার

146

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

@ সিভিফ্যান: আমি অন্যান্য সম্পাদনাগুলি বা পোস্টের পরিচয়টি আসলে দেখিনি; সেই ভূমিকাটি তৃতীয় পক্ষের সম্পাদকও যুক্ত করেছিলেন। আমি মুছে ফেলা মন্তব্যগুলিতে কোথাও দেখতে পাচ্ছি না যে সেটাই ছিল অভিপ্রায়, তবে আমি আমার সম্পাদনাটি পূর্বাবস্থায় ফেলা এবং মন্তব্যগুলি সরিয়ে ফেলতে পারি, এখানে সম্পাদিত সংস্করণ ব্যতীত অন্য যে কোনও কিছুতে ভোটদানের পক্ষে দীর্ঘ সময় অতিবাহিত হয়েছে the ।
মার্তিজান পিটারস

কি logging.fatalলগিং লাইব্রেরিতে একটি পদ্ধতি? আমি শুধু দেখতে critical
আয়ান

1
@Ian এটা একটি ওরফে এর 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)
    

আপনি কেন "_, _, ex_traceback = sys.exc_info ()" ফাংশনটির বাইরে log_traceback রেখেছেন এবং তারপরে এটি একটি আর্গুমেন্ট হিসাবে পাস করেছেন? এটি সরাসরি ফাংশনের ভিতরে ব্যবহার করবেন না কেন?
বেসিল মুসা

@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

এই উত্তরটি উপরের চমৎকারগুলি থেকে তৈরি করা হয়েছে।

বেশিরভাগ অ্যাপ্লিকেশনগুলিতে, আপনি লগিং.এক্সেপশন (ঙ) সরাসরি কল করবেন না। সম্ভবত আপনি নিজের অ্যাপ্লিকেশন বা মডিউলটির জন্য নির্দিষ্ট কাস্টম লগারটিকে সংজ্ঞায়িত করেছেন:

# 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

দ্বিতীয় alচ্ছিক কীওয়ার্ড আর্গুমেন্টটি stack_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

আপনার লগিং মডিউলে (যদি কাস্টম মডিউল থাকে) কেবল স্ট্যাক_ইনফো সক্ষম করুন।

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

-1

যদি আপনি অতিরিক্ত নির্ভরতা মোকাবেলা করতে পারেন তবে টুইস্টডলগ ব্যবহার করুন, আপনাকে স্পষ্টভাবে ত্রুটিগুলি লগ করতে হবে না এবং এটি ফাইল বা প্রবাহে পুরো ট্রেসব্যাক এবং সময় দেয়।


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।
মার্ক আমেরিকা
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.