ট্রেসব্যাক সহ ব্যতিক্রম লগ করুন


152

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

try:
    do_something()
except:
    # How can I log my exception here, complete with its traceback?

উত্তর:


203

কোনও বার্তা সহ প্রেরিত ট্রেস তথ্যের সাথে বর্তমান ব্যতিক্রম লগ করতে হ্যান্ডলার / ব্লকের logging.exceptionমধ্যে থেকে ব্যবহার করুন except:

import logging
LOG_FILENAME = '/tmp/logging_example.out'
logging.basicConfig(filename=LOG_FILENAME, level=logging.DEBUG)

logging.debug('This message should go to the log file')

try:
    run_my_stuff()
except:
    logging.exception('Got exception on main handler')
    raise

এখন লগ ফাইলটি খুঁজছেন /tmp/logging_example.out:

DEBUG:root:This message should go to the log file
ERROR:root:Got exception on main handler
Traceback (most recent call last):
  File "/tmp/teste.py", line 9, in <module>
    run_my_stuff()
NameError: name 'run_my_stuff' is not defined

1
এর জন্য জাঙ্গো কোডটি সন্ধান করা হয়েছে, এবং আমি ধরে নিচ্ছি উত্তরটি হ'ল না, তবে কোনও চিহ্ন বা অক্ষরের নির্দিষ্ট পরিমাণে ট্রেসব্যাক সীমাবদ্ধ করার কোনও উপায় আছে কি? সমস্যাটি হ'ল বড় ট্র্যাসব্যাকগুলির জন্য এটি বেশ দীর্ঘ সময় নেয়।
এডুয়ার্ড লুকা

10
মনে রাখবেন যে আপনি যদি কোনও লগার সংজ্ঞায়িত করেন তবে আপনাকে এই কাজ logger = logging.getLogger('yourlogger')করতে লিখতে logger.exception('...')হবে ...
576i

আমরা কী এটি পরিবর্তন করতে পারি যাতে বার্তাটি লগ স্তরের INFO দিয়ে মুদ্রিত হয়?
এনএম

নোট করুন যে নির্দিষ্ট বাহ্যিক অ্যাপ্লিকেশনগুলির জন্য, যেমন অ্যাজুরে অন্তর্দৃষ্টি, ল্যাকগুলিতে ট্র্যাকব্যাক সংরক্ষণ করা হয় না। তারপরে এগুলি স্পষ্টভাবে ম্যাসেজ স্ট্রিংয়ে নীচের শো হিসাবে প্রেরণ করা প্রয়োজন।
এডগার এইচ

138

ব্যবহারের exc_infoবিকল্পগুলি আরও ভাল হতে পারে, সতর্কতা বা ত্রুটির শিরোনাম থেকে যায়:

try:
    # coode in here
except Exception as e:
    logging.error(e, exc_info=True)

exc_info=কোয়ার্গ যাকে বলে তা আমি কখনই মনে করতে পারি না ; ধন্যবাদ!
বার্তো

4
এটি লগিংয়ের অনুরূপ ception আপনি ত্রুটি ব্যতীত অন্য কোনও স্তর না চাইলে কেবল লগিং.এক্সেপশন ব্যবহার করুন।
ওয়াইর্মউড

@ ওয়ার্মউড এটি অভিন্ন নয় যেমন আপনাকে কোনও বার্তা সরবরাহ করতে হবেlogging.exception
পিটার উড

57

আমার কাজটি সম্প্রতি আমাদের অ্যাপ্লিকেশন থেকে সমস্ত ট্রেসব্যাকস / ব্যতিক্রমগুলি লগ ইন করার জন্য আমাকে কাজ দেয়। আমি অন্যান্য কৌশলগুলি চেষ্টা করেছি যা অন্যরা অনলাইনে পোস্ট করেছিল যেমন উপরের মতো তবে একটি ভিন্ন পদ্ধতির উপর স্থির হয়েছে। উপেক্ষা করাtraceback.print_exception

Http://www.bbarrows.com/ এ আমার একটি লেখা আছে এ যা পড়া সহজ হবে তবে আমি এটি এখানে আটকান।

যখন আমাদের সফ্টওয়্যার বন্যের সাথে মোকাবিলা করতে পারে তার সমস্ত ব্যতিক্রম লগিংয়ের কাজ করার সময় আমি অজগর ব্যতিক্রম ট্র্যাকব্যাকগুলিকে লগ করার জন্য বিভিন্ন পদ্ধতিতে চেষ্টা করেছি। প্রথমে আমি ভেবেছিলাম লগিং কোডটি সন্নিবেশ করার জন্য পাইথন সিস্টেমের ব্যতিক্রম হুক, sys.excepthook হবে সঠিক জায়গা। আমি অনুরূপ কিছু চেষ্টা করছিলাম:

import traceback
import StringIO
import logging
import os, sys

def my_excepthook(excType, excValue, traceback, logger=logger):
    logger.error("Logging an uncaught exception",
                 exc_info=(excType, excValue, traceback))

sys.excepthook = my_excepthook  

এটি মূল থ্রেডের জন্য কাজ করেছে তবে আমি শীঘ্রই দেখতে পেলাম যে আমার প্রক্রিয়া শুরু হওয়া কোনও নতুন থ্রেডে আমার sys.excepthook উপস্থিত থাকবে না। এটি একটি বিশাল সমস্যা কারণ বেশিরভাগ সবকিছুই এই প্রকল্পের থ্রেডে ঘটে।

গুগলিং এবং প্রচুর ডকুমেন্টেশন পড়ার পরে আমার পাওয়া সবচেয়ে সহায়ক তথ্য পাইথন ইস্যু ট্র্যাকার থেকে।

থ্রেডের প্রথম পোস্টটি sys.excepthookথ্রেডগুলি জুড়ে না রাখার একটি কার্যকারী উদাহরণ দেখায় (নীচে দেখানো হয়েছে)। স্পষ্টতই এটি প্রত্যাশিত আচরণ।

import sys, threading

def log_exception(*args):
    print 'got exception %s' % (args,)
sys.excepthook = log_exception

def foo():
    a = 1 / 0

threading.Thread(target=foo).start()

এই পাইথন ইস্যু থ্রেডে থাকা বার্তাগুলি সত্যিই 2 টি প্রস্তাবিত হ্যাকের ফলস্বরূপ। Threadব্যতিক্রম বা বানরের প্যাচ ধরতে এবং লগ করার জন্য ব্লক ব্যতীত সাবক্লাস এবং রান পদ্ধতিটি আমাদের নিজের পদ্ধতিতে মোড়ক করুনthreading.Thread.run ব্লক এবং ব্যতিক্রমগুলি লগ ব্যতীত আপনার নিজের চেষ্টা চালানোর জন্য ।

সাবক্লাসিংয়ের প্রথম পদ্ধতিটি আপনার কোডটিতে Threadআমার কাছে কম মার্জিত বলে মনে হচ্ছে কারণ আপনি নিজের কাস্টম Threadক্লাসটি আমদানি করতে এবং ব্যবহার করতে হবে যেখানেই আপনি লগিংয়ের থ্রেড রাখতে চেয়েছিলেন। এটি একটি ঝামেলা হিসাবে শেষ হয়েছে কারণ আমাকে আমাদের পুরো কোড বেসটি অনুসন্ধান করতে হয়েছিল এবং Threadsএই কাস্টমটির সাথে সমস্ত স্বাভাবিক প্রতিস্থাপন করতে হয়েছিল Thread। তবে এটি কী Threadকরছে সে সম্পর্কে এটি স্পষ্ট ছিল এবং কাস্টম লগিং কোডটিতে কোনও সমস্যা হয়ে থাকলে কারও জন্য নির্ণয় এবং ডিবাগ করা সহজ হবে। একটি গ্রাহক লগিং থ্রেড এর মতো দেখতে পারে:

class TracebackLoggingThread(threading.Thread):
    def run(self):
        try:
            super(TracebackLoggingThread, self).run()
        except (KeyboardInterrupt, SystemExit):
            raise
        except Exception, e:
            logger = logging.getLogger('')
            logger.exception("Logging an uncaught exception")

বানর প্যাচিংয়ের দ্বিতীয় পদ্ধতিটি দুর্দান্ত threading.Thread.runকারণ আমি ঠিক এটির পরে একবার চালাতে পারি __main__এবং সমস্ত ব্যাতিক্রমে আমার লগিং কোডটি ব্যবহার করতে পারি। বানরের প্যাচিং ডিবাগ করতে বিরক্তিকর হতে পারে যদিও এটি কোনও কিছুর প্রত্যাশিত কার্যকারিতা পরিবর্তন করে। পাইথন ইস্যু ট্র্যাকারের প্রস্তাবিত প্যাচটি হ'ল:

def installThreadExcepthook():
    """
    Workaround for sys.excepthook thread bug
    From
http://spyced.blogspot.com/2007/06/workaround-for-sysexcepthook-bug.html

(https://sourceforge.net/tracker/?func=detail&atid=105470&aid=1230540&group_id=5470).
    Call once from __main__ before creating any threads.
    If using psyco, call psyco.cannotcompile(threading.Thread.run)
    since this replaces a new-style class method.
    """
    init_old = threading.Thread.__init__
    def init(self, *args, **kwargs):
        init_old(self, *args, **kwargs)
        run_old = self.run
        def run_with_except_hook(*args, **kw):
            try:
                run_old(*args, **kw)
            except (KeyboardInterrupt, SystemExit):
                raise
            except:
                sys.excepthook(*sys.exc_info())
        self.run = run_with_except_hook
    threading.Thread.__init__ = init

আমি আমার ব্যতিক্রম লগিং পরীক্ষা করা শুরু না করেই বুঝতে পেরেছিলাম যে আমি এটির সমস্ত ভুল করছি।

পরীক্ষা করার জন্য আমি একটি ছিল

raise Exception("Test")

আমার কোড কোথাও। যাইহোক, আ পদ্ধতিটি যাকে এই পদ্ধতিটি বলা হয় মোড়ানো সেটি ব্লক ব্যতীত চেষ্টা ছিল যা ট্রেসব্যাক প্রিন্ট করে ব্যতিক্রমটিকে গ্রাস করে। এটি খুব হতাশার কারণ আমি দেখেছিলাম যে ট্রেসব্যাকটি এসটিডিওউটে প্রিন্ট করা হয়েছে তবে লগ হচ্ছে না। আমি তখন সিদ্ধান্ত নিয়েছিলাম যে ট্রেসব্যাকগুলি লগ করার একটি সহজ পদ্ধতি হ'ল কেবল বানরটি প্যাচ করা যা সমস্ত পাইথন কোডটি ট্রেসব্যাকগুলি তাদের মুদ্রণের জন্য ব্যবহার করে, ট্রেসব্যাক.প্রিন্ট_সেপশন। আমি নিম্নলিখিত অনুরূপ কিছু দিয়ে শেষ করেছি:

def add_custom_print_exception():
    old_print_exception = traceback.print_exception
    def custom_print_exception(etype, value, tb, limit=None, file=None):
        tb_output = StringIO.StringIO()
        traceback.print_tb(tb, limit, tb_output)
        logger = logging.getLogger('customLogger')
        logger.error(tb_output.getvalue())
        tb_output.close()
        old_print_exception(etype, value, tb, limit=None, file=None)
    traceback.print_exception = custom_print_exception

এই কোডটি একটি স্ট্রিং বাফারকে ট্রেসব্যাক লিখে এবং এটি লগিং ইআরআরএর জন্য লগ করে। আমার কাছে একটি কাস্টম লগিং হ্যান্ডলার রয়েছে 'কাস্টমলগার' লগার সেটআপ করা যা ERROR স্তরের লগগুলি নিয়ে যায় এবং বিশ্লেষণের জন্য তাদের বাড়িতে পাঠায় send


2
বেশ একটি আকর্ষণীয় পদ্ধতির। একটি প্রশ্ন - add_custom_print_exceptionআপনি লিঙ্ক করেছেন এমন সাইটে উপস্থিত হবে না এবং এর পরিবর্তে সেখানে বেশ কিছু ভিন্ন চূড়ান্ত কোড রয়েছে। আপনি কোনটি বলবেন ভাল / আরও চূড়ান্ত এবং কেন? ধন্যবাদ!
কল্পনা

ধন্যবাদ, দুর্দান্ত উত্তর!
101

একটি কাটা এবং পেস্ট টাইপো আছে। পুরানো_প্রিন্ট_সেপ্টেশনে ডেলিগ্রেড কলে, সীমা এবং ফাইলকে সীমা এবং ফাইলটি পাস করতে হবে, কোনওটি নয় - ওল্ড_প্রিন্ট_ এক্সসেপশন (টাইপ, মান, টিবি, সীমা, ফাইল)
মার্ভিন ২

আপনার শেষ কোড ব্লকের জন্য, একটি স্ট্রিংআইও শুরু করার পরিবর্তে এবং এর ব্যতিক্রম মুদ্রণের চেয়ে আপনি কেবল ব্যতিক্রম করতে পারেন logger.error(traceback.format_tb())(বা format_exc () যদি আপনি ব্যতিক্রম তথ্যও চান) want
জেমস 21

8

আপনি প্রধান থ্রেডে সমস্ত অপ্রকাশিত ব্যতিক্রম ল্যান্ড করতে পারেন কোনও হ্যান্ডলারকে sys.excepthook, সম্ভবত exc_infoপাইথনের লগিং ফাংশনগুলির পরামিতি ব্যবহার করে :

import sys
import logging

logging.basicConfig(filename='/tmp/foobar.log')

def exception_hook(exc_type, exc_value, exc_traceback):
    logging.error(
        "Uncaught exception",
        exc_info=(exc_type, exc_value, exc_traceback)
    )

sys.excepthook = exception_hook

raise Exception('Boom')

তবে যদি আপনার প্রোগ্রামটি থ্রেড ব্যবহার করে তবে থ্রেড ব্যবহার করে তৈরি করা উচিত threading.Thread পাইথনের ইস্যু ট্র্যাকারের 1230540 ইস্যুতে উল্লিখিত হিসাবে, যখন সেগুলির মধ্যে কোনও অপ্রকাশিত ব্যতিক্রম ঘটে তখন ট্রিগার করবে না । কিছু হ্যাককে এই সীমাবদ্ধতার আশেপাশের কাজ করার পরামর্শ দেওয়া হয়েছে, যেমন একটি বিকল্প পদ্ধতিতে ওভাররাইট করার জন্য বানর-প্যাচিং যা কোনও ব্লকে আসলটি আবৃত করে এবং ব্লকের ভিতরে থেকে কল করে । বিকল্পভাবে, আপনি কেবল নিজের / নিজের নিজের প্রতিটি থ্রেডের জন্য প্রবেশের পয়েন্টটি ম্যানুয়ালি মুড়ে দিতে পারেন ।sys.excepthookThread.__init__self.runruntrysys.excepthookexcepttryexcept


3

অপ্রকাশিত ব্যতিক্রম বার্তাগুলি STDERR এ যায়, সুতরাং পাইথনে নিজেই আপনার লগিং প্রয়োগের পরিবর্তে আপনি নিজের পাইথন স্ক্রিপ্টটি চালানোর জন্য যা কিছু শেল ব্যবহার করছেন তা ব্যবহার করে আপনি কোনও ফাইলে এসটিডিআরআর প্রেরণ করতে পারেন। বাশ স্ক্রিপ্টে, আপনি এটি আউটপুট পুনর্নির্দেশের সাহায্যে করতে পারেন, যেমন BASH গাইডে বর্ণিত

উদাহরণ

টার্মিনালে ফাইলগুলি ত্রুটি, অন্যান্য আউটপুট যুক্ত করুন:

./test.py 2>> mylog.log

ইন্টারলিভড STDOUT এবং STDERR আউটপুট সহ ফাইলটি ওভাররাইট করুন:

./test.py &> mylog.log


1

আপনি যেকোন পর্যায়ে (ডিইবিইউজি, ইনফো, ...) লগার ব্যবহার করে ট্রেসব্যাক পেতে পারেন। নোট করুন যে ব্যবহার করে logging.exception, স্তরটি ERROR।

# test_app.py
import sys
import logging

logging.basicConfig(level="DEBUG")

def do_something():
    raise ValueError(":(")

try:
    do_something()
except Exception:
    logging.debug("Something went wrong", exc_info=sys.exc_info())
DEBUG:root:Something went wrong
Traceback (most recent call last):
  File "test_app.py", line 10, in <module>
    do_something()
  File "test_app.py", line 7, in do_something
    raise ValueError(":(")
ValueError: :(

সম্পাদনা করুন:

এটি খুব কার্যকর হয় (অজগর 3.6 ব্যবহার করে)

logging.debug("Something went wrong", exc_info=True)

1

এখানে একটি সংস্করণ যা sys.excepthook ব্যবহার করে

import traceback
import sys

logger = logging.getLogger()

def handle_excepthook(type, message, stack):
     logger.error(f'An unhandled exception occured: {message}. Traceback: {traceback.format_tb(stack)}')

sys.excepthook = handle_excepthook

{traceback.format_exc()}পরিবর্তে ব্যবহার সম্পর্কে {traceback.format_tb(stack)}?
পরিবর্তনশীল

0

সম্ভবত হিসাবে আড়ম্বরপূর্ণ না, কিন্তু সহজ:

#!/bin/bash
log="/var/log/yourlog"
/path/to/your/script.py 2>&1 | (while read; do echo "$REPLY" >> $log; done)

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