一般在python中查看一些变量信息和程序运行情况都采用print函数打印到控制台,然而python的logging模块功能强大。从今天起学习一下logging,告别傻瓜式输出吧~
1.初识logging
1.1简单日志打印
导入格式:
import logging
logging提供了一组便利的函数,用来做简单的日志。它们分别是 debug()、 info()、 warning()、 error() 和 critical()。
日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET)。
logging输出到控制台的默认等级是WARNING,因此我们可以看到只有warning以上的等级才会被输出。
logging.debug('this is debug,打印调试信息,级别最低')
logging.info('this is info,打印正常操作信息')
logging.warning('this is warning,打印警告信息')
logging.error('this is error!打印错误信息')
logging.critical('this critical!打印致命错误信息,级别最高')
WARNING:root:this is warning,打印警告信息
ERROR:root:this is error!打印错误信息
CRITICAL:root:this critical!打印致命错误信息,级别最高
1.2日志级别配置
如果我们想把debug和info也打印出来,使用 basicConfig 对日志打印级别进行配置:
logging.basicConfig(level=logging.DEBUG)
这样debug及其以上级别的信息都会被打印出来,我们可以根据自己的需求来设置日志打印级别。
DEBUG:root:this is debug,打印调试信息,级别最低
INFO:root:this is info,打印正常操作信息
WARNING:root:this is warning,打印警告信息
ERROR:root:this is error!打印错误信息
CRITICAL:root:this critical!打印致命错误信息,级别最高
1.3配置日志格式及日志文件输出位置
同样也是采用basicConfig函数
logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有:
参数名 | 含义 |
---|---|
filename | 创建FiledHandler,这样日志会被存储在指定的文件中。 |
filemode | 文件打开方式,指定filename时使用该参数,w为写模式,a为追加模式 |
format | 指定handler使用的日志显示格式 |
datefmt | 指定日期时间格式 |
level | 设置rootlogger日志级别 |
stream | 用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件,默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。 |
format参数中常用的格式化串:
格式串 | 含义 |
---|---|
%(name)s | Logger的名字 |
%(levelno)s | 打印日志级别的数值 |
%(pathname)s | 打印当前执行程序的路径,其实就是sys.argv[0] |
%(filename)s | 打印当前执行程序名 |
%(funcName)s | 打印日志的当前函数 |
%(lineno)d | 打印日志的当前行号 |
%(asctime)s | 打印日志的时间 |
%(thread)d | 打印线程ID |
%(threadName)s | 打印线程名称 |
%(process)d | 打印进程ID |
%(message)s | 打印日志信息 |
我们把指定格式的日志输出到文件:
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
datefmt='%a, %d %b %Y %H:%M:%S',
filename='test.log',
filemode='w')
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')
test.log文件内容如下:
2.logging模块化设计
logging 库采取了模块化的设计,提供了许多组件:记录器、处理器、过滤器和格式化器。
模块 | 作用 |
---|---|
Logger | 暴露了应用程序代码能直接使用的接口 |
Handler | 将(记录器产生的)日志记录发送至合适的目的地 |
Filter | 提供了更好的粒度控制,它可以决定输出哪些日志记录 |
Formatter | 指明了最终输出中日志记录的布局 |
2.1 Logger
Logger 对象要做三件事情。
- 首先,向应用代码暴露了许多方法,这样应用可以在运行时记录消息
- 其次,记录器对象通过严重程度(默认的过滤设施)或者过滤器对象来决定哪些日志消息需要记录下来。
- 第三,记录器对象将相关的日志消息传递给所有感兴趣的日志处理器。
常用的记录器对象的方法分为两类:配置和发送消息。
常用的配置方法如下:
方法 | 作用 |
---|---|
Logger.setLevel() | 指定logger将会处理的最低的安全等级日志信息 |
Logger.addHandler()和Logger.removeHandler() | 从记录器对象中添加和删除处理程序对象 |
Logger.addFilter()和Logger.removeFilter() | 从记录器对象添加和删除过滤器对象 |
2.2 Handler
处理程序对象负责将适当的日志消息(基于日志消息的严重性)分派到处理程序的指定目标。
常用的有4种:
1) logging.StreamHandler -> 控制台输出
2) logging.FileHandler -> 文件输出
3) logging.handlers.RotatingFileHandler -> 按照大小自动分割日志文件,一旦达到指定的大小重新生成文件
这个Handler类似于上面的FileHandler,但是它可以管理文件大小。当文件达到一定大小之后,它会自动将当前日志文件改名,然后创建 一个新的同名日志文件继续输出。比如日志文件是chat.log。当chat.log达到指定的大小之后,RotatingFileHandler自动把 文件改名为chat.log.1。不过,如果chat.log.1已经存在,会先把chat.log.1重命名为chat.log.2…最后重新创建 chat.log,继续输出日志信息。
它的构造函数为:
RotatingFileHandler( filename[, mode[, maxBytes[, backupCount]]])
参数 | 含义 |
---|---|
filename | 文件名 |
mode | 写入模式 |
maxBytes | 最大文件大小 ,maxBytes=0则日志文件可以无限大 |
backupCount | 指定保留的备份文件的个数 |
4) logging.handlers.TimedRotatingFileHandler -> 按照时间自动分割日志文件
间隔一定时间就 自动创建新的日志文件。重命名的过程RotatingFileHandler类似,不过新的文件不是附加数字,而是当前时间。
它的构造函数是:
TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])
其中filename参数和backupCount参数和RotatingFileHandler具有相同的意义。
interval是时间间隔。
when参数是一个字符串。表示时间间隔的单位,不区分大小写。
它有以下取值:
- S 秒
- M 分
- H 小时
- D 天
- W 每星期(interval==0时代表星期一)
- midnight 每天凌晨
下面看一个示例:
需求:
输出log到控制台以及将日志写入log文件。
保存2种类型的log, all.log 保存debug, info, warning, critical 信息, error.log则只保存error信息,同时按照时间自动分割日志文件。
代码如下:
import logging
from logging import handlers
class Logger(object):
#日志级别关系映射
level_relations = {
'debug':logging.DEBUG,
'info':logging.INFO,
'warning':logging.WARNING,
'error':logging.ERROR,
'critical': logging.CRITICAL
}
def __init__(self,filename,level='info',when='S',backCount=3,fmt='%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s:%(message)s'):
self.logger = logging.getLogger(filename)
format_str = logging.Formatter(fmt) #设置日志格式
self.logger.setLevel(self.level_relations.get(level))#设置日志级别
sh = logging.StreamHandler() #设置向屏幕输出
sh.setFormatter(format_str) #设置屏幕上显示的格式
# 往文件里写入#指定间隔时间自动生成文件的处理器
th = handlers.TimedRotatingFileHandler(filename=filename,when=when,backupCount=backCount,encoding='utf-8')
th.setFormatter(format_str)
self.logger.addHandler(sh)
self.logger.addHandler(th)
if __name__ == '__main__':
log = Logger('all.log',level='debug')
log.logger.debug('debug')
log.logger.info('info')
log.logger.warning('警告')
log.logger.error('报错')
log.logger.critical('严重')
Logger('error.log',level='error').logger.error('error')
控制台输出为:
when=‘S’,生成的文件如下:
参考博客:
https://www.cnblogs.com/nancyzhu/p/8551506.html
https://blog.youkuaiyun.com/Runner1st/article/details/96481954