python logging模块的作用_python中logging模块下篇

本文承接上一篇分为如下几个部分日志输出

捕获异常

配置共享

配置到文件

使用规范

参考资料

日志输出

我们之前都是将日志输出到控制台,而实际项目中常常需要将日志存储为文件,我们直接看代码

import logging

logging.basicConfig(level=logging.INFO,

format='%(asctime)s%(message)s',

datefmt='%a,%d%b %Y %H:%M:%S +0000',

filename='my.log')

logging.info('this is a info')

可以看到,只要在logging.basicConfig中加入filename参数,就不会再在控制台中输出日志,而是会将所有日志存入my.log文件中。

需要注意的一点是:上面日志存储方式是追加的,也就是说,上面这个代码连续运行两次,文件中是会有两行日志的。

如果需要改变输出形式,需要调整参数如下

import logging

logging.basicConfig(level=logging.INFO,

format='%(asctime)s%(message)s',

datefmt='%a,%d%b %Y %H:%M:%S +0000',

filename='my.log', filemode='w')

logging.info('this is a info')

其他读写格式可以参考文件读写格式。

指定日志输出也可以不在logging.basicConfig中配置,而是单独设置

import logging

logger = logging.getLogger(__name__)

logger.setLevel(level=logging.INFO)

handler = logging.FileHandler('my.log')

formatter = logging.Formatter('%(asctime)s%(message)s')

handler.setFormatter(formatter)

logger.addHandler(handler)

logger.critical('Critical 50')

logger.error('Error 40')

logger.warning('Warning 30')

logger.info('Info 20')

logger.debug('Debug 10')

这可以达到和刚才相同的效果。我们可以看到,不仅输出方式可以单独配置,而且format也可以单独配置。

配置它们的流程是配置好的format设置到handler中

配置好的handler添加到logger中

添加多个输出端,且不同输出端输出内容不一样(level不同,format不同)

import logging

import sys

logger = logging.getLogger(__name__)

logger.setLevel(level=logging.DEBUG) # 设置基本level

# 输出到控制台,不设置format

handler_stream = logging.StreamHandler(sys.stdout)

handler_stream.setLevel(level=logging.WARN) # 更改level

logger.addHandler(handler_stream)

# 输出到文件,继承基础level

handler_file = logging.FileHandler('my.log', 'w')

formatter = logging.Formatter('%(asctime)s%(message)s')

handler_file.setFormatter(formatter) # 设置format

logger.addHandler(handler_file)

logger.critical('Critical 50')

logger.error('Error 40')

logger.warning('Warning 30')

logger.info('Info 20')

logger.debug('Debug 10')

控制台输出结果为

Critical 50

Error 40

Warning 30

my.log文件输出结果为

2018-07-01 21:03:27,164 Critical 50

2018-07-01 21:03:27,165 Error 40

2018-07-01 21:03:27,167 Warning 30

2018-07-01 21:03:27,171 Info 20

2018-07-01 21:03:27,172 Debug 10

这里需要注意一点,基础level要设置比较低一些,后面handler设置的level只有比基础高才有效。

logging模块还提供了许多其他的日志输出形式,详情可以见官网

捕获异常

我们希望将程序的报错信息记录到log文件中

import logging

logging.basicConfig(level=logging.INFO,

format='%(asctime)s%(message)s',

datefmt='%a,%d%b %Y %H:%M:%S +0000',

filename='my.log')

logging.info('this is a info')

try:

do

except Exception:

logging.error('There are something wrong', exc_info=True)

logging.info('continue')

输出到文件的结果如下

Sun, 01 Jul 2018 21:10:43 +0000 this is a info

Sun, 01 Jul 2018 21:10:53 +0000 this is a info

Sun, 01 Jul 2018 21:10:53 +0000 There are something wrong

Traceback (most recent call last):

File "learn.py", line 9, in

do

NameError: name 'do' is not defined

Sun, 01 Jul 2018 21:10:53 +0000 continue

其中exc_info的作用就是在日志中包含具体的报错信息,默认是False不包含。

配置共享

在写一个项目时,需要编写多个文件,每个文件内都要设置相同格式的日志输出,如果每个文件都重新配置一遍就太麻烦了,logging模块为我们提供了一个简单的方法。

比如在main.py文件中编写如下代码

import logging

import a

logging.basicConfig(level=logging.INFO,

format='%(asctime)s%(message)s',

datefmt='%a,%d%b %Y %H:%M:%S +0000')

logger = logging.getLogger('mainlogger')

logger.info('main file log')

a.run()

在a.py文件中编写如下代码

import logging

logger = logging.getLogger('mainlogger.a')

def run():

logger.info('a file log')

运行main.py文件,输出结果如下

Sun, 01 Jul 2018 21:19:57 +0000 main file log

Sun, 01 Jul 2018 21:19:57 +0000 a file log

我们可以看到,在a.py文件中只是将logger名称设置为以main.py文件中的logger名称开头,就可以继承main.py文件中的配置了,甚至不需要在a.py文件中导入main.py文件。

配置到文件

我们不仅可以通过python代码进行logging配置,而且可以通过写一个yaml文件进行配置,每次需要用logging时只要调用这个文件就配置完成。

config.yaml文件内容如下

version: 1

formatters:

simple:

format: "%(message)s"

more:

format: "%(asctime)s - %(levelname)s - %(message)s"

handlers:

console:

class : logging.StreamHandler

formatter: simple

level: INFO

stream: ext://sys.stdout

file:

class: logging.FileHandler

formatter: more

level: DEBUG

filename: debug.log

loggers:

mainlogger:

level: DEBUG

handlers: [console, file]

root:

level: DEBUG

handlers: [console]

main.py文件中编写代码如下

import logging

import logging.config

import yaml

import a

with open('config.yaml', 'r', encoding='utf-8') as f:

config = yaml.load(f)

logging.config.dictConfig(config)

logging.info('main file log')

a.run()

a.py文件中编写代码如下

import logging

logger = logging.getLogger('mainlogger')

def run():

logger.info('a file log')

运行main.py结果在控制台中输出如下

a file log

INFO:mainlogger:a file log

在debug.log文件中输出如下

2018-07-01 21:45:37,673 - INFO - a file log

对于这样的输出结果,我们回到yaml文件理一下思路,对这个文件从下往上看首先对于不同的logger名称,如果名称是mainlogger,则使用[console, file]这两个handler,如果未指定(使用logging.info进行输出)则对应root只按照console输出

对于不同的handler,名称为console的handler使用logging.StreamHandler输出到控制台,调用simple的format,而file则输出到文件,使用more的format

对于不同的format格式则在最上面的formatters中定义

通过文件配置的更多内容可以参考官网

使用规范

1.输出字符串的规范

import logging

logging.basicConfig(level=logging.INFO,

format='%(asctime)s%(levelname)s%(message)s')

info = 'apple'

# bad

logging.info('this is a{}'.format(info))

# good

logging.info('this is a%s', info)

二者输出皆为

2018-07-01 21:56:12,969 INFO this is a apple

2.异常处理规范

import logging

logging.basicConfig(level=logging.INFO,

format='%(asctime)s%(message)s',

datefmt='%a,%d%b %Y %H:%M:%S +0000')

logging.info('this is a info')

try:

do

except Exception as e:

# bad

logging.error('There are something wrong:%s', e)

# good

logging.error('There are something wrong', exc_info=True)

# good

logging.exception('There are something wrong')

logging.info('continue')

第一种输出异常结果会是

Sun, 01 Jul 2018 21:58:52 +0000 There are something wrong: name 'do' is not defined

后两种输出异常结果会是

Sun, 01 Jul 2018 21:58:52 +0000 There are something wrong

Traceback (most recent call last):

File "learn.py", line 8, in

do

NameError: name 'do' is not defined

3.日志级别设置

这里列出这篇文章中认为的日志级别使用方法最细微的信息记录到debug中,这个级别就是用来debug的,看程序在哪一次迭代中发生了错误,比如每次循环都输出一些东西用debug级别

info级别用于routines,也就是输出start finish 状态改变等信息

warn输出一些相对重要,但是不是程序bug的信息,比如输入了错误的密码,或者连接较慢

error输出程序bug,打印异常信息

critical用于处理一些非常糟糕的事情,比如内存溢出、磁盘已满,这个一般较少使用

4.建议使用RotatingFileHandler而不是FileHandler

因为日志文件写入是不断增加的过程,如果用FileHandler,久了日志文件会非常大,不利于读写和管理。

用RotatingFileHandler设置日志文件大小,比如10M。则如果日志文件达到10M,就会自动将这个文件重命名,然后创建一个新的日志文件继续写入

也可以使用TimedRotatingFileHandler,这是根据时间,每隔一段时间会自动创建新的日志文件

5.get_logger位置

在一个被import的文件中get_logger的代码要放在函数里面,因为如果放在函数外面,在主文件import这个文件时,就会运行这个初始化。而在import的时候,主文件一般还没有读入yaml文件,因此事先初始化的log就不会正常工作。

参考资料

专栏信息

专栏目录:目录

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值