পাইথন লগিং (ফাংশন নাম, ফাইলের নাম, লাইন নম্বর) একটি একক ফাইল ব্যবহার করে


109

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

আমি যা জানি তা এখানে:

  1. ফাংশনটির নাম পাওয়ার জন্য, আমি ব্যবহার করতে function_name.__name__পারি তবে আমি ফাংশন_নামটি ব্যবহার করতে চাই না (যাতে আমি দ্রুত Log.info("Message")সমস্ত ফাংশনের শরীরে জেনেরিকটি অনুলিপি করতে এবং আটকাতে পারি )। আমি জানি __func__ম্যাক্রো ব্যবহার করে সি-তে এটি করা যেতে পারে তবে আমি পাইথন সম্পর্কে নিশ্চিত নই।

  2. ফাইলের নাম এবং লাইন নম্বর পাওয়ার জন্য, আমি দেখেছি যে (এবং আমি বিশ্বাস করি) আমার অ্যাপ্লিকেশন পাইথন locals()ফাংশনটি ব্যবহার করছে তবে একটি বাক্য গঠনতে যা আমি পুরোপুরি অবগত নই: options = "LOG.debug('%(flag)s : %(flag_get)s' % locals())এবং আমি এটি ব্যবহার করে চেষ্টা করেছি LOG.info("My message %s" % locals())যা এর মতো কিছু তৈরি করে {'self': <__main__.Class_name object at 0x22f8cd0>}। দয়া করে কোন ইনপুট?

  3. আমি জানি যে কোনও ফাইল লগ করতে লগিং কীভাবে ব্যবহার করতে হয় এবং এতে হ্যান্ডলার যুক্ত করা যায় তবে আমি নিশ্চিত নই যে প্রকল্পটিতে ফাংশন কলের সঠিক ক্রমে সমস্ত লগ বার্তা রেকর্ড করার জন্য একটি ফাইল ব্যবহার করা যেতে পারে কিনা I

আমি যে কোন সাহায্যকে সর্ব্বোচ্চ প্রশংসা করব।

ধন্যবাদ!


আপনি ব্যবহার করে পাইথন ডিবাগারে ফেলে যেতে পারেন import pdb; pdb.set_trace()এবং তারপরে ইন্টারেক্টিভভাবে কোডের মাধ্যমে পদক্ষেপ নিতে পারেন। এটি আপনাকে প্রোগ্রামের প্রবাহটি সনাক্ত করতে সহায়তা করতে পারে।
ম্যাথু শিনকেল

ভালো বুদ্ধি! ধন্যবাদ ম্যাট প্রশ্নে উল্লিখিত লগ পাওয়ার জন্য এটি এখনও সহায়ক হবে যাতে আমাকে প্রতিবারই ডিবাগ করতে হবে না। এছাড়াও, আপনি কি অজগরের জন্য একটি আইডিই জানেন যা জাভা (যেমন সিটিআরএল + ক্লিক আপনাকে সংজ্ঞায়িত করতে পারে) এর মতো ভাল, আমি ডিবাগিংকে আরও সহজ করার জন্য ব্যবহার করতে পারি?
ব্যবহারকারী1126425

উত্তর:


28

আপনার এখানে কয়েকটি প্রান্তিক সম্পর্কিত প্রশ্ন রয়েছে।

আমি সবচেয়ে সহজ দিয়ে শুরু করব: (3)। loggingআপনি ব্যবহার করে সমস্ত কল একটি একক লগ ফাইল বা অন্যান্য আউটপুট টার্গেটে একত্রিত করতে পারেন: তারা প্রক্রিয়াটিতে যে ক্রম ঘটেছিল সেভাবে তা হবে।

পরবর্তী: (2)। locals()বর্তমান সুযোগের একটি ডিক সরবরাহ করে। সুতরাং, এমন কোনও পদ্ধতিতে যার অন্য কোনও যুক্তি নেই, আপনার selfসুযোগ রয়েছে, যা বর্তমান দৃষ্টান্তের রেফারেন্স ধারণ করে। যে কৌশলটি আপনাকে স্টাম্পিং করছে তা হ'ল %অপারেটরের আরএইচএস হিসাবে ডিক ব্যবহার করে স্ট্রিং ফর্ম্যাটিং । "%(foo)s" % barমানটি যাই হোক না কেন দ্বারা প্রতিস্থাপিত হবে bar["foo"]

অবশেষে, আপনি কিছু অন্তর্নির্মাণ কৌশল ব্যবহার করতে পারেন, এটির মতো ব্যবহৃত pdbআরও তথ্য লগ করতে পারে:

def autolog(message):
    "Automatically log the current function details."
    import inspect, logging
    # Get the previous frame in the stack, otherwise it would
    # be this function!!!
    func = inspect.currentframe().f_back.f_code
    # Dump the message + the name of this function to the log.
    logging.debug("%s: %s in %s:%i" % (
        message, 
        func.co_name, 
        func.co_filename, 
        func.co_firstlineno
    ))

এটি পাস করা বার্তাটি, এবং (মূল) ফাংশনটির নাম, যে ফাইলের সংজ্ঞাটি প্রদর্শিত হবে, এবং সেই ফাইলের লাইনটি লগ করবে। পরিদর্শন করে দেখুন - লাইভ অবজেক্টগুলি পরীক্ষা করুন আরও তথ্যের জন্য পরীক্ষা করুন।

যেমনটি আমি আমার মন্তব্যে আগেই উল্লেখ করেছি, আপনি pdbলাইনটি সন্নিবেশ করিয়ে import pdb; pdb.set_trace()এবং আপনার প্রোগ্রামটি পুনরায় চালিয়ে যে কোনও সময়ে ইন্টারেক্টিভ ডিবাগিং প্রম্পটেও যেতে পারেন । এটি আপনাকে কোডটি পদক্ষেপে সক্ষম করে, আপনার পছন্দ মতো ডেটা পরীক্ষা করে।


ধন্যবাদ ম্যাট! আমি এই অটোলজ ফাংশনটি চেষ্টা করব। % অপারেটরের আরএইচএস হিসাবে ডিক ব্যবহার সম্পর্কে আমার কিছুটা বিভ্রান্তি রয়েছে: এর মানটিও কি '%(foo)s : %(bar)s'মুদ্রিত হবে bar["foo"]? নাকি এটি আপনার উদাহরণের চেয়ে কিছুটা আলাদা?
ব্যবহারকারী1126425

মূলত, ফর্মের সমস্ত %(<foo>)sকিছুই ডিক দ্বারা রেফারেন্সযুক্ত বস্তুর মান দ্বারা প্রতিস্থাপিত হয় <foo>ডকস.পিথথন.আর.
ম্যাথু শিংকেল

3
@ সাইন্সেসাইজারপেটেলের উত্তর আরও অনেক সহায়ক।
জানুয়ারী

503

এর সঠিক উত্তরটি ইতিমধ্যে সরবরাহ করা funcNameভেরিয়েবল ব্যবহার করা

import logging
logger = logging.getLogger('root')
FORMAT = "[%(filename)s:%(lineno)s - %(funcName)20s() ] %(message)s"
logging.basicConfig(format=FORMAT)
logger.setLevel(logging.DEBUG)

তারপরে আপনি যেখানেই চান, কেবল যুক্ত করুন:

logger.debug('your message') 

আমি এখনই কাজ করছি এমন স্ক্রিপ্ট থেকে আউটপুট উদাহরণ:

[invRegex.py:150 -          handleRange() ] ['[A-Z]']
[invRegex.py:155 -     handleRepetition() ] [[<__main__.CharacterRangeEmitter object at 0x10ba03050>, '{', '1', '}']]
[invRegex.py:197 -          handleMacro() ] ['\\d']
[invRegex.py:155 -     handleRepetition() ] [[<__main__.CharacterRangeEmitter object at 0x10ba03950>, '{', '1', '}']]
[invRegex.py:210 -       handleSequence() ] [[<__main__.GroupEmitter object at 0x10b9fedd0>, <__main__.GroupEmitter object at 0x10ba03ad0>]]

61
এই উত্তর হওয়া উচিত ছিল!
ব্যবহারকারী 3885927

1
দুর্দান্ত .. একটি জিনিস যোগ করার জন্য, আমরা কি লগফিলকে কোডফাইলে গতিযুক্তভাবে নামকরণ করতে পারি? উদাহরণস্বরূপ: গতিশীলভাবে ফাইলের নাম নিতে আমি লগিংয়ের জন্য চেষ্টা করেছি bas বেসিক কনফিগ (ফাইলের নাম = "% (ফাইলের নাম)", ফর্ম্যাট = ফর্ম্যাট), তবে এটি স্থির মান নিয়েছে। যেকোনো পরামর্শ?
আউটিলার

2
@ আউটলির না, এটি অর্জনের প্রস্তাবিত getLogger(__name__)
উপায়টি

2
আমার একটি প্রশ্ন আছে: জাভাতে কোথাও আমি পড়েছি লাইন নম্বরটি মুদ্রণ করা নিরুৎসাহিত করা হয়েছে কারণ লাইনটি কোন লাইনটি ডাকা হচ্ছে তা নির্ধারণ করতে অতিরিক্ত সময় লাগে takes অজগর এ সত্য নয়?
ম্যাকসঙ্ক

2
অপ্রাসঙ্গিক, তবে logging.getLogger('root')আপনি যা প্রত্যাশা করছেন তা নয়, এটি rootলগার নয়, 'রুট' নামের সাধারণ লগার ger
0xc0de

5

funcname, linenameএবং linenoলগিংয়ের মাধ্যমে শেষ ফাংশন সম্পর্কিত তথ্য সরবরাহ করুন।

আপনার যদি লগারের মোড়ক থাকে (যেমন সিঙ্গলটন লগার), তবে @ সিন্থেসাইজারপ্যাটেলের উত্তরটি আপনার পক্ষে কাজ না করে।

কল স্ট্যাকের অন্যান্য কলার সন্ধানের জন্য আপনি এটি করতে পারেন:

import logging
import inspect

class Singleton(type):
    _instances = {}

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]

class MyLogger(metaclass=Singleton):
    logger = None

    def __init__(self):
        logging.basicConfig(
            level=logging.INFO,
            format="%(asctime)s - %(threadName)s - %(message)s",
            handlers=[
                logging.StreamHandler()
            ])

        self.logger = logging.getLogger(__name__ + '.logger')

    @staticmethod
    def __get_call_info():
        stack = inspect.stack()

        # stack[1] gives previous function ('info' in our case)
        # stack[2] gives before previous function and so on

        fn = stack[2][1]
        ln = stack[2][2]
        func = stack[2][3]

        return fn, func, ln

    def info(self, message, *args):
        message = "{} - {} at line {}: {}".format(*self.__get_call_info(), message)
        self.logger.info(message, *args)

1
আপনার উত্তরটি আমার সমস্যা সমাধানের জন্য ঠিক আমার যা প্রয়োজন ছিল। ধন্যবাদ.
ত্রুটি - সিন্ট্যাক্টিকাল রিফোর্স

পাইথন 3.8 সাল থেকে, loggingবর্গ সমর্থন স্ট্যাক স্তর আউট-অফ-বক্স কুঁদন: পদ্ধতি পছন্দ log(), debug()ইত্যাদি এখন একটি গ্রহণ stacklevelযুক্তি। দস্তাবেজগুলি দেখুন ।
প্রাণপণ শক্তিতে
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.