python 日志logging模块学习
logging模块介绍:
logging是python内置的标准库模块,模块提供不同的日志级别,并可以采用不同的方式记录日志,比如:文件,HTTP GET/POST,SMTP,Socket等,甚至可以实现自己的日记记录方式。
模块提供logger,handler,filter,formatter
logger:
提供提供日志接口,供应用代码使用。
logger最常用的操作有两类:配置和发送消息。
通过logger = logging.getLogger(name)获取logger对象,如果不指定name则返回root对象。多次使用相同的name调用getLogger返回同一个logger对象。
logging模块保证在同一个python解释器内多次使用相同的name调用getLogger返回同一个logger对象,即使在多个模块的情况下。
handler:
日志处理器。负责日志的具体怎么处理-----将日志发送到合适的目的地。比如:文件,Socket等。
一个logger对象可以通过addHandler方法添加0到多个handler。每个handler可以定义不同的日志级别,以实现日志分级过滤显示。
filter:
日志过滤器:提供一种优雅的方式决定一个日志记录是否发送到handler
formattler:
定义日志记录输出格式化方式。
发送消息:
使用logger.info(message),或debug(message)等,发送不同级别的日志消息
只有发送的消息级别大于或等于设定的日志级别,才会进行日志记录,否则忽略。
配置方式:
python代码配置,配置文件。
logging的简单使用:
将日志消息同时发送到控制台与日志文件内。
coding=utf-8
import logging
import sys
#定义日志输出格式
formattler = '%(levelname)s - %(name)s - %(asctime)s - %(message)s'
fmt = logging.Formatter(formattler)
#获得logger,默认获得root logger对象
#设置logger级别 debug
#root logger默认的级别是warning级别。
#不设置的话 只能发送 >= warning级别的日志
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
#设置handleer日志处理器,日志具体怎么处理都在日志处理器里面定义
#SteamHandler 流处理器,输出到控制台,输出方式为stdout
# StreamHandler默认输出到sys.stderr
#设置handler所处理的日志级别。
# 只能处理 >= 所设置handler级别的日志
#设置日志输出格式
stream_handler = logging.StreamHandler(sys.stdout)
stream_handler.setLevel(logging.DEBUG)
stream_handler.setFormatter(fmt)
#FileHandler 文件处理器,定义日志输出到mylog.log文件内
# 文件打开方式默认为 a
file_handler = logging.FileHandler('mylog.log')
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(fmt)
#对logger增加handler日志处理器
logger.addHandler(stream_handler)
logger.addHandler(file_handler)
#发送debug级别日志消息
logger.debug('日志测试')
image.png
mylog.log文件内同样出现日志消息。
image.png
logging 的日志级别:
logging 提供了完整的日志体系,支持五种日志级别以便记录程序的执行过程。
DEBUG 详细信息,典型地调试问题的时候会使用。
INFO 证明事情按预期工作。
WARNING 表明发生了一些意外,或者不久的将来会发生问题(如‘磁盘满了’)。软件还是在正常工作。
ERROR 由于更严重的问题,软件已不能执行一些功能了。
CRITICAL 严重错误,表明软件已不能继续运行了。
以上五种日志级别从低到高分别是:DEBUG < INFO < WARNING < ERROR < CRITICAL 。默认的是WARNING,只有日志级别高于WARNING的日志信息才会输出
logging handler 日志处理器:
一些常用的日志处理器handler
-
logging.StreamHandler
使用这个Handler可以向类似与sys.stdout或者sys.stderr的流输出信息,也就是输出到控制台。它的构造函数是:StreamHandler([strm])其中strm参数默认是sys.stderr -
logging.FileHandler
和StreamHandler类似,用于向一个文件输出日志信息。不过FileHandler会帮你打开这个文件。它的构造函数是:FileHandler(filename[,mode])
filename是文件名,必须指定一个文件名。
mode是文件的打开方式。参见Python内置函数open()的用法。默认是’a',即添加到文件末尾。 -
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两个参数和FileHandler一样。
maxBytes用于指定日志文件的最大文件大小。如果maxBytes为0,意味着日志文件可以无限大,这时上面描述的重命名过程就不会发生。
backupCount用于指定保留的备份文件的个数。比如,如果指定为2,当上面描述的重命名过程发生时,原有的chat.log.2并不会被更名,而是被删除。 -
logging.handlers.TimedRotatingFileHandler
这个Handler和RotatingFileHandler类似,不过,它没有通过判断文件大小来决定何时重新创建日志文件,而是间隔一定时间就 自动创建新的日志文件。重命名的过程与RotatingFileHandler类似,不过新的文件不是附加数字,而是当前时间。它的构造函数是:
TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])
其中filename参数和backupCount参数和RotatingFileHandler具有相同的意义。
interval是时间间隔,意思就是间隔多久创建新日志一次。
when参数是一个字符串。表示时间间隔的单位,不区分大小写。它有以下取值:
S 秒
M 分
H 小时
D 天
W 每星期(interval==0时代表星期一)
midnight 每天凌晨
比如:when=‘M’,interval=1 就表示一分钟创建新日志一次。 -
logging.handlers.SocketHandler
-
logging.handlers.DatagramHandler
以上两个Handler类似,都是将日志信息发送到网络。不同的是前者使用TCP协议,后者使用UDP协议。它们的构造函数是:
Handler(host, port)
其中host是主机名,port是端口名
我们来试一下TimedRotatingFileHandler日志处理器
以一分钟创建一次日志文件。
代码如下:
#coding=utf-8
import sys
import time
import logging
import logging.handlers
#定义日志输出格式
formattler = '%(levelname)s - %(name)s - %(asctime)s - %(message)s'
fmt = logging.Formatter(formattler)
#获得logger,默认获得root logger对象
#设置logger级别 debug
#root logger默认的级别是warning级别。
#不设置的话 只能发送 >= warning级别的日志
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
#设置handleer日志处理器,日志具体怎么处理都在日志处理器里面定义
#SteamHandler 流处理器,输出到控制台,输出方式为stdout
# StreamHandler默认输出到sys.stderr
#设置handler所处理的日志级别。
# 只能处理 >= 所设置handler级别的日志
#设置日志输出格式
stream_handler = logging.StreamHandler(sys.stdout)
stream_handler.setLevel(logging.DEBUG)
stream_handler.setFormatter(fmt)
#FileHandler 文件处理器,定义日志输出到mylog.log文件内
# 文件打开方式默认为 a
time_handler = logging.handlers.TimedRotatingFileHandler('mylog.log',when='M',interval=1)
time_handler.setLevel(logging.DEBUG)
time_handler.setFormatter(fmt)
#对logger增加handler日志处理器
logger.addHandler(stream_handler)
logger.addHandler(time_handler)
for i in range(10):
#发送debug级别日志消息
#15秒发送一次日志消息
logger.debug('日志测试'+str(i))
time.sleep(15)
看一下运行结果:15秒发送一次日志消息。
看一下日志文件:的确是一分钟新建一个日志文件。
image.png
要注意 第一个日志文件是 mylog.log.2017-03-09_15-32。
最后一个日志文件才是 mylog.log
image.png
image.png
logging Formatters 日志消息格式化。
Formatters 跟python中的字符串格式化是一个意思,定义了最终log信息的顺序,结构和内容
logging.Formatter(fmt,datefmt)
fmt参数为格式化字符串
datefmt为时间格式化,默认的时间格式为%Y-%m-%d %H:%M:%S
常用格式为:
%(name)s Logger的名字
%(levelno)s 数字形式的日志级别
%(levelname)s 文本形式的日志级别
%(pathname)s 调用日志输出函数的模块的完整路径名,可能没有
%(filename)s 调用日志输出的模块的文件名
%(module)s 调用日志输出函数的模块名
%(funcName)s 调用日志输出函数的函数名
%(lineno)d 调用日志输出函数的语句所在的代码行
%(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示
%(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数
%(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒。datefmt就是设置这个的。
%(thread)d 线程ID。可能没有
%(threadName)s 线程名。可能没有
%(process)d 进程ID。可能没有
%(message)s 用户输出的消息。就是logger.info(message)发送的日志消息。
例如:
'%(levelname)s - %(name)s - %(asctime)s - %(message)s'
表示 输出格式为:
日志级别名称 - logger名字 - 当前时间 - 日志消息
结果:
DEBUG - root - 2017-03-09 15:34:27,963 - 日志测试8
logging 配置:
logging配置有两种方式:python代码内配置,配置文件。
python代码内配置就是上面那样。
下面说一下配置文件:
logging配置文件 是 conf格式的文本文件:
#logging.conf
#logging配置文件
#定义logger模块,root是父类,必须存在,其他的自定义
#logging。getLogger(name) 相当于向loggging模块注册了一种日志打印
#如果name为loggers里面keys的值,则调用对应的配置,如果name没有则调用默认(root)的配置
#name 中用点 . 表示继承关系
#可以有多个,以逗号隔开
[loggers]
keys=root,filelog
#实现logger对应的配置信息
# 必须是 logger_name格式 name为loggers中key的值
#level 日志级别,级别有 DEBUG,INFO,WARNING,ERROR,CRITICAL
#handlers 日志处理器,可以有多个 以逗号隔开
#qualname logger的名称,通过logging.getLogger(name)获取,这里的name便是qualname
# 如果获取的logger 名称不存在,则调用默认(root)logger
#propagate 是否继承符类的配置信息,0:否 1:是
[logger_root]
level=DEBUG
handlers=consoleHandler
qualname=root
#在这里 如果propagate=1,则表示继承父类(root)的配置信息。
#也就是说 既输出到控制台(继承父类的配置)又输出到日志文件
#propagate = 0 表示仅使用自身的配置,仅输出到日志文件
[logger_filelog]
level=DEBUG
handlers=fileHandler
qualname=filelog
propagate=0
#定义handlers
[handlers]
keys=consoleHandler,fileHandler
#handlers的具体配置实现
#必须是 handler_name格式 name为handlers中key的值
#class为logging包里面的handler处理器
#formatter 日志输入格式
#args handler相关参数
[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)
[handler_fileHandler]
class=FileHandler
level=DEBUG
formatter=simpleFormatter
args=('error.log','a')
#定义日志输出格式
[formatters]
keys=simpleFormatter
#日志输出格式化实现
#datefmt 日期格式 对应asctime
#----------------------------
#日志格式
#----------------------------
# %(asctime)s 年-月-日 时-分-秒,毫秒
# %(filename)s 文件名,不含目录
# %(pathname)s 目录名,完整路径
# %(funcName)s 函数名
# %(levelname)s 级别名
# %(lineno)d 行号
# %(module)s 模块名
# %(message)s 日志信息
# %(name)s 日志模块名
# %(process)d 进程id
# %(processName)s 进程名
# %(thread)d 线程id
# %(threadName)s 线程名
#----------------------------
[formatter_simpleFormatter]
format=%(levelname)s - %(name)s - %(asctime)s - %(module)s.%(funcName)s - %(message)s
datefmt=%Y-%m-%d %H:%M:%S
这里有个几个地方需要讲解一下:
logger实现 也就是 logger_name里面的 qualanme 除了root logger以外其他的logger必须都存在,并设置值。
当logging.getLogger(name)时候 如果配置文件中并没有name,那么则默认获取root的配置。
propagate 表示是否继承父logger 也就是 root logger的配置。
如果 propagate = 1 表示继承root logger的配置。
比如:把 logger_filelog里面的 propagate 设置为 1,则使用filelog的时候 即输出到日志文件,又输出到控制台。
设置为 0 则仅输出到日志文件。
propagate默认为 1
下面来使用一下配置文件来配置logging。
logging使用 logging.config.fileConfig(confname)加载日志配置文件。
加载完后 就可以 使用 logging.getLogger(name)来使用logger了。
#coding=utf-8
import logging.config
#加载配置文件
logging.config.fileConfig('logging.conf')
#获取根 root logger 输出到控制台
root_logger = logging.getLogger()
root_logger.debug('输出到控制台')
#获取名称为 filelog的 logger 输出日志消息到日志文件
logger = logging.getLogger('filelog')
logger.debug('输出到日志文件')
#获取配置文件中不存在的logger,如果不存在,则默认使用root logger的配置
name_logger = logging.getLogger('test')
name_logger.debug('使用 配置文件中logger名称不存在的 logger')
结果如下:
image.png
image.png
可以看到 使用 配置文件中不存在的logger,则默认使用的是root logger的配置。
filelog logger 仅输出到了 日志文件中,并没有在控制台输出。
因为 filelog logger 中 propagate = 0 表示不继承 root logger 的配置。
设置为 propagate = 1 则 即输出日志文件,又输出到控制台(root logger的配置是输出到控制台)