2011-06-13 14 views
34

में जोड़ा गया है मेरे पास कोड का एक टुकड़ा है जो नीचे के रूप में लॉगर प्रारंभ कर रहा है। मैं एक सिंगलटन का उपयोग किए बिना इस लागू करने के लिए पसंद करते हैं -पायथन लॉगिंग सुनिश्चित करें कि एक हैंडलर केवल एक बार

logger = logging.getLogger() 
hdlr = logging.FileHandler('logfile.log') 
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') 
hdlr.setFormatter(formatter) 
logger.addHandler(hdlr) 
logger.setLevel(logging.DEBUG) 

दुर्भाग्य से इस कोड को कई बार बुलाया जा रहा है, वहाँ किसी भी तरह से मैं देखने के लिए अगर हैंडलर पहले से मौजूद है की जाँच कर सकते है।

संपादित करें: - चियर्स, रिचर्ड

+0

मुझे लगता है कि आप जवाब का पुनर्मूल्यांकन करना चाहिए, क्योंकि (लेखन के समय) mouad का जवाब है कि एक विधि के लिए कई कॉल एक ही लकड़हारा वस्तु * CAN लौटने * डुप्लिकेट संचालकों को जोड़ने तथ्य पर ध्यान नहीं देता। नारायण यह समझाने का अच्छा काम करता है। –

उत्तर

21

@offbyone टिप्पणियों के रूप में, लॉगर के उसी उदाहरण में अनावश्यक हैंडलर जोड़ना संभव है। python docs for logging कहना

"एक से अधिक getLogger() ही नाम के साथ करने के लिए कॉल एक ही लकड़हारा वस्तु के लिए एक संदर्भ वापस आ जाएगी।"

इसलिए हमें कार्यान्वयन को सिंगलटन बनाने की चिंता करने की आवश्यकता नहीं है, जैसा कि पहले से ही है।

दुर्भाग्य से यह लॉगर के समान उदाहरण से जुड़े हैंडलर के लिए सही नहीं है। डुप्लिकेट हैंडलर संलग्न हो सकते हैं।

उदाहरण

  1. कॉपी इस कोड और sub.py

    print 'inside sub.py', 
    print '-'*50 
    print 'importing main.py' 
    import main 
    print 'imported main.py' 
    import logging 
    print 'getting logger instance in sub' 
    sub_logger = main.logger() 
    print 'got logger instance in sub' 
    sub_logger.info("utilizing sub_logger") 
    print 'exiting sub.py', 
    print '-'*50 
    
  2. भागो उप में main.py

    import logging 
    print 'inside main.py', 
    print '-'*50 
    def logger(): 
    
         print 'initializing logger....' 
         logPath = '.' 
         fileName = 'temp' 
    
         # configure log formatter 
         logFormatter = logging.Formatter("%(asctime)s [%(filename)s] [%(funcName)s] [%(levelname)s] [%(lineno)d] %(message)s") 
    
         # configure file handler 
         fileHandler = logging.FileHandler("{0}/{1}.log".format(logPath, fileName)) 
         fileHandler.setFormatter(logFormatter) 
    
         # configure stream handler 
         consoleHandler = logging.StreamHandler() 
         consoleHandler.setFormatter(logFormatter) 
    
         # get the logger instance 
         logger = logging.getLogger(__name__) 
    
         # set the logging level 
         logger.setLevel(logging.DEBUG) 
    
         print 'adding handlers- ' 
    
         #if not len(logger.handlers): 
         logger.addHandler(fileHandler) 
         logger.addHandler(consoleHandler) 
    
         print 'logger initialized....\n' 
         print 'associated handlers - ', len(logger.handlers) 
         for handler in logger.handlers: 
          print handler 
         print 
         return logger 
    
    main_logger = logger() 
    main_logger.info('utilizing main.py logger.') 
    print 'exiting main.py', 
    print '-'*50 
    
  3. और निम्न कोड में इसे सहेजें।एक ही लकड़हारा लौटने विधि के लिए py

    [email protected]:~/code/so$ python sub.py 
    inside sub.py -------------------------------------------------- 
    importing main.py 
    inside main.py -------------------------------------------------- 
    initializing logger.... 
    adding handlers- 
    logger initialized.... 
    
    associated handlers - 2 
    <logging.FileHandler object at 0x7f7158740c90> 
    <logging.StreamHandler object at 0x7f7158710b10> 
    
    2015-08-04 07:41:01,824 [main.py] [<module>] [INFO] [41] utilizing main.py logger. 
    exiting main.py -------------------------------------------------- 
    imported main.py 
    getting logger instance in sub 
    initializing logger.... 
    adding handlers- 
    logger initialized.... 
    
    associated handlers - 4 # <===== 4 handlers (duplicates added) 
    <logging.FileHandler object at 0x7f7158740c90> 
    <logging.StreamHandler object at 0x7f7158710b10> 
    <logging.FileHandler object at 0x7f7158710bd0> 
    <logging.StreamHandler object at 0x7f7158710c10> 
    
    got logger instance in sub 
    2015-08-04 07:41:01,824 [sub.py] [<module>] [INFO] [10] utilizing sub_logger 
    2015-08-04 07:41:01,824 [sub.py] [<module>] [INFO] [10] utilizing sub_logger 
    exiting sub.py -------------------------------------------------- 
    

इसलिए कई कॉल डुप्लिकेट संचालकों गयी।

अब, अपने सवाल के लिए

वहाँ किसी भी तरह से मैं अगर हैंडलर पहले से मौजूद है

हाँ, वहाँ है-

logger.handlers की सूची लौटाता है देखने के लिए जाँच कर सकते हैं दिए गए logger से जुड़े सभी हैंडलर।

लकड़हारा का एक उदाहरण के लिए संचालकों जोड़ने से पहले, डुप्लिकेट संचालकों main.py में, जोड़ने का तरीका नहीं कर बस अन-टिप्पणी लाइन है कि if not len(logger.handlers): कहते हैं और इंडेंट निम्नांकित दो पंक्तियों properly-

if not len(logger.handlers): 
    logger.addHandler(fileHandler) 
    logger.addHandler(consoleHandler) 

अब फिर से sub.py

[email protected]:~/code/so$ python sub.py 
inside sub.py -------------------------------------------------- 
importing main.py 
inside main.py -------------------------------------------------- 
initializing logger.... 
adding handlers- 
logger initialized.... 

associated handlers - 2 
<logging.FileHandler object at 0x7fd67a891c90> 
<logging.StreamHandler object at 0x7fd67a862b10> 

2015-08-04 08:14:45,620 [main.py] [<module>] [INFO] [41] utilizing main.py logger. 
exiting main.py -------------------------------------------------- 
imported main.py 
getting logger instance in sub 
initializing logger.... 
adding handlers- 
logger initialized.... 

associated handlers - 2 # <===== Still 2 handlers (no duplicates) 
<logging.FileHandler object at 0x7fd67a891c90> 
<logging.StreamHandler object at 0x7fd67a862b10> 

got logger instance in sub 
2015-08-04 08:14:45,620 [sub.py] [<module>] [INFO] [10] utilizing sub_logger 
exiting sub.py -------------------------------------------------- 

आगे चलाने के लिए, यदि आप संचालकों लकड़हारा उदाहरण के लिए जोड़ा जा करने के लिए के प्रकार को सीमित करना चाहते हैं, तो आप इस-

की तरह कुछ कर सकते हैं
print 'adding handlers- ' 
    # allows to add only one instance of file handler and stream handler 
    if len(logger.handlers) > 0: 
     print 'making sure we do not add duplicate handlers' 
     for handler in logger.handlers: 
       # add the handlers to the logger 
       # makes sure no duplicate handlers are added 

       if not isinstance(handler, logging.FileHandler) and not isinstance(handler, logging.StreamHandler): 
        logger.addHandler(fileHandler) 
        print 'added file handler' 
        logger.addHandler(consoleHandler) 
        print 'added stream handler' 
    else: 
     logger.addHandler(fileHandler) 
     logger.addHandler(consoleHandler) 
     print 'added handlers for the first time' 

उम्मीद है कि इससे मदद मिलती है!

संपादित करें:

दुर्भाग्य से एक ही नहीं सच लकड़हारा का एक ही उदाहरण के साथ जुड़े संचालकों के लिए है। वहां डुप्लिकेट हैंडलर संलग्न हो सकते हैं।

यह पता चला है कि उपर्युक्त कथन पूरी तरह से सत्य नहीं है।

मान लीजिए कि हमने मुख्य मॉड्यूल में 'main_logger' नामक लॉगर को बनाया और कॉन्फ़िगर किया है (जो केवल लॉगर को कॉन्फ़िगर करता है, कुछ भी वापस नहीं करता है)।

# get the logger instance 
logger = logging.getLogger("main_logger") 
# configuration follows 
... 

अब एक उप मॉड्यूल में, अगर हम एक बच्चे लकड़हारा नामकरण पदानुक्रम 'main_logger.sub_module_logger' निम्नलिखित बनाते हैं तो हम उप मॉड्यूल में यह विन्यस्त करने की जरूरत नहीं है। नामकरण पदानुक्रम के बाद बस लॉगर का निर्माण पर्याप्त है।

# get the logger instance 
logger = logging.getLogger("main_logger.sub_module_logger") 
# no configuration needed 
# it inherits the configuration from the parent logger 
... 

और यह डुप्लिकेट हैंडलर भी नहीं जोड़ देगा।

Reference- Using logging in multiple modules

+1

यह निश्चित रूप से सबसे अच्छा जवाब है। मौद का जवाब दुर्भाग्य से शॉर्ट्सइट किया गया है कि यह लॉगर (सिंगलटन) के एक उदाहरण के लिए डुप्लिकेट हैंडलर (सिंगलेट्स नहीं) की संभावना को याद करता है। आपके उत्तर ने मुझे अपनी समस्या का समाधान करने में मदद की। –

+0

"logger.handlers दिए गए लॉगर से जुड़े सभी हैंडलरों की एक सूची देता है" ... हाँ यह करता है, लेकिन क्या मैं आपसे पूछ सकता हूं कि आपको यह कैसे पता चला? क्या आप स्रोत कोड पर वापस गए थे? चूंकि पाइथन लॉगिंग मॉड्यूल प्रलेखन https://docs.python.org/2/library/logging.html इस जानकारी को प्रकट नहीं करता है। कभी-कभी मुझे लगता है कि पाइथन के मानक दस्तावेज की कमी है ... कुछ भी बेहतर आप सिफारिश कर सकते हैं? –

+0

@mikerodent मुझे SO पर _logger.handlers_ के बारे में पता चला जब मैं लॉग इन करने और स्रोत कोड में सत्यापित करने के लिए इस डुप्लिकेट आउटपुट समस्या से जूझ रहा था। प्रलेखन के संबंध में, अक्सर नहीं, मानक दस्तावेज़ नौकरी करते हैं। [pymotw] (https://pymotw.com/2/contents.html) जब भी मैं पाइथन मानक पुस्तकालय की मदद से कुछ विशिष्ट करना चाहता हूं, मेरी मदद करता है। – narayan

14

खैर logger.addHandler() एक हैंडलर जोड़ने नहीं होगा अगर हैंडलर पहले से मौजूद है क्षमा करें, यह अजगर 2.5 पर है उल्लेख करना भूल गया।

logger = logging.getLogger() 
hdlr = logging.FileHandler('logfile.log') 
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') 
hdlr.setFormatter(formatter) 
logger.addHandler(hdlr) 
logger.setLevel(logging.DEBUG) 
print logger.handlers 
# [<logging.FileHandler object at 0x14542d0>] 
logger.addHandler(hdlr) 
print logger.handlers 
# [<logging.FileHandler object at 0x14542d0>] 
है कि मैं अगर आपके पास है अपने मुख्य() फ़ंक्शन में इस कोड को डालने का सुझाव देगा बगल

या अपने पैकेज के __init__.py फ़ाइल में: अगर हैंडलर पहले से ही वहाँ है आप logger.handlers सूची की जांच कर सकते हैं की जाँच करने के इसलिए इसे हर बार कॉल करने की ज़रूरत नहीं है। मैं यह भी सुझाव दूंगा कि आप नामित लॉगर का उपयोग करें, और रूट लॉगर का उपयोग न करें। कुछ इस तरह:

logger = logging.getLogger(__name__) 
... 

आशा इस मददगार था :)

+2

कहीं भी दस्तावेज 'Logger.handlers' सूची है? मैं इसे http: // डॉक्स पर नहीं ढूंढ सका।python.org/2/library/logging.html –

+1

@ MariuszPluciński: हाँ मुझे नहीं लगता कि यह कहीं भी दस्तावेज है, लेकिन अगर मुझे अच्छी तरह याद है तो मुझे यह काम समझने के लिए लॉगर क्लास कोड देखना होगा: http: // hg। python.org/cpython/file/482590320549/Lib/logging/__init__.py#l1215 – mouad

+1

लेकिन अगर यह अनियंत्रित है, तो यह लॉगिंग लाइब्रेरी के कुछ भविष्य संस्करण में चुपचाप गायब हो सकता है। मुझे यकीन नहीं है कि इस सुविधा पर निर्भर होना अच्छा है (लेकिन मैं सहमत हूं कि, यह जांचने के लिए कोई दस्तावेज तरीका प्रतीत नहीं होता है)। –

1

पता चल सके कि logger पहले से ही सेट किया गया है की कोशिश करो। उदाहरण के लिए, यदि यह कोड फ़ंक्शन के अंदर है:

logger = None 
def init_logger(): 
    global logger 
    if logger is not None: 
     #logger has already been initialized 
     return 
    logger = logging.getLogger() 
    hdlr = logging.FileHandler('logfile.log') 
    formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') 
    hdlr.setFormatter(formatter) 
    logger.addHandler(hdlr) 
    logger.setLevel(logging.DEBUG) 
+0

मुझे लगता है कि चेकर नहीं है 'अगर लॉगजर नहीं है कोई भी 'थ्रेड सुरक्षित नहीं है इसलिए प्रारंभिक कोड की कोई गारंटी नहीं है एक से अधिक बार नहीं चलेंगे। –

2

आप यह भी देखने के लिए जांच सकते हैं कि हैंडलर सूची खाली है या नहीं। यहाँ समाधान मैं के साथ घाव है:

def setup_logging(self, logfile): 
    self._logger = logging.getLogger('TestSuite') 
    self._logger.setLevel(logging.INFO) 
    host = socket.gethostname().split('.')[0] 
    if self._logger.handlers == []: 
     fh = logging.handlers.RotatingFileHandler(logfile, 
                maxBytes=10*1024*1024, 
                backupCount=5) 
     strfmt = "%" + "(asctime)s [%s] " % host + "%" + "(message)s" 
     fmt = logging.Formatter(strfmt, datefmt="%Y.%m%d %H:%M:%S") 
     fh.setFormatter(fmt) 

     self._logger.addHandler(fh) 
    self._logger.info('-' * (55 - len(host))) 

मैं देख रहा था हैंडलर कई बार जोड़ा है, इसलिए प्रत्येक लॉग संदेश एक बार से अधिक लॉग फ़ाइल के लिए लिखा जा रहा था, और इस यह तय की।

संबंधित मुद्दे