1.1、logging模块
Python内置的日志模块,日志是对软件执行时所发生事件的一种追踪方式。软件开发人员对他们的代码添加日志调用,借此来指示某事件的发生。一个事件通过一些包含变量数据的描述信息来描述(比如:每个事件发生时的数据都是不同的)。开发者还会区分事件的重要性,重要性也被称为 等级 或 严重性。
正常的项目想看 程序状态变化,尽量不要用print(断点调试/日志)。任何语言、任何程序都要记录日志。
Python中的日志要么输出至控制台,要么保存至文件。
1.2、日志级别
CRITICAL = 50 #FATAL = CRITICAL
ERROR = 40
WARNING = 30 #WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0 #不设置
1.3、默认级别为warning,默认打印到终端
import logging
logging.debug('调试debug')
logging.info('消息info')
logging.warning('警告warn')
logging.error('错误error')
logging.critical('严重critical')
'''
WARNING:root:警告warn
ERROR:root:错误error
CRITICAL:root:严重critical
'''
1.4、为logging模块指定全局配置,针对所有logger有效,控制打印到文件中
可在logging.basicConfig()函数中通过具体参数来更改logging模块默认行为,可用参数有
(1)filename:用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。
(2)filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。
(3)format:指定handler使用的日志显示格式。
(4)datefmt:指定日期时间格式。
(5)level:设置rootlogger(后边会讲解具体概念)的日志级别
(6)stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件,默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。
可指定的格式有:
实际应用
执行程序为
import logging
logging.basicConfig(filename='access.log',
format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
datefmt='请叫我龙哥-v-%Y*%m*%d %H:%M:%S %p',
level=10)
logging.debug('调试debug')
logging.info('消息info')
logging.warning('警告warn')
logging.error('错误error')
logging.critical('严重critical')
#将filename='access.log'去掉就会往终端打印
# 输出的日志打印到桌面改成gbk(其实就是写文件,默认变编码windows系统,所以打出来会乱码)
# 默认级别为warning,默认打印到终端
输出的结果为:
请叫我龙哥-v-2020*12*20 22:31:07 PM - root - DEBUG -1-日志模块: 调试debug
请叫我龙哥-v-2020*12*20 22:31:07 PM - root - INFO -1-日志模块: 消息info
请叫我龙哥-v-2020*12*20 22:31:07 PM - root - WARNING -1-日志模块: 警告warn
请叫我龙哥-v-2020*12*20 22:31:07 PM - root - ERROR -1-日志模块: 错误error
请叫我龙哥-v-2020*12*20 22:31:07 PM - root - CRITICAL -1-日志模块: 严重critical
1.5、 logging模块的Formatter,Handler,Logger,Filter对象
logging模块的四个对象:
(1)logger:产生日志的对象
(2)Filter:过滤日志的对象
(3)Handler:接收日志然后控制打印到不同的地方,FileHandler用来打印到文件中,StreamHandler用来打印到终端
(4)Formatter对象:可以定制不同的日志格式对象,然后绑定给不同的Handler对象使用,以此来控制不同的Handler的日志格式
如何使用
logging模块的应用
'''
critical=50
error =40
warning =30
info = 20
debug =10
'''
import logging
(1)logger对象:负责产生日志,然后交给Filter过滤,然后交给不同的Handler输出
logger=logging.getLogger(__file__)
(2)Filter对象:不常用,略
(3)Handler对象:接收logger传来的日志,然后控制输出到不同的位置。
h1=logging.FileHandler('t1.log') #定义一个输出至当前目录文件t1.log的Handler对象.
h2=logging.FileHandler('t2.log') #定义一个输出至当前目录文件t2.log的Handler对象.
h3=logging.StreamHandler() # 定义一个输出至终端的Handler对象.
(4)Formatter对象:定义日志格式
formmater1=logging.Formatter('%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',)
formmater2=logging.Formatter('%(asctime)s : %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',)
formmater3=logging.Formatter('%(name)s %(message)s',)
(5)为Handler对象绑定格式
h1.setFormatter(formmater1)
h2.setFormatter(formmater2)
h3.setFormatter(formmater3)
(6)将Handler添加给logger并设置日志级别,1个logger对象可以绑定多个Handler,用以输出至不同位置。
logger.addHandler(h1)
logger.addHandler(h2)
logger.addHandler(h3)
logger.setLevel(10) # debug级别及以上的日志都会输出至两个日志文件和终端
(7)测试
logger.debug('debug')
logger.info('info')
logger.warning('warning')
logger.error('error')
logger.critical('critical')
1.6、 Logger与Handler的级别
logger是第一级过滤,然后才能到handler,我们可以给logger和handler同时设置level,如果将logger等级设为debug,handler设为info,那么handler对象的输出不会包含debug级别的日志,因为debug < info
# 验证
import logging
# 定义一个Formatter对象
fmt = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',)
# 定义一个标准输出的Handler对象-输出到终端
std = logging.StreamHandler()
# 将Formatter绑定给Handler,设定日志等级为20
std.setFormatter(fmt)
std.setLevel(20)
# 定义一个Logger名字为root,设定日志等级为10
log1 = logging.getLogger('root')
log1.setLevel(10)
# 将Handler对象绑定给Logger
log1.addHandler(std)
# 产生日志.
log1.debug('debug信息')
log1.info('info信息')
输出的结果为:
2020-12-21 16:50:38 PM - root - INFO -code: info信息
可以看到debug信息并没有输出,因为Handler对象的等级为20,只有info及以上级别的信息会输出,debug会被过滤掉。
Formatter、Handler和Logger对象的使用顺序为:
(1)先产生Formatter对象,定义不同日志格式。
(2)产生Handler对象,定义不同的输出位置,定义Handler对象过滤日志的等级。
(3)将Formatter对象绑定给Handler对象,通常输出至终端的日志格式要比输出至文件的日志格式要精简。
(4)产生Logger对象,在括号内定义对象的名称,也就是%(name)s所输出的内容。
(5)将Handler对象绑定给Logger,一个Logger对象可以绑定多个Handler。
1.7、logging的进阶使用
通常我们会使用一个配置字典来定义日志。实例:
1、导入logging模块。
import os
import logging
import logging.config
2、定义三种日志输出格式。
standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d][%(levelname)s][%(message)s]' # 其中name为getlogger指定的名字
simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s'
3、定义日志文件位置。
# 动态获取目录
logfile_dir = os.path.dirname(os.path.dirname(__file__))
logfile_name = 'f1.log' # 日志文件名
# 如果不存在定义的日志目录就创建一个
if not os.path.isdir(logfile_dir):
os.mkdir(logfile_dir)
# log文件的完整路径
logfile_path = os.path.join(logfile_dir, logfile_name)
4、定义配置字典。通常会放在配置文件中,比如项目conf目录下settings文件中。
LOGGING_DIC = {
'version': 1, # 配置字典的版本.
'disable_existing_loggers': False, # 是否关闭已存在的日志,默认False.
'formatters': { # 先定义的多个Formatter对象。
'standard': { # Formatter对象standard,格式为上述变量内的值.
'format': standard_format
},
'simple': { # Formatter对象simple,格式为上述变量内的值.
'format': simple_format
},
},
'filters': {}, # Filter对象,不常用.
'handlers': { # 里面是定义的多个Handler对象。
'console': { # 打印到终端的Handler对象console
'level': 'DEBUG', # 级别为DEBUG
'class': 'logging.StreamHandler', # 打印到屏幕
'formatter': 'simple', # 绑定Formatter对象为simple
},
'default': { # 打印到文件的Handler对象default。
'level': 'DEBUG', # 级别为DEBUG
'class': 'logging.handlers.RotatingFileHandler', # 保存到文件
'formatter': 'standard', # 绑定Formatter对象为standard
'filename': logfile_path, # 指定日志文件路径
# 指定文件大小,单位为字节.
'maxBytes': 1024*1024*5, # 日志大小 5M
'backupCount': 5, # 最大保存5个日志文件,多了就会把最旧的那个文件删除。
'encoding': 'utf-8', # 日志文件的编码,通常指定为utf-8
},
},
'loggers': { # 里面是定义的多个logger对象
"""
******此处 'handlers': ['terminal','file1_hanlder','file2_hanlder']与下面不一致意思以后可以自定义******
'权限相关': {
'handlers': ['terminal','file1_hanlder','file2_hanlder'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
'level': 'DEBUG',
'propagate': False, # 向上(更高level的logger)传递
},
"""
# ''所定义的配置就是logging.getLogger(__name__)拿到的logger配置
'': {
'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
'level': 'DEBUG',
'propagate': False, # 向上(更高level的logger)传递,通常设置为False即可,否则会一份日志向上层层传递
},
},
}
5、在其他文件中导入配置字典,logging模块是个包,要使用里面的方法可以通过如下方式导入。
from logging import config
from logging import getLogger
# 导入配置字典
from conf import settings
6、加载配置
logging.config.dictConfig(settings.LOGGING_DIC)
7、生成logger对象,输出日志。
logger1 = logging.getLogger('name')
logger1.info('请叫我longge')
8、结果为:
# console Handler对象会输出至屏幕。
[INFO][2020-12-20 20:00:11,247][code.py:127]请叫我longge
# default Handler对象会输出至conf的父目录下f1.log文件中。
[2020-12-20 20:00:11,247][MainThread:9032][task_id:name][code.py:127][INFO][请叫我longge]
9、如果要在其他文件中使用该配置,那么也要重复执行导入配置字典操作,所以我们可以将导入字典这步操作写入字典所在文件中,将之放入一个函数,以后再导入该函数即可:
def get_logger(name):
logging.config.dictConfig(LOGGING_DIC)
logger = logging.getLogger(name)
return logger
#为甚么要自己定义一个get_logger函数
(1)getlogger这个功能是别人写的,系统内置的模块,需要自定义一个函数,以后调用的时候方便,防止忘记这个功能
(2)以后有可能还要添加功能,这个时候就需要使用函数直接在上面添加即可
10、在其他文件中使用
from conf.settings import get_logger
logger1 = get_logger('name')
logger1.info('请叫我longge')
所得到的的结果也相同,并且还能在产生logger对象时,可以在函数中自定义添加其他功能,更加方便使用。
参考文档:https://docs.python.org/zh-cn/3/library/logging.html?highlight=loggin#module-logging