2009-06-10 9 views
11

पर रीडायरेक्ट करने के लिए रीडायरेक्ट कर रहा है तो अभी हमारे पास बहुत सारी पायथन स्क्रिप्ट हैं और हम उन्हें मजबूत करने और फिक्स और अनावश्यकताओं को मजबूत करने की कोशिश कर रहे हैं। उन चीजों में से एक जो हम करने की कोशिश कर रहे हैं, यह सुनिश्चित करना है कि सभी sys.stdout/sys.stderr पायथन लॉगिंग मॉड्यूल में जाते हैं।sys.stdout को python लॉगिंग

अब मुख्य बात यह है कि हम चाहते हैं निम्नलिखित मुद्रित: अजगर त्रुटि संदेशों में से सभी में काफी

[<ERROR LEVEL>] | <TIME> | <WHERE> | <MSG> 

अब सभी sys.stdout/sys.stderr msgs [स्तर के प्रारूप में हैं ] - एमएसजी, जो सभी sys.stdout/sys.stderr का उपयोग कर लिखे गए हैं। मैं ठीक से पार्स कर सकता हूं, मेरे sys.stdout wrapper में और sys.stderr wrapper में। फिर विश्लेषण किए गए इनपुट के आधार पर संबंधित लॉगिंग स्तर पर कॉल करें।

तो मूल रूप से हमारे पास foo नामक एक पैकेज है, और लॉग नामक एक उप-पैकेज है।

def initLogging(default_level = logging.INFO, stdout_wrapper = None, \ 
       stderr_wrapper = None): 
    """ 
     Initialize the default logging sub system 
    """ 
    root_logger = logging.getLogger('') 
    strm_out = logging.StreamHandler(sys.__stdout__) 
    strm_out.setFormatter(logging.Formatter(DEFAULT_LOG_TIME_FORMAT, \ 
              DEFAULT_LOG_TIME_FORMAT)) 
    root_logger.setLevel(default_level) 
    root_logger.addHandler(strm_out) 

    console_logger = logging.getLogger(LOGGER_CONSOLE) 
    strm_out = logging.StreamHandler(sys.__stdout__) 
    #strm_out.setFormatter(logging.Formatter(DEFAULT_LOG_MSG_FORMAT, \ 
    #          DEFAULT_LOG_TIME_FORMAT)) 
    console_logger.setLevel(logging.INFO) 
    console_logger.addHandler(strm_out) 

    if stdout_wrapper: 
     sys.stdout = stdout_wrapper 
    if stderr_wrapper: 
     sys.stderr = stderr_wrapper 


def cleanMsg(msg, is_stderr = False): 
    logy = logging.getLogger('MSG') 
    msg = msg.rstrip('\n').lstrip('\n') 
    p_level = r'^(\s+)?\[(?P<LEVEL>\w+)\](\s+)?(?P<MSG>.*)$' 
    m = re.match(p_level, msg) 
    if m: 
     msg = m.group('MSG') 
     if m.group('LEVEL') in ('WARNING'): 
      logy.warning(msg) 
      return 
     elif m.group('LEVEL') in ('ERROR'): 
      logy.error(msg) 
      return 
    if is_stderr: 
     logy.error(msg) 
    else: 
     logy.info(msg) 

class StdOutWrapper: 
    """ 
     Call wrapper for stdout 
    """ 
    def write(self, s): 
     cleanMsg(s, False) 

class StdErrWrapper: 
    """ 
     Call wrapper for stderr 
    """ 
    def write(self, s): 
     cleanMsg(s, True) 

अब हम उदाहरण के लिए हमारे लिपियों में से एक में यह कहेंगे:

import foo.log 
foo.log.initLogging(20, foo.log.StdOutWrapper(), foo.log.StdErrWrapper()) 
sys.stdout.write('[ERROR] Foobar blew') 

कौन सा एक त्रुटि लॉग संदेश में परिवर्तित किया जाएगा __init__.py हम निम्नलिखित परिभाषित करते हैं। जैसा:

[ERROR] | 20090610 083215 | __init__.py | Foobar Blew 

अब समस्या यह है कि जब हम, मॉड्यूल जहां त्रुटि संदेश लॉग इन किया गया था अब __init__ है जो पूरा उद्देश्य धरा (foo.log.__init__.py फ़ाइल के अनुरूप)।

मैंने stderr/stdout ऑब्जेक्ट्स की गहरी कॉपी/उथली कॉपी करने की कोशिश की, लेकिन यह कुछ भी नहीं करता है, यह अभी भी मॉड्यूल का संदेश __init__.py में हुआ था। मैं इसे कैसे बना सकता हूं ताकि ऐसा न हो?

उत्तर

6

समस्या यह है कि लॉगिंग मॉड्यूल कॉल स्टैक को एक परत को देख रहा है, जिसे यह कहने के लिए कहा जाता है, लेकिन अब आपका फ़ंक्शन उस बिंदु पर एक मध्यवर्ती परत है (हालांकि मुझे लगता है कि यह cleanMsg की रिपोर्ट करने की अपेक्षा नहीं करता था, __init__, वैसे ही जहां आप लॉग() में कॉल कर रहे हैं)। इसके बजाए, आपको दो स्तरों पर जाने की आवश्यकता है, या फिर आपका कॉलर लॉग संदेश में कौन है। आप इसे स्टैक फ्रेम का निरीक्षण करके और कॉलिंग फ़ंक्शन को पकड़कर, संदेश में डालने के द्वारा ऐसा कर सकते हैं। एन फ्रेम ऊपर दिखेगा

import inspect 
f = inspect.currentframe(N) 

, और आप फ्रेम सूचक लौट:

अपने बुला फ्रेम खोजने के लिए, आप का निरीक्षण मॉड्यूल का उपयोग कर सकते हैं। यानी आपका तत्काल कॉलर वर्तमान फ्रेम (1) है, लेकिन यदि यह stdout.write विधि है तो आपको एक और फ्रेम जाना होगा। एक बार आपके पास कॉलिंग फ्रेम हो जाने पर, आप निष्पादन कोड ऑब्जेक्ट प्राप्त कर सकते हैं, और इसके साथ जुड़े फ़ाइल और फ़ंक्शन नाम को देख सकते हैं।उदाहरण के लिए:

code = f.f_code 
caller = '%s:%s' % (code.co_filename, code.co_name) 

तुम भी रूप में इन f_code वस्तुओं की कमी हो सकती, गैर अजगर कोड आप में बुला (। यानी सी कार्य या builtins) को संभालने के लिए कुछ कोड डाल करने के लिए आवश्यकता हो सकती है।

वैकल्पिक रूप से, mikej's answer का पालन करने के बाद, आप लॉगिंग से विरासत में प्राप्त एक कस्टम लॉगर क्लास में एक ही दृष्टिकोण का उपयोग कर सकते हैं। लॉगर जो ओवरराइड को ओवरराइड करता है, कई के बजाय कई फ्रेम को नेविगेट करने के लिए कॉलर।

2

मुझे लगता है कि समस्या यह है कि अपने वास्तविक लॉग संदेश अब, cleanMsg में logy.error और logy.info कॉल बना रहे हैं, इसलिए है कि विधि लॉग संदेशों का स्रोत है और आप के रूप में __init__.py

यह देख रहे हैं आप तो पायथन के lib/logging/__init__.py के स्रोत में देखें, आपको findCaller नामक एक विधि दिखाई देगी जो कि लॉगिंग मॉड्यूल लॉगिंग अनुरोध के कॉलर को प्राप्त करने के लिए उपयोग करता है।
शायद आप व्यवहार को अनुकूलित करने के लिए इसे अपने लॉगिंग ऑब्जेक्ट पर ओवरराइड कर सकते हैं?