पाइथन की लॉगिंग सुविधा में एक कस्टम लॉजवेल कैसे जोड़ें


116

मैं अपने आवेदन के लिए loglevel TRACE (5) रखना चाहूंगा, क्योंकि मुझे नहीं लगता कि debug()यह पर्याप्त है। इसके अतिरिक्त log(5, msg)मुझे जो चाहिए वह नहीं है। मैं पायथन लॉगर में एक कस्टम लॉजेल कैसे जोड़ सकता हूं?

मेरे पास mylogger.pyनिम्नलिखित सामग्री है:

import logging

@property
def log(obj):
    myLogger = logging.getLogger(obj.__class__.__name__)
    return myLogger

अपने कोड में मैं इसे निम्नलिखित तरीके से उपयोग करता हूं:

class ExampleClass(object):
    from mylogger import log

    def __init__(self):
        '''The constructor with the logger'''
        self.log.debug("Init runs")

अब मैं फोन करना चाहूंगा self.log.trace("foo bar")

आपकी सहायता के लिये पहले से ही धन्यवाद।

संपादित करें (8 दिसंबर 2016): मैंने पीएएफ के स्वीकार किए गए उत्तर को बदल दिया है, जो आईएमएचओ , एरिक एस के बहुत अच्छे प्रस्ताव पर आधारित एक उत्कृष्ट समाधान है।

जवाबों:


171

@ एरिक एस।

एरिक एस का जवाब उत्कृष्ट है, लेकिन मैंने प्रयोग द्वारा सीखा कि यह हमेशा नए डिबग स्तर पर लॉग किए गए संदेशों को मुद्रित करने का कारण होगा - लॉग स्तर के लिए सेट किए जाने के बावजूद। इसलिए यदि आप एक नए स्तर की संख्या बनाते हैं 9, यदि आप कॉल करते हैं setLevel(50), तो निचले स्तर के संदेश गलत तरीके से मुद्रित होंगे।

ऐसा होने से रोकने के लिए, आपको "debugv" फ़ंक्शन के अंदर एक और लाइन की आवश्यकता है ताकि यह जांचा जा सके कि प्रश्न में लॉगिंग स्तर वास्तव में सक्षम है या नहीं।

यदि लॉगिंग स्तर सक्षम है, तो निश्चित उदाहरण

import logging
DEBUG_LEVELV_NUM = 9 
logging.addLevelName(DEBUG_LEVELV_NUM, "DEBUGV")
def debugv(self, message, *args, **kws):
    if self.isEnabledFor(DEBUG_LEVELV_NUM):
        # Yes, logger takes its '*args' as 'args'.
        self._log(DEBUG_LEVELV_NUM, message, args, **kws) 
logging.Logger.debugv = debugv

यदि आप में कोड को देखते class Loggerहैंlogging.__init__.py अजगर 2.7 के लिए, यह सब मानक लॉग कार्यों करना क्या (.critical, .debug, आदि) है।

मैं जाहिर तौर पर प्रतिष्ठा की कमी के लिए दूसरों के जवाबों का जवाब नहीं दे सकता ... उम्मीद है कि एरिक अपनी पोस्ट को अपडेट करेगा यदि वह यह देखता है। =)


7
यह बेहतर उत्तर है क्योंकि यह लॉग स्तर की सही जाँच करता है।
कर्नल पैनिक

2
वर्तमान उत्तर की तुलना में निश्चित रूप से बहुत अधिक जानकारीपूर्ण।
मैड फिजिसिस्ट

4
@pfa जोड़ने के बारे में क्या है logging.DEBUG_LEVEL_NUM = 9ताकि आप उस डिबग स्तर तक पहुँच सकें जहाँ आप अपने कोड में लकड़हारा आयात करते हैं?
एडगरस्टैक

4
निश्चित रूप से इसके बजाय DEBUG_LEVEL_NUM = 9आपको परिभाषित करना चाहिए logging.DEBUG_LEVEL_NUM = 9। इस तरह आप ठीक log_instance.setLevel(logging.DEBUG_LEVEL_NUM)उसी तरह उपयोग कर पाएंगे जैसे आप जानते हैं logging.DEBUGयाlogging.INFO
maQ

यह उत्तर बहुत मददगार रहा है। धन्यवाद pfa और EricS मैं सुझाव देना चाहता हूं कि पूर्णता के लिए दो और कथनों को शामिल किया जाना चाहिए: logging.DEBUGV = DEBUG_LEVELV_NUMऔर logging.__all__ += ['DEBUGV'] दूसरा बहुत महत्वपूर्ण नहीं है, लेकिन पहला आवश्यक है यदि आपके पास कोई कोड है जो गतिशील रूप से लॉगिंग स्तर को समायोजित करता है और आप if verbose: logger.setLevel(logging.DEBUGV)` जैसे कुछ करने में सक्षम होना चाहते हैं
कीथ हनलान

63

मैंने "लैम्ब्डा देखने से बचें" उत्तर लिया और संशोधित करना पड़ा जहां log_at_my_log_level जोड़ा जा रहा था। मैंने यह भी समस्या देखी कि पॉल ने "मुझे यह काम नहीं लगता है। क्या आपको log_at_my_log_level में पहले arg के रूप में लकड़हारे की आवश्यकता नहीं है?" इसने मेरे लिए काम किया

import logging
DEBUG_LEVELV_NUM = 9 
logging.addLevelName(DEBUG_LEVELV_NUM, "DEBUGV")
def debugv(self, message, *args, **kws):
    # Yes, logger takes its '*args' as 'args'.
    self._log(DEBUG_LEVELV_NUM, message, args, **kws) 
logging.Logger.debugv = debugv

7
+1 भी। एक सुरुचिपूर्ण दृष्टिकोण, और इसने पूरी तरह से काम किया। एक महत्वपूर्ण नोट: आपको केवल एक बार, एक एकल मॉड्यूल में ऐसा करने की आवश्यकता है, और यह सभी मॉड्यूल के लिए काम करेगा । आपको "सेटअप" मॉड्यूल आयात करने की भी आवश्यकता नहीं है। इसलिए इसे एक पैकेज में टॉस करें __init__.pyऔर खुश रहें: D
MestreLion

4
@ एरिक एस। आपको इस उत्तर पर एक नज़र डालनी चाहिए: stackoverflow.com/a/13638084/600110
सैम मुसम्मन

1
मैं @SamMussmann से सहमत हूं। मुझे वह उत्तर याद आ गया क्योंकि यह शीर्ष मतदान का उत्तर था।
कर्नल पैनिक

@ Eric S. आपको बिना * args की आवश्यकता क्यों है? अगर मैं ऐसा TypeError: not all arguments converted during string formattingकरता हूं, मुझे मिलता है लेकिन यह ठीक है * के साथ। (पायथन 3.4.3)। यह एक अजगर संस्करण मुद्दा है, या कुछ मुझे याद आ रही है?
पीटर

यह जवाब मेरे काम नहीं आता। 'Logging.debugv' करने की कोशिश में एक त्रुटि मिलती हैAttributeError: module 'logging' has no attribute 'debugv'
एलेक्स

51

उपयोग के अनुभव के एक गुच्छा के साथ मौजूदा सभी उत्तरों को मिलाकर, मुझे लगता है कि मैं उन सभी चीजों की एक सूची के साथ आया हूं, जिन्हें नए स्तर पर पूरी तरह से सहज उपयोग सुनिश्चित करने के लिए किए जाने की आवश्यकता है। नीचे दिए गए चरण मान लेते हैं कि आप TRACEमूल्य के साथ एक नया स्तर जोड़ रहे हैं logging.DEBUG - 5 == 5:

  1. logging.addLevelName(logging.DEBUG - 5, 'TRACE') नए स्तर पर आंतरिक रूप से पंजीकृत होने के लिए आमंत्रित करने की आवश्यकता है ताकि इसे नाम से संदर्भित किया जा सके।
  2. loggingस्थिरता के लिए खुद को एक विशेषता के रूप में नए स्तर को जोड़ने की आवश्यकता है logging.TRACE = logging.DEBUG - 5:।
  3. एक विधि जिसे मॉड्यूल में traceजोड़ने की आवश्यकता है logging। यह सिर्फ तरह व्यवहार करना चाहिए debug, infoआदि
  4. एक विधि जिसे traceवर्तमान में कॉन्फ़िगर किए गए लॉगर वर्ग में जोड़ने की आवश्यकता है। चूंकि यह 100% होने की गारंटी नहीं है logging.Logger, इसलिए logging.getLoggerClass()इसके बजाय उपयोग करें ।

नीचे दिए गए विधि में सभी चरणों का वर्णन किया गया है:

def addLoggingLevel(levelName, levelNum, methodName=None):
    """
    Comprehensively adds a new logging level to the `logging` module and the
    currently configured logging class.

    `levelName` becomes an attribute of the `logging` module with the value
    `levelNum`. `methodName` becomes a convenience method for both `logging`
    itself and the class returned by `logging.getLoggerClass()` (usually just
    `logging.Logger`). If `methodName` is not specified, `levelName.lower()` is
    used.

    To avoid accidental clobberings of existing attributes, this method will
    raise an `AttributeError` if the level name is already an attribute of the
    `logging` module or if the method name is already present 

    Example
    -------
    >>> addLoggingLevel('TRACE', logging.DEBUG - 5)
    >>> logging.getLogger(__name__).setLevel("TRACE")
    >>> logging.getLogger(__name__).trace('that worked')
    >>> logging.trace('so did this')
    >>> logging.TRACE
    5

    """
    if not methodName:
        methodName = levelName.lower()

    if hasattr(logging, levelName):
       raise AttributeError('{} already defined in logging module'.format(levelName))
    if hasattr(logging, methodName):
       raise AttributeError('{} already defined in logging module'.format(methodName))
    if hasattr(logging.getLoggerClass(), methodName):
       raise AttributeError('{} already defined in logger class'.format(methodName))

    # This method was inspired by the answers to Stack Overflow post
    # http://stackoverflow.com/q/2183233/2988730, especially
    # http://stackoverflow.com/a/13638084/2988730
    def logForLevel(self, message, *args, **kwargs):
        if self.isEnabledFor(levelNum):
            self._log(levelNum, message, args, **kwargs)
    def logToRoot(message, *args, **kwargs):
        logging.log(levelNum, message, *args, **kwargs)

    logging.addLevelName(levelNum, levelName)
    setattr(logging, levelName, levelNum)
    setattr(logging.getLoggerClass(), methodName, logForLevel)
    setattr(logging, methodName, logToRoot)

द्वारा उत्तर क्रमबद्ध करें Oldest, और आप सराहना करेंगे कि यह उन सभी का सबसे अच्छा जवाब है!
सर्ज स्ट्रोबोबांट

धन्यवाद। मैंने इस तरह से एक साथ कुछ काम करने में काफी काम किया है और यह क्यूए बहुत मददगार था, इसलिए मैंने कुछ जोड़ने की कोशिश की।
मैड फिजिसिस्ट

1
@PeterDolan। अगर आपको इससे दिक्कत है तो मुझे बताएं। मेरे व्यक्तिगत टूलबॉक्स में मेरे पास एक विस्तारित संस्करण है जो आपको परस्पर विरोधी स्तर की परिभाषाओं को संभालने के लिए कॉन्फ़िगर करने देता है। यह मेरे लिए एक बार आया क्योंकि मैं एक TRACE स्तर जोड़ना पसंद करता हूं, और इसलिए स्फिंक्स के घटकों में से एक है।
मैड फिजिसिस्ट

1
क्या कार्यान्वयन argsमें तारांकन की कमी logForLevelजानबूझकर / आवश्यक है?
क्रिस एल। बार्न्स

1
@Tunisia। यह अनजाने में है। पकड़ने के लिए धन्यवाद।
मैड फिजिसिस्ट

40

यह प्रश्न पुराना है, लेकिन मैंने सिर्फ एक ही विषय को निपटाया है और एक तरीका पाया है जो पहले से ही उल्लेखित है जो मेरे लिए थोड़ा साफ दिखाई देता है। यह 3.4 पर परीक्षण किया गया था, इसलिए मुझे यकीन नहीं है कि पुराने तरीकों में इस्तेमाल किए गए तरीके मौजूद हैं:

from logging import getLoggerClass, addLevelName, setLoggerClass, NOTSET

VERBOSE = 5

class MyLogger(getLoggerClass()):
    def __init__(self, name, level=NOTSET):
        super().__init__(name, level)

        addLevelName(VERBOSE, "VERBOSE")

    def verbose(self, msg, *args, **kwargs):
        if self.isEnabledFor(VERBOSE):
            self._log(VERBOSE, msg, args, **kwargs)

setLoggerClass(MyLogger)

1
यह IMHO का सबसे अच्छा जवाब है, क्योंकि यह बंदर पेटिंग से बचा जाता है। क्या getऔर setLoggerClassवास्तव में क्या करते हैं और उनकी आवश्यकता क्यों है?
मार्को सुल्ला

3
@MarcoSulla वे पायथन के लॉगिंग मॉड्यूल के हिस्से के रूप में प्रलेखित हैं। डायनामिक सब-क्लासिंग, मेरा मानना ​​है कि इस लाइब्रेरी का उपयोग करते समय किसी ने अपने स्वयं के llogger चाहा है। यह MyLogger तब दोनों को मिलाकर मेरी कक्षा का एक उप-वर्ग बन जाएगा।
क्रैकरजैक

यह इस चर्चा में प्रस्तुत समाधान के समान है कि क्या TRACEडिफ़ॉल्ट लॉगिंग लाइब्रेरी में एक स्तर जोड़ें । +1
IMP1

18

आंतरिक तरीकों ( self._log) का उपयोग करने का बुरा अभ्यास किसने शुरू किया और प्रत्येक उत्तर उस पर आधारित क्यों है ?! पाइथोनिक सॉल्यूशन self.logइसके बजाय उपयोग करना होगा ताकि आपको किसी भी आंतरिक सामान के साथ गड़बड़ न करना पड़े:

import logging

SUBDEBUG = 5
logging.addLevelName(SUBDEBUG, 'SUBDEBUG')

def subdebug(self, message, *args, **kws):
    self.log(SUBDEBUG, message, *args, **kws) 
logging.Logger.subdebug = subdebug

logging.basicConfig()
l = logging.getLogger()
l.setLevel(SUBDEBUG)
l.subdebug('test')
l.setLevel(logging.DEBUG)
l.subdebug('test')

18
कॉल स्टैक में एक अतिरिक्त स्तर शुरू करने से बचने के लिए लॉग () के बजाय _log () का उपयोग करना आवश्यक है। यदि लॉग () का उपयोग किया जाता है, तो अतिरिक्त स्टैक फ्रेम की शुरूआत वास्तविक कॉल करने वाले के बजाय डिबग फ़ंक्शन को इंगित करने के लिए कई LogRecord विशेषताएँ (funcName, lineno, filename, pathname, ...) का कारण बनती है। यह संभवतः वांछित परिणाम नहीं है।
रिवाई

5
कब से एक वर्ग के अपने आंतरिक तरीकों को अनुमति नहीं है? सिर्फ इसलिए कि फ़ंक्शन को कक्षा के बाहर परिभाषित किया गया है, इसका मतलब यह नहीं है कि यह एक बाहरी विधि है।
OozeMeister

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

मुझे लगता है, @schlamar जो कहते हैं, वह सही है, लेकिन काउंटर कारण को समान संख्या में वोट मिले। तो क्या उपयोग करें?
सुमित मुरारी

1
एक विधि एक आंतरिक विधि का उपयोग क्यों नहीं करेगी?
ग्रिंगो सुवे

9

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

import logging

@property
def log(obj):
    logging.addLevelName(5, 'TRACE')
    myLogger = logging.getLogger(obj.__class__.__name__)
    setattr(myLogger, 'trace', lambda *args: myLogger.log(5, *args))
    return myLogger

अभी

mylogger.trace('This is a trace message')

उम्मीद के मुताबिक काम करना चाहिए।


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

नीचे @Zbigniew ने संकेत दिया कि यह काम नहीं किया, जो मुझे लगता है कि क्योंकि आपके लकड़हारे को अपनी कॉल करने की आवश्यकता है _log, नहीं log
marqueed

9

जबकि हमारे पास पहले से ही बहुत सारे सही उत्तर हैं, निम्नलिखित मेरी राय में अधिक है:

import logging

from functools import partial, partialmethod

logging.TRACE = 5
logging.addLevelName(logging.TRACE, 'TRACE')
logging.Logger.trace = partialmethod(logging.Logger.log, logging.TRACE)
logging.trace = partial(logging.log, logging.TRACE)

यदि आप mypyअपने कोड का उपयोग करना चाहते हैं , तो यह # type: ignoreविशेषता जोड़ने से चेतावनियों को दबाने के लिए जोड़ने की सिफारिश की जाती है ।


1
यह बहुत अच्छा लग रहा है, लेकिन अंतिम पंक्ति भ्रामक है। यह नहीं होना चाहिए logging.trace = partial(logging.log, logging.TRACE) # type: ignore?
सर्गेई न्यूडनोव

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

8

मुझे लगता है कि आपको Loggerकक्षा को उप- वर्ग करना होगा और एक विधि जोड़ना होगा traceजिसे मूल रूप Logger.logसे निम्न स्तर के साथ कॉल किया जाता है DEBUG। मैंने यह कोशिश नहीं की है, लेकिन यह डॉक्स दर्शाता है


3
और आप शायद logging.getLoggerबिल्ट-इन क्लास के बजाय अपने उपवर्ग को वापस करना चाहेंगे ।
S.Lott

4
@ एस.लॉट - वास्तव में (कम से कम पायथन के वर्तमान संस्करण के साथ, शायद यह 2010 में वापस नहीं था) आपको उपयोग करना होगा setLoggerClass(MyClass)और फिर getLogger()सामान्य रूप से कॉल करना होगा ...
मैक

IMO, यह अब तक का सबसे अच्छा (और सबसे पाइथोनिक) उत्तर है, और अगर मैंने इसे एकाधिक + 1 का दिया है, तो मुझे मिलेगा। यह निष्पादित करने के लिए सरल है, हालांकि नमूना कोड अच्छा रहा होगा। :-D
डौग आर

@ डगआर। धन्यवाद, लेकिन जैसा मैंने कहा, मैंने इसकी कोशिश नहीं की है। :)
नूफ़ल इब्राहिम

6

एक कस्टम लकड़हारा बनाने के लिए सुझाव:

  1. उपयोग न करें _log, उपयोग करें log(आपको जांचने की आवश्यकता नहीं हैisEnabledFor )
  2. लॉगिंग मॉड्यूल कस्टम लॉगर का एक बनाने वाला उदाहरण होना चाहिए क्योंकि यह कुछ जादू करता है getLogger, इसलिए आपको कक्षा को इसके माध्यम से सेट करना होगाsetLoggerClass
  3. __init__यदि आप कुछ भी स्टोर नहीं कर रहे हैं, तो आपको लकड़हारे, वर्ग के लिए परिभाषित करने की आवश्यकता नहीं है
# Lower than debug which is 10
TRACE = 5
class MyLogger(logging.Logger):
    def trace(self, msg, *args, **kwargs):
        self.log(TRACE, msg, *args, **kwargs)

इस लकड़हारे का उपयोग setLoggerClass(MyLogger)करते समय इस से डिफ़ॉल्ट लकड़हारा बनाने के लिए उपयोग करेंgetLogger

logging.setLoggerClass(MyLogger)
log = logging.getLogger(__name__)
# ...
log.trace("something specific")

आप की आवश्यकता होगी करने के लिए setFormatter, setHandlerऔर setLevel(TRACE)पर handlerऔर पर logवास्तव में यह निम्न स्तर का पता लगाने के लिए स्वयं se


3

यह मेरे लिए काम किया:

import logging
logging.basicConfig(
    format='  %(levelname)-8.8s %(funcName)s: %(message)s',
)
logging.NOTE = 32  # positive yet important
logging.addLevelName(logging.NOTE, 'NOTE')      # new level
logging.addLevelName(logging.CRITICAL, 'FATAL') # rename existing

log = logging.getLogger(__name__)
log.note = lambda msg, *args: log._log(logging.NOTE, msg, args)
log.note('school\'s out for summer! %s', 'dude')
log.fatal('file not found.')

लंबर / फंकनामे समस्या लकड़हारे के साथ तय की गई है। मुझे लगता है कि लैम्ब्डा का उपयोग करना थोड़ा साफ दिखता है, लेकिन दोष यह है कि यह कीवर्ड तर्क नहीं ले सकता है। मैंने कभी खुद का इस्तेमाल नहीं किया है, इसलिए कोई बड़ी बात नहीं है।

  नोट सेटअप: गर्मियों के लिए स्कूल से बाहर! दोस्त
  FATAL सेटअप: फ़ाइल नहीं मिली।

2

मेरे अनुभव में, यह ऑप की समस्या का पूर्ण समाधान है ... "लैम्ब्डा" को उस फ़ंक्शन के रूप में देखने से बचने के लिए जिसमें संदेश उत्सर्जित होता है, गहरा जाएं:

MY_LEVEL_NUM = 25
logging.addLevelName(MY_LEVEL_NUM, "MY_LEVEL_NAME")
def log_at_my_log_level(self, message, *args, **kws):
    # Yes, logger takes its '*args' as 'args'.
    self._log(MY_LEVEL_NUM, message, args, **kws)
logger.log_at_my_log_level = log_at_my_log_level

मैंने कभी भी स्टैंडअलोन लकड़हारा वर्ग के साथ काम करने की कोशिश नहीं की है, लेकिन मुझे लगता है कि मूल विचार समान है (_log का उपयोग करें)।


मुझे नहीं लगता कि यह काम करता है। क्या आपको loggerपहले arg के रूप में ज़रूरत नहीं है log_at_my_log_level?
पॉल

हां, मुझे लगता है कि आप शायद करेंगे। यह उत्तर उस कोड से अनुकूलित किया गया था जो थोड़ी अलग समस्या को हल करता है।
marqueed

2

फ़ाइल का नाम और लाइन नंबर सही पाने के लिए पागल भौतिकविदों का उदाहरण:

def logToRoot(message, *args, **kwargs):
    if logging.root.isEnabledFor(levelNum):
        logging.root._log(levelNum, message, args, **kwargs)

1

पिन किए गए उत्तर के आधार पर, मैंने एक छोटी सी विधि लिखी जो स्वचालित रूप से नए लॉगिंग स्तर बनाती है

def set_custom_logging_levels(config={}):
    """
        Assign custom levels for logging
            config: is a dict, like
            {
                'EVENT_NAME': EVENT_LEVEL_NUM,
            }
        EVENT_LEVEL_NUM can't be like already has logging module
        logging.DEBUG       = 10
        logging.INFO        = 20
        logging.WARNING     = 30
        logging.ERROR       = 40
        logging.CRITICAL    = 50
    """
    assert isinstance(config, dict), "Configuration must be a dict"

    def get_level_func(level_name, level_num):
        def _blank(self, message, *args, **kws):
            if self.isEnabledFor(level_num):
                # Yes, logger takes its '*args' as 'args'.
                self._log(level_num, message, args, **kws) 
        _blank.__name__ = level_name.lower()
        return _blank

    for level_name, level_num in config.items():
        logging.addLevelName(level_num, level_name.upper())
        setattr(logging.Logger, level_name.lower(), get_level_func(level_name, level_num))

विन्यास ऐसा हो सकता है:

new_log_levels = {
    # level_num is in logging.INFO section, that's why it 21, 22, etc..
    "FOO":      21,
    "BAR":      22,
}

0

लॉगर वर्ग में एक अतिरिक्त विधि जोड़ने के विकल्प के रूप में मैं Logger.log(level, msg)विधि का उपयोग करने की सलाह दूंगा ।

import logging

TRACE = 5
logging.addLevelName(TRACE, 'TRACE')
FORMAT = '%(levelname)s:%(name)s:%(lineno)d:%(message)s'


logging.basicConfig(format=FORMAT)
l = logging.getLogger()
l.setLevel(TRACE)
l.log(TRACE, 'trace message')
l.setLevel(logging.DEBUG)
l.log(TRACE, 'disabled trace message')

0

मैं उलझन में हूं; अजगर 3.5 के साथ, कम से कम, यह सिर्फ काम करता है:

import logging


TRACE = 5
"""more detail than debug"""

logging.basicConfig()
logging.addLevelName(TRACE,"TRACE")
logger = logging.getLogger('')
logger.debug("n")
logger.setLevel(logging.DEBUG)
logger.debug("y1")
logger.log(TRACE,"n")
logger.setLevel(TRACE)
logger.log(TRACE,"y2")
    

उत्पादन:

डीबग: जड़: y1

ट्रेस: ​​जड़: y2


1
यह तुम क्या नहीं करता है logger.trace('hi')जो मेरा मानना है कि मुख्य लक्ष्य है
Ultimation

-3

यदि कोई व्यक्ति लॉगिंग मॉड्यूल (या इसकी एक प्रति) में नए लॉगिंग स्तर को जोड़ने का स्वचालित तरीका चाहता है, तो मैंने @ pfa के उत्तर का विस्तार करते हुए, यह फ़ंक्शन बनाया है:

def add_level(log_name,custom_log_module=None,log_num=None,
                log_call=None,
                   lower_than=None, higher_than=None, same_as=None,
              verbose=True):
    '''
    Function to dynamically add a new log level to a given custom logging module.
    <custom_log_module>: the logging module. If not provided, then a copy of
        <logging> module is used
    <log_name>: the logging level name
    <log_num>: the logging level num. If not provided, then function checks
        <lower_than>,<higher_than> and <same_as>, at the order mentioned.
        One of those three parameters must hold a string of an already existent
        logging level name.
    In case a level is overwritten and <verbose> is True, then a message in WARNING
        level of the custom logging module is established.
    '''
    if custom_log_module is None:
        import imp
        custom_log_module = imp.load_module('custom_log_module',
                                            *imp.find_module('logging'))
    log_name = log_name.upper()
    def cust_log(par, message, *args, **kws):
        # Yes, logger takes its '*args' as 'args'.
        if par.isEnabledFor(log_num):
            par._log(log_num, message, args, **kws)
    available_level_nums = [key for key in custom_log_module._levelNames
                            if isinstance(key,int)]

    available_levels = {key:custom_log_module._levelNames[key]
                             for key in custom_log_module._levelNames
                            if isinstance(key,str)}
    if log_num is None:
        try:
            if lower_than is not None:
                log_num = available_levels[lower_than]-1
            elif higher_than is not None:
                log_num = available_levels[higher_than]+1
            elif same_as is not None:
                log_num = available_levels[higher_than]
            else:
                raise Exception('Infomation about the '+
                                'log_num should be provided')
        except KeyError:
            raise Exception('Non existent logging level name')
    if log_num in available_level_nums and verbose:
        custom_log_module.warn('Changing ' +
                                  custom_log_module._levelNames[log_num] +
                                  ' to '+log_name)
    custom_log_module.addLevelName(log_num, log_name)

    if log_call is None:
        log_call = log_name.lower()

    setattr(custom_log_module.Logger, log_call, cust_log)
    return custom_log_module

1
अमल के अंदर का ईविल। वाह।
मैड

2
..... पता नहीं मैंने क्या कर दिया .... इतने महीनों के बाद मैं ख़ुशी से इस कथन को एक setattrबदले से बदल
दूंगा
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.