2013-06-24 9 views
24

मेरे उद्देश्य श्रेणीबद्ध छानने

जिस तरह से यह प्रवेश लेखक विनय Sajip द्वारा प्रस्तावित है के साथ एक बहु मॉड्यूल प्रवेश करना है, कम से कम जहाँ तक मुझे लगता है कि के रूप में ;-)पायथन लॉगिंग का उपयोग कर विभिन्न लॉगर्स फ़िल्टर करने का सही तरीका क्या है?

आप के लिए छोड़ सकते हैं दुर्भाग्य से

"मैं इसे कैसे काम करना चाहता हूँ", मैं बहुत जल्दी सीखा है कि प्रवेश की सुविधा के साथ काम करने और अधिक परिष्कृत है भाषा के साथ मेरे दूसरे अनुभव की तुलना में सबसे और मैं पहले से ही आम (डिजाइन) के एक बहुत कुछ किया गलतियों, उदाहरण के लिए एकाधिक मॉड्यूल या यहां तक ​​कि योजनाओं जैसे using Python logger class to generate multiple logs for different log levels) के लिए केंद्रीकृत सिंगल लॉगर क्लास लॉगिंग प्राप्त करने का प्रयास कर रहा है। लेकिन स्पष्ट रूप से बेहतर डिजाइन के लिए एक कमरा है, और यह समय खोजने और सीखने में बुरा खर्च हो सकता है। तो, अभी मैं आशा करता हूं कि मैं सही रास्ते पर हूं। अन्यथा Vinaj बाकी ;-)

मैं इस रूप में अपने प्रवेश की व्यवस्था को स्पष्ट करना होगा:

  • प्रत्येक अजगर मॉड्यूल अपने own logger
  • प्रत्येक लकड़हारा एक नाम मॉड्यूल यह वह जगह है जहाँ के रूप में ही है है परिभाषित, उदाहरण के लिए logger = logging.getLogger(__name__)
  • इस तरह, प्रत्येक मॉड्यूल के अंदर कोड संचालकों (logging.Handler) करने के लिए लॉगिंग संदेश (logging.LogRecord) भेजने के लिए अपने स्वयं के (स्थानीय रूप से परिभाषित) लकड़हारा उपयोग कर सकते हैं
  • उपयोग logging.config लॉगिंग की विन्यस्त करने में पूरी छूट प्राप्त करने के लिए (नोट: कोड में नीचे मैं सिर्फ basicConfig के साथ शुरू)

इस तरह के दृष्टिकोण एक सुझाई गई पहुंच है और मैं इसके संभावित लाभ के साथ सहमत हैं। उदाहरण के लिए मैं पूरी तरह से योग्य मॉड्यूल नामों का उपयोग कर बाहरी पुस्तकालयों के DEBUG को चालू/बंद कर सकता हूं (नामकरण पदानुक्रम जो कोड में पहले से मौजूद है)।

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

यह सब ठीक है, लेकिन यहाँ वर्णित के रूप में छानने

Filter instances are used to perform arbitrary filtering of LogRecords. 

Loggers and Handlers can optionally use Filter instances to filter 
records as desired. The base filter class only allows events which are 
below a certain point in the logger hierarchy. For example, a filter 
initialized with "A.B" will allow events logged by loggers "A.B", 
"A.B.C", "A.B.C.D", "A.B.D" etc. but not "A.BB", "B.A.B" etc. If 
initialized with the empty string, all events are passed. 

अभी भी मेरे लिए काम नहीं कर रहा है।

मेरा अनुमान है कि LogRecords प्रचार के पीछे विवरण समझने की मेरी कमी समस्या का स्रोत है। logging flow-chart

उदाहरण कोड

मैं दो मॉड्यूल उदाहरण के साथ शुरू, प्रत्येक का उपयोग करता है इसके मालिक: कोड के कूदने से पहले मैं यहाँ (cookbook tutorial से जो पहली बार में मैं किसी भी तरह विफल रही है तुरंत खोज के लिए) एक प्रवाह चार्ट दिखाना चाहते हैं नामित लकड़हारा:

bar.py:

import logging 


logger = logging.getLogger(__name__) 


def bar(): 
    logger.info('hello from ' + __name__) 

foo।py:

import logging 
from bar import bar, logger as bar_logger 


logger = logging.getLogger('foo') 


def foo(): 
    logger.info('hello from foo') 


if __name__ == '__main__': 
    # Trivial logging setup. 
    logging.basicConfig(
     level=logging.INFO, 
     format='%(asctime)s %(name)-20s %(levelname)-8s %(message)s', 
     datefmt='%m-%d %H:%M' 
    ) 
    # Do some work. 
    foo() 
    bar() 

लॉगिंग पहले logging.basicConfig साथ निर्माण किया है (रूट लकड़हारा, जो import logging के बाद __main__ द्वारा बनाया गया था एक धारा हैंडलर इसे से जुड़ी हो जाता है, ताकि हम एक कंसोल है), सक्षम है (संबंधित लॉगर .disabled = गलत) और दोनों मॉड्यूल लॉगर्स बार और foo रूट लॉगर पर प्रचारित करें (इसलिए हमारे पास कुल में तीन लॉगर्स हैं)।

print logger 
print bar_logger 
print logging.root 
# Prints 
#<logging.Logger object at 0x7f0cfd520790> 
#<logging.Logger object at 0x7f0cfd55d710> 
#<logging.RootLogger object at 0x7f0cfd520550> 

वास्तविक उपयोगकेस तब होता है जब बार एक बाहरी पुस्तकालय है जिसे मैं चुप करना चाहता हूं (फ़िल्टर आउट)।

यह कैसे काम करता है, लेकिन "मैं" यह

# Don't like it 
bar_logger.addFilter(logging.Filter('foo')) 
# Do some work. 
foo() 
bar() 

प्रिंट केवल

06-24 14:08 foo     INFO  hello from foo 

मैं कैसे यह काम करने के लिए

मैं इसे बाहर फिल्टर करने के लिए केंद्रीय रूप से चाहते हैं पसंद नहीं है , यानी मेरे रूट लॉगर w/o में सभी बाहरी मॉड्यूल के सभी लॉगर्स आयात करने की आवश्यकता है।

logging.root.addFilter(logging.Filter('foo')) 

प्रिंट

06-24 14:17 foo     INFO  hello from foo 
06-24 14:17 bar     INFO  hello from bar 

वहाँ कुछ स्पष्ट/बेवकूफ गलती है कि मैं याद आती है होना चाहिए: मैं बार लकड़हारा से कोई संदेश नहीं करना चाहती। हे, लेकिन एसओ, लोगों पर संक्षेप में संक्षेप में इसे खोजने का बेहतर तरीका क्या है? ;-)

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

प्रवाह चार्ट आरेख आप पोस्ट में

handler.addFilter(logging.Filter('foo')) 

स्पष्टीकरण, नोटिस देखते हैं:

+0

इसके अलावा http://stackoverflow.com/questions/7507825/python-complete-example-of-dict-for चेकआउट -logging-config-dictconfig –

+0

आपको जटिल लॉगिंग मामलों के लिए *** logging_tree *** आत्मनिरीक्षण बहुत अंतर्दृष्टि भी मिल सकती है https://pypi.python.org/pypi/logging_tree –

+0

लॉगिंग के बारे में मेरे एक कॉलेग्यू से ग्रेट टिप सामान्य http://pythonsweetness.tumblr.com/post/67394619015/use-of-logging-package-from-within-a-library –

उत्तर

30

समाधान

फिल्टर हैंडलर के लिए नहीं बल्कि लकड़हारा से जोड़े दो हीरे:

  • क्या लॉगर से जुड़ा एक फ़िल्टर रिकॉर्ड को अस्वीकार करता है?
  • क्या से जुड़ा एक फ़िल्टर हैडर रिकॉर्ड को अस्वीकार करता है?

इस प्रकार, आपको LogRecord को अस्वीकार करने पर दो स्विंग मिलते हैं। यदि आप रूट लॉगर पर फ़िल्टर संलग्न करते हैं, लेकिन लॉगऑकॉर्ड को, foo या bar loggers के माध्यम से शुरू करें, तो LogRecord फ़िल्टर नहीं किया जाता है क्योंकि LogRecord foo या bar loggers के माध्यम से स्वतंत्र रूप से गुजरता है और रूट लॉगर फ़िल्टर कभी भी प्रवेश नहीं करता है प्ले। (प्रवाह चार्ट फिर से देखें।)

इसके विपरीत, basicConfig द्वारा परिभाषित StreamHandler किसी भी LogRecord पास को फ़िल्टर करने में सक्षम है।

तो: बल्कि लकड़हारा से हैंडलर के लिए फ़िल्टर जोड़ें:

# foo.py 
import logging 
import bar 

logger = logging.getLogger('foo') 

def foo(): 
    logger.info('hello from foo') 

if __name__ == '__main__': 
    # Trivial logging setup. 
    logging.basicConfig(
     level=logging.INFO, 
     format='%(asctime)s %(name)-20s %(levelname)-8s %(message)s', 
     datefmt='%m-%d %H:%M') 
    for handler in logging.root.handlers: 
     handler.addFilter(logging.Filter('foo')) 

    foo() 
    bar.bar() 

पैदावार

06-24 09:17 foo     INFO  hello from foo 

आप वालों जिसका नाम foo या bar साथ शुरू होता है से प्रवेश करने की अनुमति देना चाहते हैं , लेकिन किसी भी अन्य लॉगर्स से नहीं, आप इस तरह एक श्वेतसूची फ़िल्टर बना सकते हैं:

import logging 
foo_logger = logging.getLogger('foo') 
bar_logger = logging.getLogger('bar') 
baz_logger = logging.getLogger('baz') 

class Whitelist(logging.Filter): 
    def __init__(self, *whitelist): 
     self.whitelist = [logging.Filter(name) for name in whitelist] 

    def filter(self, record): 
     return any(f.filter(record) for f in self.whitelist) 

logging.basicConfig(
    level=logging.INFO, 
    format='%(asctime)s %(name)-20s %(levelname)-8s %(message)s', 
    datefmt='%m-%d %H:%M') 
for handler in logging.root.handlers: 
    handler.addFilter(Whitelist('foo', 'bar')) 

foo_logger.info('hello from foo') 
# 06-24 09:41 foo     INFO  hello from foo 
bar_logger.info('hello from bar') 
# 06-24 09:41 bar     INFO  hello from bar 
baz_logger.info('hello from baz') 
# No output since Whitelist filters if record.name not begin with 'foo' or 'bar' 

और इसी तरह, आप इस के साथ लकड़हारा के नाम काली सूची में डाल सकता है:

class Blacklist(Whitelist): 
    def filter(self, record): 
     return not Whitelist.filter(self, record) 
+0

काम करता है और अधिक लचीलापन की अनुमति देता है! बहुत अच्छा। –

+0

मुझे लगता है कि आखिरकार एप्लिकेशन पर्याप्त परिष्कृत है (जैसे django) में लॉगिंग.config.dictConfig (डिफ़ॉल्ट के लिए) और logging.config.fileConfig (उपयोगकर्ता टेक्स्ट फ़ाइल अनुकूलन के लिए) के साथ एक उदाहरण होना चाहिए, ताकि सभी बहुत अच्छी तरह से फिट हो जाएं लॉगिंग का उपयोग करने का मेरा विचार। कस्टम कारखानों के लिए '()' नोटेशन का उपयोग करके वहां व्हाइटलिस्ट को इंजेक्ट कर सकते हैं। फिर से Thnx! –

+1

@YauhenYakimovich: संपादन के लिए धन्यवाद। – unutbu

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