পাইথনের লগিং সুবিধাটিতে কীভাবে কাস্টম লগলেভেল যুক্ত করা যায়


116

আমি আমার আবেদনের জন্য লগলেভেল ট্র্যাক (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): আমি পিএফএর গ্রহণযোগ্য উত্তরটি পরিবর্তন করেছি যা হ'ল আইএমএইচও, এরিক এস এর খুব ভাল প্রস্তাবের ভিত্তিতে একটি দুর্দান্ত সমাধান solution

উত্তর:


171

@ এরিক এস।

এরিক এস এর উত্তরটি দুর্দান্ত, তবে আমি পরীক্ষার মাধ্যমে শিখেছি যে এটির ফলে সর্বদা নতুন ডিবাগ স্তরে লগ হওয়া বার্তাগুলি মুদ্রিত হবে - লগ স্তরটি কী সেট করা আছে তা নির্বিশেষে। সুতরাং আপনি যদি একটি নতুন স্তরের নম্বর করেন 9, যদি আপনি কল করেন setLevel(50)তবে নিম্ন স্তরের বার্তা ভুলভাবে মুদ্রিত হবে।

এটি যাতে না ঘটে তার জন্য, "ডিবাগভি" ফাংশনের অভ্যন্তরে আপনার আর একটি লাইন প্রয়োজন যাচাই করা প্রশ্নে লগিং স্তরটি আসলে সক্ষম হয়েছে কিনা তা পরীক্ষা করতে।

স্থির উদাহরণ যা লগিং স্তরটি সক্ষম হয়েছে কিনা তা পরীক্ষা করে:

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 Loggerlogging.__init__.pyপাইথন 2.7 জন্য, এই সব মান লগ ফাংশন কি (.critical, .debug, ইত্যাদি) হয়।

আমি খ্যাতির অভাবে অন্যের জবাবগুলিতে স্পষ্টত জবাব পোস্ট করতে পারি না ... আশা করি এরিক যদি সে এটি দেখেন তবে তার পোস্টটি আপডেট করবেন। =)


7
এটি আরও ভাল উত্তর কারণ এটি লগ স্তরটি সঠিকভাবে পরীক্ষা করে।
কর্নেল আতঙ্ক

2
অবশ্যই বর্তমান উত্তরের চেয়ে অনেক বেশি তথ্যপূর্ণ।
ম্যাড পদার্থবিদ

4
@ পিএফএ যুক্ত করার বিষয়ে কী 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
ম্যাক

এই উত্তরটি খুব সহায়ক হয়েছে। আপনাকে পিএফএ এবং এরিকস ধন্যবাদ। আমি পরামর্শ দিতে চাই যে সম্পূর্ণতার জন্য আরও দুটি বিবৃতি অন্তর্ভুক্ত করা উচিত: logging.DEBUGV = DEBUG_LEVELV_NUMএবং logging.__all__ += ['DEBUGV'] দ্বিতীয়টি ভয়াবহভাবে গুরুত্বপূর্ণ নয় তবে প্রথমটি প্রয়োজনীয় যদি আপনার কোনও কোড থাকে যা লগিং স্তরকে গতিশীলভাবে সামঞ্জস্য করে এবং আপনি if verbose: logger.setLevel(logging.DEBUGV)Ke
কীথের

63

আমি "ল্যাম্বডা দেখা এড়ানো" উত্তরটি নিয়েছি এবং লগ_এট_মাই_লগ_লেভেলটি কোথায় যুক্ত করা হচ্ছে তা সংশোধন করতে হয়েছিল। আমিও যে সমস্যাটি পলকে দেখেছি তা দেখেছি "আমার মনে হয় এটি কাজ করে না log এটি আমার পক্ষে কাজ করেছে

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এবং খুশি
হোন

4
: @Eric এস আপনি এই উত্তর কটাক্ষপাত করা উচিত stackoverflow.com/a/13638084/600110
স্যাম Mussmann

1
আমি @ সামসম্যানের সাথে একমত আমি উত্তরটি মিস করেছি কারণ এটি ছিল শীর্ষ ভোটের উত্তর।
কর্নেল আতঙ্ক

@ এরিক এস। * ছাড়াই আপনার কী দরকার? আমি যদি এটি করি তবে আমি পেয়েছি TypeError: not all arguments converted during string formattingতবে এটি * দিয়ে ভাল কাজ করে। (পাইথন ৩.৪.৩) এটি কি অজগর সংস্করণ সমস্যা, বা আমি অনুপস্থিত কিছু?
পিটার

এই উত্তরটি আমার পক্ষে কাজ করে না। একটি 'লগিং.দেবগভ' করার চেষ্টা করে একটি ত্রুটি দেয়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এবং আপনি প্রশংসা করবেন যে এটি তাদের সবার সেরা উত্তর!
সার্জ Stroobandt

ধন্যবাদ। আমি একসাথে এই জাতীয় কিছু কোবল করার জন্য বেশ কিছুটা কাজ করেছি এবং এই কিউএ খুব সহায়ক ছিল, তাই আমি কিছু যুক্ত করার চেষ্টা করেছি।
ম্যাড পদার্থবিদ

1
@PeterDolan। আপনার যদি এ নিয়ে সমস্যা হয় তবে আমাকে জানান। আমার ব্যক্তিগত টুলবক্সে আমার একটি বর্ধিত সংস্করণ রয়েছে যা আপনাকে বিরোধী স্তরের সংজ্ঞাগুলি কীভাবে পরিচালনা করতে হবে তা কনফিগার করতে দেয়। এটি আমার জন্য একবার এসেছিল কারণ আমি একটি ট্র্যাক স্তর যুক্ত করতে চাই এবং স্ফিংসের অন্যতম উপাদানও এটি।
ম্যাড পদার্থবিদ

1
সামনে তারকাচিহ্ন অভাব argsমধ্যে logForLevelবাস্তবায়ন ইচ্ছাকৃত / প্রয়োজনীয়?
ক্রিস এল বার্নস

1
@Tunisia। এটা অনিচ্ছাকৃত। ধরার জন্য ধন্যবাদ
ম্যাড পদার্থবিদ 18

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
এটি আইএমএইচও সেরা উত্তর, কারণ এটি বানরের প্যাচিং এড়ানো হয়। কি getএবং setLoggerClassসঠিকভাবে এবং কেন তাদের প্রয়োজন?
মার্কো সুলা

3
@ মার্কোসুল্লা এগুলি পাইথনের লগিং মডিউলের অংশ হিসাবে নথিভুক্ত করা হয়েছে। আমার ধারণা, গতিশীল সাব-ক্লাসিংটি ব্যবহার করা হয় যদি এই লাইব্রেরিটি ব্যবহার করার সময় কেউ তাদের নিজস্ব লোগার চাইত। এই মাইলগারটি তখন আমার ক্লাসের একটি সাব-ক্লাস হয়ে উঠবে, দুটোকে একত্রিত করে।
ক্র্যাকারজ্যাক 9

এটি ডিফল্ট লগিং লাইব্রেরিতে কোনও স্তর যুক্ত করে কিনা তা এই আলোচনায় উপস্থাপিত সমাধানের সাথে খুব মিল TRACE। +1
আইএমপি 1

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
কল স্ট্যাকের অতিরিক্ত স্তরের প্রবর্তন এড়াতে লগ () এর পরিবর্তে _লগ () ব্যবহার করা দরকার। যদি লগ () ব্যবহার করা হয় তবে অতিরিক্ত স্ট্যাক ফ্রেমের প্রবর্তনের ফলে বেশ কয়েকটি লগরেকর্ড অ্যাট্রিবিউট (ফানকনাম, লিনেনো, ফাইল নাম, পাথনাম, ...) প্রকৃত কলারের পরিবর্তে ডিবাগ ফাংশনে নির্দেশ করতে পারে। এটি সম্ভবত কাঙ্ক্ষিত ফলাফল নয়।
রিভি

5
যেহেতু কোনও শ্রেণীর নিজস্ব অভ্যন্তরীণ পদ্ধতিগুলি কল করা জায়েয নয়? ক্লাসের বাইরে ফাংশনটি সংজ্ঞায়িত করা হয়েছে তার অর্থ এটি বাহ্যিক পদ্ধতি নয় method
ওজেজমিস্টার

3
এই পদ্ধতিটি কেবল স্ট্যাক ট্রেসকে অহেতুক পরিবর্তন করে না, তবে সঠিক স্তরটি লগ হচ্ছে কিনা তাও পরীক্ষা করে না।
ম্যাড পদার্থবিদ

আমি অনুভব করছি, @ স্ক্লামার যা বলেছে তা সঠিক, তবে পাল্টা কারণ একই সংখ্যক ভোট পেয়েছে। তাহলে কী ব্যবহার করবেন?
সুমিত মুরারি

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
pm

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?
সের্গেই নুডনভ

@ সের্গে নুডনভকে নির্দেশ করার জন্য ধন্যবাদ, আমি এটি ঠিক করেছি। আমার পক্ষ থেকে একটি ভুল ছিল, আমি কেবল আমার কোড থেকে অনুলিপি করেছি এবং স্পষ্টতই পরিষ্কার করতে গিয়ে গোলযোগ করেছি।
ডেরওহ

8

আমি মনে করি আপনাকে Loggerক্লাসটি সাবক্লাস করতে হবে এবং এমন একটি পদ্ধতি যুক্ত করতে হবে traceযার নাম মূলত এর Logger.logচেয়ে কম স্তর সহ কল করে DEBUG। আমি এটি চেষ্টা করে দেখিনি তবে এটি ডক্স সূচিত করে


3
এবং আপনি সম্ভবত logging.getLoggerবিল্ট-ইন ক্লাসের পরিবর্তে আপনার সাবক্লাসটি ফিরিয়ে আনতে চাইবেন ।
এস .লট

4
@ এস.লট - আসলে (কমপক্ষে পাইথনের বর্তমান সংস্করণটি নিয়ে, সম্ভবত এটি 2010 এর আগে ঘটেনি) আপনাকে ব্যবহার করতে হবে setLoggerClass(MyClass)এবং তারপরে getLogger()স্বাভাবিক হিসাবে কল করতে হবে ...
ম্যাক

আইএমও, এটি এখন পর্যন্ত সেরা (এবং সর্বাধিক পাইথোনিক) উত্তর, এবং যদি আমি এটিকে একাধিক + 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

আমি কখনও স্ট্যান্ডেলোন লগার শ্রেণীর সাথে কাজ করার চেষ্টা করি নি, তবে আমি মনে করি যে প্রাথমিক ধারণাটি একই (_ লগ ব্যবহার করুন)।


আমি মনে করি না এটি কাজ করে। loggerপ্রথম আর্গ হিসাবে আপনার দরকার নেই 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')আমার পক্ষে বিশ্বাস করি যা প্রধান লক্ষ্য
চূড়ান্ত পরিণতি

-3

যদি কেউ লগিং মডিউলটিতে নতুন লগিং স্তরটি (বা এর একটি অনুলিপি) যুক্ত করতে একটি স্বয়ংক্রিয় পদ্ধতি চায় তবে আমি @ পিএফএর উত্তরটি প্রসারিত করে এই ফাংশনটি তৈরি করেছি:

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পরিবর্তে এই বিবৃতিটি বদলে
দেব
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.