पायथन लॉगिंग (फ़ंक्शन नाम, फ़ाइल नाम, लाइन नंबर) एक एकल फ़ाइल का उपयोग कर


109

मैं यह जानने की कोशिश कर रहा हूं कि कोई एप्लिकेशन कैसे काम करता है। और इसके लिए मैं फ़ंक्शन के नाम के साथ-साथ लाइन नंबर (कोड के भीतर) पर लॉग करने के लक्ष्य के साथ प्रत्येक फ़ंक्शन के निकाय की पहली पंक्ति के रूप में डिबग कमांड सम्मिलित कर रहा हूं जहां मैं लॉग आउटपुट को संदेश भेजता हूं। अंत में, चूंकि इस एप्लिकेशन में कई फाइलें शामिल हैं, मैं एक सिंगल लॉग फाइल बनाना चाहता हूं ताकि मैं एप्लिकेशन के नियंत्रण प्रवाह को बेहतर ढंग से समझ सकूं।

यहाँ मुझे पता है:

  1. फ़ंक्शन नाम प्राप्त करने के लिए, मैं उपयोग कर सकता हूं, function_name.__name__लेकिन मैं function_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. मुझे पता है कि लॉगिंग का उपयोग कैसे करना है और किसी फाइल में लॉग इन करने के लिए हैंडलर को जोड़ना है, लेकिन मुझे यकीन नहीं है कि प्रोजेक्ट में फ़ंक्शन कॉल के सही क्रम में सभी लॉग संदेशों को रिकॉर्ड करने के लिए एकल फ़ाइल का उपयोग किया जा सकता है।

मै किसी भी सहायता के लिए बहुत आभारी रहूँगा।

धन्यवाद!


आप उपयोग करके अजगर डीबगर में छोड़ सकते हैं import pdb; pdb.set_trace(), और फिर अंतःक्रियात्मक रूप से कोड के माध्यम से कदम बढ़ा सकते हैं। इससे आपको प्रोग्राम फ्लो ट्रेस करने में मदद मिल सकती है।
मैथ्यू Schinckel

महान विचार! धन्यवाद मैट। यह अभी भी एक लॉग पाने के लिए सहायक होगा जैसा कि प्रश्न में उल्लेख किया गया है ताकि मुझे हर बार डिबग न करना पड़े। इसके अलावा, क्या आप अजगर के लिए एक आईडीई जानते हैं जो जावा के लिए ग्रहण जितना अच्छा है (ctrl + click आपको कार्य करने के लिए परिभाषा देता है) कि मैं डिबगिंग को आसान बनाने के लिए उपयोग कर सकता हूं?
user1126425

जवाबों:


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()को सम्मिलित करके और अपने कार्यक्रम को फिर से चलाकर एक इंटरैक्टिव डिबगिंग प्रॉम्प्ट में छोड़ सकते हैं । यह आपको कोड के माध्यम से कदम उठाने में सक्षम करता है, जैसा कि आप चुनते हैं, डेटा का निरीक्षण करना।


धन्यवाद मैट! मैं इस ऑटोलॉग फंक्शन की कोशिश करूंगा। मुझे% ऑपरेटर के RHS के रूप में उपयोग करने के बारे में थोड़ा भ्रम है: क्या '%(foo)s : %(bar)s'यह भी प्रिंट होगा bar["foo"]? या यह आपके उदाहरण से कुछ अलग है?
user1126425

मूल रूप से, फॉर्म की सभी चीज़ों को उस %(<foo>)sवस्तु के मान से बदल दिया जाता है, जिसे हुक द्वारा संदर्भित किया जाता है <foo>Docs.python.org/library/stdtypes.html#string-formatting
मैथ्यू सिनचकेल

3
@synthesizerpatel का उत्तर अधिक उपयोगी है।
Jan

504

इसके लिए सही उत्तर पहले से उपलब्ध कराए गए उपयोग का है 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
यह उत्तर होना चाहिए था!
user3885927

1
महान .. जोड़ने के लिए एक चीज, क्या हम लॉगफाइल को कोडफाइल के समान गतिशील रूप से नाम दे सकते हैं? उदाहरण के लिए: मैंने डायनामिक रूप से फाइलनाम लेने के लिए logging.basicConfig (फ़ाइल नाम = "% (फ़ाइल नाम)", प्रारूप = FORMAT) आज़माया, लेकिन इसने स्थैतिक मूल्य ले लिया। कोई उपाय?
24

2
@ सामान्य तौर पर, इसे प्राप्त करने का अनुशंसित तरीका हैgetLogger(__name__)
farthVader

2
मेरा एक प्रश्न है: जावा में मैंने कहीं पढ़ा है कि लाइन नंबर को प्रिंट करने को हतोत्साहित किया जाता है क्योंकि यह पता लगाने में अतिरिक्त समय लगता है कि लॉगर को किस लाइन से बुलाया जा रहा है। अजगर में यह सच नहीं है?
मैक्कोंक

2
अप्रासंगिक, लेकिन logging.getLogger('root')वह नहीं है जिसकी आप शायद अपेक्षा कर रहे हैं, यह rootलकड़हारा नहीं है , लेकिन 'रूट' नाम वाला एक साधारण लकड़हारा है।
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तर्क। डॉक्स देखें ।
एकाएक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.