python功能简介_Python常用模块功能简介(三)logging

Apple iPhone 11 (A2223) 128GB 黑色 移动联通电信4G手机 双卡双待

4999元包邮

去购买 >

iphone.jpg

logging基本介绍

先介绍一下我们为什么要使用日志,平常我们编写程序为了验证程序运行与debug,通常会使用print函数来对一些中间结果进行输出验证,在验证成功后再将print语句注释或删除掉。这样做在小型程序中还比较灵活,但是对于大型项目来说,就十分繁琐了----->所以使用日志log就很自然了,日志可以调整日志级别,来决定我们是否输出对应级别的日志,同时还可以将日志导入文件记录下来。

再介绍一下logging中的log级别:

Level

Numeric Value

logging.CRITICAL

50

logging.ERROR

40

logging.WARNING

30

logging.INFO

20

logging.DEBUG

10

实际上这些level都是整数值,可由如type(logging.info)验证为int类型。

模块级的使用方法

logging模块的模块级使用方法就是使用一些模块级接口函数。而且还有一个比较重要的是对日志的输出形式和输出目的地等进行设置。

接口函数也是对应日志级别而输出信息的:

logging.debug(msg)

logging.info(msg)

logging.warning(msg)

logging.error(msg)

logging.critical(msg)

这几个函数除了日志级别上的区别,其实都是使用默认的root logger来对信息进行log的,它是处于日志器层级关系最顶层的日志器,且该实例是以单例模式存在的。见源码:

def info(msg, *args, **kwargs):

if len(root.handlers) == 0:

basicConfig()

root.info(msg, *args, **kwargs)

这里可以见到在logging模块的info函数中:(1)首先进行了一个对于root logger的handlers属性的长度判断是否调用basicConfig函数。(2)之后是调用root logger的info函数来实现功能的。

这里对于第(2)点我们进一下探寻:

root = RootLogger(WARNING)

在logging的源码中可以看到如上语句,即我们将logging模块import后,其实已经默认的创建了一个root logger对象,并且之后我们自己创建的logger都是root logger的子类。

日志的设置

对于日志的设置,我们是使用logging.basicConfig(**kwargs)函数,它是对root logger进行设置的,一般使用较多的关键字参数如下:

level 决定root logger的日志级别。

format 它是日志格式字符串,指定日志输出的字段信息,如日期,日志级别,文件名,当然还有我们的msg信息等等。

datefmt 决定日期字段的输出格式。

filename 日志信息的输出目的地文件,不指定时默认输出到控制台。

filemode 目的地文件的打开模式,不指定默认为"a"。

对于logging.basicConfig函数有一点需要注意:我们不能在该函数前使用任何模块级日志输出函数如logging.info、logging.error,因为它们会调用一个不带参的basicConfig函数,使得logging.basicConfig函数失效。见源码(由于代码过多,建议参考注释进行阅读):

def basicConfig(**kwargs):

_acquireLock()

try:

#这里由于不带参调用basicConifg,

#而root.handlers默认为空列表

#在Logger定义中可见self.handlers被设为[],

#而默认的root实例在创建时只指定了log级别

#所以if条件必然通过

if len(root.handlers) == 0:

#由于不带参,所以handlers必为None

handlers = kwargs.pop("handlers", None)

if handlers is None:

#这里由于不带参,所以即是handlers为None

#通过上面的if判断,但kwargs同样为None,

#所以该if不通过

if "stream" in kwargs and "filename" in kwargs:

raise ValueError("'stream' and 'filename' should not be "

"specified together")

else:

if "stream" in kwargs or "filename" in kwargs:

raise ValueError("'stream' or 'filename' should not be "

"specified together with 'handlers'")

#这里由于handlers为None通过if判断继续执行

if handlers is None:

filename = kwargs.pop("filename", None)

mode = kwargs.pop("filemode", 'a')

if filename:

h = FileHandler(filename, mode)

#不带参,kwargs为None,所以filename

#在上面的执行语句的返回值为None,所以

#执行这个else分支

else:

stream = kwargs.pop("stream", None)

h = StreamHandler(stream)

#注意这里,十分重要,可见handlers终于不为None

#被赋予了一个列表,该列表有一个元素h

handlers = [h]

dfs = kwargs.pop("datefmt", None)

style = kwargs.pop("style", '%')

if style not in _STYLES:

raise ValueError('Style must be one of: %s' % ','.join(

_STYLES.keys()))

fs = kwargs.pop("format", _STYLES[style][1])

fmt = Formatter(fs, dfs, style)

#再看这里,十分重要

for h in handlers:

#这个无所谓,就是对format进行默认设置

if h.formatter is None:

h.setFormatter(fmt)

#这里最为关键,可见root.addHandler(h)函数

#会把h添加进root.handlers列表中,那么很显然

#root.handlers不再是一个空列表

root.addHandler(h)

level = kwargs.pop("level", None)

if level is not None:

root.setLevel(level)

if kwargs:

keys = ', '.join(kwargs.keys())

raise ValueError('Unrecognised argument(s): %s' % keys)

finally:

_releaseLock()

所以即是不带参调用basicConfig(),但是经过其函数体执行,root.handlers的列表长度会不为0,所以之后再调用logging.basicConifg函数时,对root.handlers判断,就会因此而直接略过函数体中try部分(主要部分),直接执行finally,没有进行任何设置。

对象级使用

在logging模块中logger对象从来都不是直接实例化,而是通过一个模块级借口完成:logging.getLogger(name=None),注意我们创建的logger都是root logger的子类。而通过我们自己创建的logger对象,使用日志记录也是和模块级接口一样的:

logger.debug(msg)

logger.info(msg)

logger.warning(msg)

logger.error(msg)

logger.critical(msg)

同样对于日志格式的设置也是通过logging.basicConfig函数完成的,虽然该函数是对root logger的日志格式设置,但由于我们定义的logger类都是root logger的子类,所以便能够沿用该设置。并且对于对象级接口,如logger.info函数:

def info(self, msg, *args, **kwargs):

if self.isEnabledFor(INFO):

self._log(INFO, msg, args, **kwargs)

可见其中没有对basicConfig函数的调用,所以也就没有修改root.handlers列表,即不会发生上文的logging.basciConfig函数失效的问题。

jd_dn250.png

jd_sj250.jpg

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值