日志之logging.Logger 类 的使用

这次介绍logging.Logger的使用。

一.代码的介绍

 

 1 class Logger(Filterer):
 2     """
 3     Instances of the Logger class represent a single logging channel. A
 4     "logging channel" indicates an area of an application. Exactly how an
 5     "area" is defined is up to the application developer. Since an
 6     application can have any number of areas, logging channels are identified
 7     by a unique string. Application areas can be nested (e.g. an area
 8     of "input processing" might include sub-areas "read CSV files", "read
 9     XLS files" and "read Gnumeric files"). To cater for this natural nesting,
10     channel names are organized into a namespace hierarchy where levels are
11     separated by periods, much like the Java or Python package namespace. So
12     in the instance given above, channel names might be "input" for the upper
13     level, and "input.csv", "input.xls" and "input.gnu" for the sub-levels.
14     There is no arbitrary limit to the depth of nesting.
15     """
    #翻译如下:
    '''
 

Logger类的实例表示单个日志记录通道。A.“日志记录通道”表示应用程序的一个区域。确切地说,如何“区域”的定义取决于应用程序开发人员。自应用程序可以有任意数量的区域,日志记录通道被标识通过唯一字符串。应用程序区域可以嵌套(例如,区域


“输入处理”可能包括子区域“读取CSV文件”、“读取XLS文件”和“读取Gnumeric文件”)。为了满足这种自然嵌套,通道名称组织为命名空间层次结构,其中级别为由句点分隔,很像Java或Python包名称空间。所以在上面给出的示例中,信道名称可能是“输入”的


级别,以及子级别的“input.csv”、“input.xls”和“input.gnu”。嵌套深度没有任意限制。

        '''
16 def __init__(self, name, level=NOTSET): 17 """ 18 Initialize the logger with a name and an optional level.使用名称和可选级别初始化记录器。
19 """ 20 Filterer.__init__(self) 21 self.name = name 22 self.level = _checkLevel(level) 23 self.parent = None 24 self.propagate = True 25 self.handlers = [] 26 self.disabled = False

着重看这个类的初始化。这个类的初始化必须要穿入一个 name 的参数,这个 name是一个名称,小编猜测可能是  日志的名称。

level 有以下级别 默认是未设置级别:


CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
# 日志级别大小关系为:CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET,当然也可以自己定义日志级别。

但是请注意 输入的级别必须是数字或字符串而且必须是已经存在的级别(如上的级别), _checkLevel(level)会检查你输入的级别类型,如下:

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:#如果是字符串的话
        if level not in _nameToLevel:#检查级别是否是已经存在的
            raise ValueError("Unknown level: %r" % level)#错误返回
        rv = _nameToLevel[level]#字符串变成数字
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv

这个代码未检测数字的级别,,所以存在一点问题,, 

_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

如此多的级别,这里以debug为例子,源代码如下:

  def debug(self, msg, *args, **kwargs):
        """
        Log 'msg % args' with severity 'DEBUG'.

        To pass exception information, use the keyword argument exc_info with
        a true value, e.g.

        logger.debug("Houston, we have a %s", "thorny problem", exc_info=1)
        """
        if self.isEnabledFor(DEBUG):
            self._log(DEBUG, msg, args, **kwargs)

解释:

日志的严重性为 debug 级别,要传递错误信息,把关键参数 exc_info 赋真值就可以了。msg是我们要传进的报错信息。

e.g.
logger.debug("Houston, we have a %s", "thorny problem", exc_info=1)

isEnabledFor()函数代码如下:

    def isEnabledFor(self, level):
        """
        Is this logger enabled for level 'level'?
        """
        if self.manager.disable >= level:
            return False
        return level >= self.getEffectiveLevel()

可以看出isEnabledFor()主要作用就是判断level是否可用。返回布尔值。

所有的错误级别的功能都是由self._log()实现,代码如下:

  def _log(self, level, msg, args, exc_info=None, extra=None, stack_info=False):
        """
        Low-level logging routine which creates a LogRecord and then calls
        all the handlers of this logger to handle the record.
        """
        sinfo = None
        if _srcfile:
            #IronPython doesn't track Python frames, so findCaller raises an
            #exception on some versions of IronPython. We trap it here so that
            #IronPython can use logging.
            try:
                fn, lno, func, sinfo = self.findCaller(stack_info)
            except ValueError: # pragma: no cover
                fn, lno, func = "(unknown file)", 0, "(unknown function)"
        else: # pragma: no cover
            fn, lno, func = "(unknown file)", 0, "(unknown function)"
        if exc_info:
            if isinstance(exc_info, BaseException):
                exc_info = (type(exc_info), exc_info, exc_info.__traceback__)
            elif not isinstance(exc_info, tuple):
                exc_info = sys.exc_info()
        record = self.makeRecord(self.name, level, fn, lno, msg, args,
                                 exc_info, func, extra, sinfo)
        self.handle(record)

这里已经需要更多时间去研究每个函数的功能,到这里我们已经大概了解了 logging.Logger类的使用。分析源代码是为了使用,想了解它的具体原理可以去看logging的源代码。

这个类就创建的时候有一点不同,其他的都一样,可以看我的上一篇 博客 有详解。

链接 : https://www.cnblogs.com/naihaizhuoxia/p/16698952.html

 

posted @ 2022-09-16 10:31  南海捉虾  阅读(431)  评论(0编辑  收藏  举报