2009-02-07 11 views
28

आज मैं एक पायथन परियोजना के बारे में सोच रहा था जिसे मैंने एक साल पहले लिखा था, जहां मैंने logging का उपयोग बड़े पैमाने पर किया था। मुझे लगता है कि ओवरहेड (hotshot संकेत दिया गया है कि यह मेरी सबसे बड़ी बाधाओं में से एक था) के भीतर आंतरिक-लूप-जैसी परिदृश्यों (90% कोड) में बहुत से लॉगिंग कॉल पर टिप्पणी करना है।मैं उन्हें बिना टिप्पणी किए पाइथन लॉगिंग कॉल कैसे रोक सकता हूं?

मैं अब आश्चर्य हो, तो कुछ विहित रास्ता प्रोग्राम के रूप में टिप्पणी और हर समय uncommenting बिना पायथन अनुप्रयोगों में प्रवेश कॉल बाहर पट्टी। मैं आप इस और लक्ष्य केवल कोड वस्तुओं है कि बाधाओं उत्पन्न कर रहे हैं की तरह कुछ करने के लिए निरीक्षण/रखता या बाईटकोड हेरफेर इस्तेमाल कर सकते हैं लगता है कि। इस तरह, आप एक के बाद संकलन कदम के रूप में एक जोड़तोड़ जोड़ सकते हैं और एक केंद्रीकृत विन्यास फाइल का उपयोग करें, तो जैसे:

[Leave ERROR and above] 
my_module.SomeClass.method_with_lots_of_warn_calls 

[Leave WARN and above] 
my_module.SomeOtherClass.method_with_lots_of_info_calls 

[Leave INFO and above] 
my_module.SomeWeirdClass.method_with_lots_of_debug_calls 
बेशक

, आप इसे किफ़ायत से और शायद का उपयोग करने के साथ प्रति-समारोह के विवरण का स्तर चाहते हैं - केवल कोड ऑब्जेक्ट्स के लिए जिन्होंने logging को एक बाधा बनने के लिए दिखाया है। किसी को इस तरह कुछ पता है?

नोट: कुछ चीजें है कि गतिशील टाइपिंग और लेट बाइंडिंग के कारण इस और अधिक कठिन एक performant ढंग से करने के लिए कर रहे हैं। उदाहरण के लिए, debug नामक विधि के लिए किसी भी कॉल को if not isinstance(log, Logger) से लपेटा जाना पड़ सकता है। किसी भी मामले में, मुझे लगता है कि सभी मामूली विवरणों को दूर किया जा सकता है, या तो सज्जन के समझौते या कुछ रन-टाइम जांच द्वारा। :-)

+0

आप एक ही रूट स्तर लकड़हारा का उपयोग करें? यानी, logging.getLogger()? यदि ऐसा है, तो आपको पहले इसे ठीक करने की आवश्यकता है। यदि नहीं, तो कृपया उन मॉड्यूल में कुछ getLogger कॉल प्रदान करें। –

+0

@ एसएलओटी: मैं प्रति-मॉड्यूल आधार पर LOG = logging.getLogger (__ name__) का उपयोग करता हूं, फिर LOG.debug (msg) और जैसा कॉल करता हूं। मैं वास्तव में नहीं देखता कि यह कैसे प्रासंगिक है, हालांकि। – cdleary

उत्तर

20

logging.disable का उपयोग करने के बारे में क्या?

मुझे यह भी पता चला है कि लॉगिंग संदेश महंगा बनाने के लिए मुझे logging.isEnabledFor का उपयोग करना पड़ा।

+0

logging.isEnabledFor काम कर सकता है, क्योंकि मुझे लगता है कि यह समय देखने वाले लॉगर विधियों में कॉल था। सशर्त निर्माण करने के लिए यह कष्टप्रद है, इस तथ्य के बावजूद मुझे इसे एक संभावित समाधान के रूप में पसंद है। मैं पुराने कोड बेस को खोदने की कोशिश करने जा रहा हूं और देख रहा हूं कि यह काम करता है या नहीं। – cdleary

+1

जैसा कि यह पता चला है, यह ठीक है कि कैसे 'Logger.debug' लागू किया गया है: http://svn.python.org/view/python/tags/r26/Lib/logging/__init__.py?view=markup – cdleary

+1

असल में, 'लॉगिंग' कोड को और आगे देखकर, यह शायद मुझे अनुकूलन की आवश्यकता है। 'getEffectiveLevel' लॉगर पदानुक्रम को पार करता है, जबकि' अक्षम 'उस ट्रैवर्सल को खत्म कर देगा। धन्यवाद! – cdleary

2

एक अपूर्ण शॉर्टकट के रूप में, MiniMock जैसे कुछ मॉड्यूल में logging को मॉड्यूल करने के बारे में कैसे?

उदाहरण के लिए, यदि my_module.py था:

from minimock import Mock 
import my_module 
my_module.logging = Mock('logging') 
c = my_module.C() 

आप केवल की प्रारंभिक आयात करने से पहले एक बार ऐसा करने, होगा:

import logging 
class C(object): 
    def __init__(self, *args, **kw): 
     logging.info("Instantiating") 

आप के साथ my_module के आपके उपयोग की जगह लेंगे मॉड्यूल।

स्तर विशिष्ट व्यवहार हो रही विशिष्ट विधियों मजाक, या logging.getLogger कुछ तरीकों नपुंसक और दूसरों असली logging मॉड्यूल को सौंपने के साथ एक नकली वस्तु वापसी होने से काफी सरल हो जाएगा।

अभ्यास में, आप शायद सरल और तेजी से कुछ के साथ MiniMock बदलना चाहते हैं चाहते हैं; कम से कम कुछ जो stdout के लिए उपयोग मुद्रित नहीं करता है! बेशक, इस मॉड्यूल बी से logging का आयात मॉड्यूल एक की समस्या को संभाल नहीं करता है (और इसलिए एक भी बी के लॉग विवरण के स्तर को आयात करने) ...

यह कभी नहीं होगा के रूप में तेजी से पर लॉग बयान के रूप में नहीं चल रहा सभी, लेकिन लॉगिंग मॉड्यूल की गहराई में सभी तरह से जाने से कहीं अधिक तेज होना चाहिए केवल यह पता लगाने के लिए कि यह रिकॉर्ड सभी के बाद लॉग नहीं होना चाहिए।

+0

यह वास्तव में बाइटकोड मैनिपुलेशन की तुलना में बहुत अधिक सना लगता है, क्योंकि बाइटकोड मैनिपुलेशन तकनीकों को वीएम में बंदरगाह नहीं होना चाहिए। एकमात्र मुद्दा जो मैं देखता हूं वह यह है कि आप केवल * जो * विधि को स्टैक ट्रेस निरीक्षण द्वारा बुलाया जाता है, जो धीमा होगा, अगर मुझे गलत नहीं लगता है। – cdleary

+0

आह, ठीक है .. तो मैं सोच रहा था कि नकली वस्तुएं बहुत गूंगा होंगी, देखभाल नहीं करेंगे (या जानना) जहां से उन्हें बुलाया गया था। आपके पास केवल प्रति-मॉड्यूल कॉन्फ़िगरेशन ग्रैन्युलरिटी होगी, प्रति फ़ंक्शन नहीं। नकली वस्तुओं को इंजेक्ट करने के लिए आपके कौन से मॉड्यूल का चयन करना आपकी एकमात्र लचीलापन है जिसे मैं डरता हूं। –

1

आप कुछ इस तरह की कोशिश कर सकते:

# Create something that accepts anything 
class Fake(object): 
    def __getattr__(self, key): 
     return self 
    def __call__(self, *args, **kwargs): 
     return True 

# Replace the logging module 
import sys 
sys.modules["logging"] = Fake() 

यह अनिवार्य रूप बदल देता है (या शुरू में में भर जाता है) Fake का एक उदाहरण जो केवल कुछ भी में ले जाता है के साथ प्रवेश मॉड्यूल के लिए अंतरिक्ष। लॉगिंग मॉड्यूल को कहीं भी इस्तेमाल करने का प्रयास करने से पहले आपको उपरोक्त कोड (केवल एक बार!) चलाना होगा।यहाँ एक परीक्षण है:

import logging 

logging.basicConfig(level=logging.DEBUG, 
        format='%(asctime)s %(levelname)-8s %(message)s', 
        datefmt='%a, %d %b %Y %H:%M:%S', 
        filename='/temp/myapp.log', 
        filemode='w') 
logging.debug('A debug message') 
logging.info('Some information') 
logging.warning('A shot across the bows') 
ऊपर के साथ

, सभी में कुछ भी नहीं है, लॉग इन के रूप में उम्मीद की जा करने के लिए किया गया था।

def doLogging(logTreshold): 
    def logFunction(aFunc): 
     def innerFunc(*args, **kwargs): 
      if LOGLEVEL >= logTreshold: 
       print ">>Called %s at %s"%(aFunc.__name__, time.strftime("%H:%M:%S")) 
       print ">>Parameters: ", args, kwargs if kwargs else "" 
      try: 
       return aFunc(*args, **kwargs) 
      finally: 
       print ">>%s took %s"%(aFunc.__name__, time.strftime("%H:%M:%S")) 
     return innerFunc 
    return logFunction 

आपको बस प्रत्येक मॉड्यूल में LogLevel निरंतर घोषित करने के लिए है (या बस विश्व स्तर पर और बस सभी मॉड्यूल में आयात) और:

+0

तो आपके पास प्रति मॉड्यूल या स्तर से लॉगिंग को चुनने या बंद करने का कोई तरीका नहीं है? –

+0

यह चीजों को गति भी नहीं देता है ... – radtek

1

मैं कुछ फैंसी प्रवेश डेकोरेटर, या उनमें से एक गुच्छा का उपयोग करेंगे तो आप इसे इस तरह उपयोग कर सकते हैं:

@doLogging(2.5) 
def myPreciousFunction(one, two, three=4): 
    print "I'm doing some fancy computations :-)" 
    return 

और अगर LogLevel 2.5 से कम है तो आप इस तरह उत्पादन मिल जाएगा:

>>Called myPreciousFunction at 18:49:13 
>>Parameters: (1, 2) 
I'm doing some fancy computations :-) 
>>myPreciousFunction took 18:49:13 

जैसा कि आप देख सकते हैं, kwargs के बेहतर संचालन के लिए कुछ काम की आवश्यकता है, इसलिए यदि वे मौजूद हैं तो डिफ़ॉल्ट मान मुद्रित किए जाएंगे, लेकिन यह एक और सवाल है।

आप शायद कच्चे print बयानों के बजाय कुछ logger मॉड्यूल का उपयोग करना चाहिए, लेकिन मैं डेकोरेटर विचार पर ध्यान केंद्रित करने और कोड बहुत लंबा बनाने से बचना चाहते थे।

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

def doLogging(logThreshold, outStream=sys.stdout): 
     ..... 
     print >>outStream, ">>Called %s at %s" etc. 

और प्रति-फ़ंक्शन आधार पर परिभाषित लॉग फ़ाइलों का उपयोग करें।

+0

मैं 'लॉगिंग' मॉड्यूल का उपयोग कर * अंदर * विधि से चीजें लॉग करता हूं - आपका दृष्टिकोण केवल उन चीजों को लॉग कर सकता है जो बाहरी रूप से दिखाई दे रहे हैं (तर्क, kwargs, वापसी मूल्य, और निष्पादन समय)। – cdleary

+0

आपने प्रति-कार्य ग्रैन्युलरिटी पर लॉगिंग का उपयोग करने के बारे में लिखा है, और आपका छद्म कोड उदाहरण भी इस तरह कुछ संकेत देता है। मेरा दृष्टिकोण बढ़ाया जा सकता है - आप अपने फ़ंक्शन में अतिरिक्त कीवर्ड पैरामीटर जोड़ सकते हैं। और वह अतिरिक्त पैरामीटर एक लॉगर या डमी ऑब्जेक्ट होगा, जो सजावटी द्वारा प्रदान किया गया है :-) – Abgan

+0

कोई आदर्श समाधान नहीं है, मैं सहमत हूं, लेकिन - सजावटी अत्यधिक एक्स्टेंसिबल नहीं हैं? – Abgan

1

यह मेरे प्रोजेक्ट में भी एक मुद्दा है - लॉगिंग लगातार प्रोफाइलर रिपोर्ट पर समाप्त होता है।

मैंने पाइफलेक्स (http://github.com/kevinw/pyflakes) के कांटा में पहले _ast मॉड्यूल का उपयोग किया है ... और लॉगिंग विधियों पर कॉल करने से पहले गार्ड को निरीक्षण और इंजेक्ट करने के लिए यह निश्चित रूप से संभव है कि आप अपने प्रश्न में सुझाव दें। आपकी स्वीकृत चेतावनी है कि आपको कुछ रनटाइम प्रकार की जांच करना होगा)। एक साधारण उदाहरण के लिए http://pyside.blogspot.com/2008/03/ast-compilation-from-python.html देखें।

संपादित करें: मैं बस अपना planetpython.org फ़ीड पर MetaPython देखा - उदाहरण के उपयोग के मामले में आयात समय लॉग बयान को हटा रहा है।

हो सकता है कि सबसे अच्छा समाधान किसी एक सी मॉड्यूल के रूप में प्रवेश reimplement करने के लिए होगा, लेकिन मैं पहली बार में इस तरह के एक ... अवसर कूदने के लिए नहीं होगा: पी

5

मैं भी ज़ोर देखा है इस्तेमाल किया इस फैशन में।

assert logging.warn('disable me with the -O option') is None 

(मेरा अनुमान है कि यह है कि चेतावनी दी है हमेशा कोई भी देता है ..यदि नहीं, तो आप एक AssertionError

मिल जाएगा लेकिन वास्तव में यह सिर्फ ऐसा करने का एक अजीब तरीका है:

if __debug__: logging.warn('disable me with the -O option') 

जब आप -O विकल्प के साथ यह है कि लाइन के साथ एक स्क्रिप्ट चलाने, लाइन होगा अनुकूलित .pyo कोड से हटा दिया जाना चाहिए। तो इसके बजाय, आप अपने खुद चर, निम्नलिखित में की तरह था, तो आप, एक सशर्त कि हमेशा निष्पादित किया जाता है (कोई बात नहीं क्या मूल्य चर रहा है) होगा, हालांकि एक सशर्त एक समारोह कॉल की तुलना में तेज अमल करना चाहिए:

my_debug = True 
... 
if my_debug: logging.warn('disable me by setting my_debug = False') 

इसलिए यदि डीबग की मेरी समझ सही है, तो यह अनावश्यक लॉगिंग कॉल से छुटकारा पाने के लिए एक अच्छा तरीका प्रतीत होता है। फ्लिपसाइड यह है कि यह आपके सभी आवेषणों को भी अक्षम करता है, इसलिए यदि आपको आवेषण की आवश्यकता है तो यह एक समस्या है।

+0

हाँ, हर कॉल के सामने एक जोर डालना बहुत बदसूरत है। सबकुछ के सामने 'if_debug'' डालना समान रूप से अवांछित और सुरुचिपूर्ण है - मैं कुछ स्वचालित रूप से उन्हें पट्टी/संशोधित करने की उम्मीद कर रहा था। :-(इसके अलावा, किसी भी को स्पष्ट तुलना के लिए हमेशा 'कोई नहीं' का उपयोग करें। :-) – cdleary

0

मुझे 'if __debug_' समाधान पसंद है, सिवाय इसके कि इसे प्रत्येक कॉल के सामने डालना थोड़ा विचलित और बदसूरत है। मुझे यह वही समस्या थी और एक स्क्रिप्ट लिखकर इसे खत्म कर दिया गया जो स्वचालित रूप से आपकी स्रोत फ़ाइलों को पार्स करता है और पास स्टेटमेंट्स के साथ लॉगिंग स्टेटमेंट्स को प्रतिस्थापित करता है (और लॉगिंग स्टेटमेंट की प्रतियां टिप्पणी करता है)। यह इस रूपांतरण को पूर्ववत भी कर सकता है।

मैं इसका उपयोग तब करता हूं जब मैं उत्पादन वातावरण में नया कोड तैनात करता हूं, जब बहुत सारे लॉगिंग स्टेटमेंट्स होते हैं जिन्हें मुझे उत्पादन सेटिंग में आवश्यकता नहीं होती है और वे प्रदर्शन को प्रभावित कर रहे हैं।

आप स्क्रिप्ट पा सकते हैं: http://dound.com/2010/02/python-logging-performance/

1

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

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

मुझे लगता है कि सजावटी विचार एक अच्छा है। लॉगिंग की आवश्यकता वाले कार्यों को लपेटने के लिए आप एक सजावट लिख सकते हैं। फिर, रनटाइम वितरण के लिए, सजावटी को "नो-ऑप" में बदल दिया जाता है जो डिबगिंग कथन को समाप्त करता है।

जॉन आर

5

उपयोग pypreprocessor

कौन सा भी PYPI (Python Package Index) पर पाया जा सकता है और पिप का उपयोग कर प्राप्त किया जा।

from pypreprocessor import pypreprocessor 

pypreprocessor.parse() 

#define nologging 

#ifdef nologging 
...logging code you'd usually comment out manually... 
#endif 

अनिवार्य रूप से, पूर्वप्रक्रमक जिस तरह से आप मैन्युअल रूप से पहले ही कर रहे थे बाहर टिप्पणी कोड:

यहाँ एक मूल उपयोग उदाहरण है। यह आपके द्वारा निर्धारित परिभाषा के आधार पर सस्ती रूप से फ्लाई पर करता है।

आप सभी प्रीप्रोसेसर निर्देशों को भी हटा सकते हैं और आयात और पार्स() कथन के बीच 'pypreprocessor.removeMeta = True' जोड़कर पोस्टप्रोसेस्ड कोड से कोड को टिप्पणी कर सकते हैं।

बाइटकोड आउटपुट (।पीईसी) फ़ाइल में अनुकूलित आउटपुट होगा।

साइड नोट: pypreprocessor python2x और python3k के साथ संगत है।

अस्वीकरण: मैं पाइप्रप्रोसेसर का लेखक हूं।

+0

मैं आमतौर पर प्रीप्रोसेसर निर्देशों का एक बड़ा प्रशंसक नहीं हूं। मैं उस दृष्टिकोण पर शून्य के किनारे गया हूं, जब यूनिक्स ने किसी भी अन्य यूनिक्स के समान चीजें नहीं कीं, और यह सुंदर नहीं थी। ओटीओएच, यह शानदार है कि सुविधा को बाहरी मॉड्यूल के रूप में जोड़ा जा सकता है। और कुछ मामलों में ... यह वही हो सकता है जो आपको चाहिए। –

+0

@ जोनाथन मैं भी नहीं हूं लेकिन कुछ विशिष्ट मामले हैं जहां यह रखरखाव पर भारी कटौती कर सकता है। मैंने मूल रूप से इसे बनाया है, इसलिए मैं एक ही फाइलों (एकाधिक संस्करणों के समानांतर विकास) में दोनों py2x और py3x कोड को चलाने में सक्षम होगा, लेकिन प्रीप्रोसेसर भी चलाने से पहले लेक्सर कोड को अमान्य कर देता है। इन मामलों के मामलों के लिए इसे बेकार ढंग से काम करना चाहिए। यह अनिवार्य रूप से केवल खुद को खुलता है, कोड पढ़ता है, अनावश्यक कोड शाखाओं को टिप्पणियां देता है, और संशोधित आउटपुट चलाता है। बहुत हैकी लेकिन यह आश्चर्यजनक रूप से अच्छी तरह से काम करता है खासकर जब से आप पोस्टप्रोसेस्ड कोड को फ़ाइल के रूप में भी सहेज सकते हैं। –

+0

'dedeine nologging' ब्लॉक में अपना कोड लपेटकर मुझे 'NameError: वैश्विक नाम' लॉगिंग 'परिभाषित नहीं किया गया है' – radtek

1

मैं वर्तमान में एक प्रोजेक्ट कर रहा हूं जो पांडा पुस्तकालय का उपयोग कर डेटा विश्लेषण API के लिए तर्क और निष्पादन समय के परीक्षण के लिए व्यापक लॉगिंग का उपयोग करता है।

मुझे इस स्ट्रिंग को इसी तरह की चिंता के साथ मिला - उदा। भले ही logging.basicConfig स्तर स्तर पर सेट है logging.debug बयान पर भूमि के ऊपर क्या है = logging.WARNING

मैं बाहर टिप्पणी या तैनाती से पहले डीबग लॉगिंग uncomment के लिए निम्न स्क्रिप्ट लिखने का सहारा लिया:

import os 
import fileinput 

comment = True 

# exclude files or directories matching string 
fil_dir_exclude = ["__","_archive",".pyc"] 

if comment : 
    ## Variables to comment 
    source_str = 'logging.debug' 
    replace_str = '#logging.debug' 
else : 
    ## Variables to uncomment 
    source_str = '#logging.debug' 
    replace_str = 'logging.debug' 

# walk through directories 
for root, dirs, files in os.walk('root/directory') : 
    # where files exist 
    if files: 
     # for each file 
     for file_single in files : 
      # build full file name 
      file_name = os.path.join(root,file_single) 
      # exclude files with matching string 
      if not any(exclude_str in file_name for exclude_str in fil_dir_exclude) : 
       # replace string in line 
       for line in fileinput.input(file_name, inplace=True): 
        print "%s" % (line.replace(source_str, replace_str)), 

यह एक फ़ाइल प्रत्यावर्तन कि मापदंड की एक सूची के आधार पर फ़ाइलें शामिल नहीं है और जगह में एक एक जवाब के आधार पर जगह प्रदर्शन करती है यहाँ पाया जाता है: Search and replace a line in a file in Python

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

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