01 logging
一. 日志级别与配置基本使用介绍
import logging
# 一:日志配置
"""
注意: 打开文件会发生乱码问题,它的内部运行原理可以理解为就是使用with open()打开文件且默认没有指定字符编码, 默认使用的是操作系统的GBK字符编码写入硬盘, 这个时候我们用文本编辑器打开"access.log"文件我们要使用GBK编码的方式来读。
logging.basicConfig: basicConfig指的是基本的配置
"""
logging.basicConfig(
# 1、日志输出位置:1、终端 2、文件
# 不指定,默认打印到终端(这种方式只能提供一种形式。如果你要往文件中输出就不能往终端中打印. 有局限性)
filename='access.log',
# 2、日志格式
# %(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
# %(name)s Logger的名字, 没有指定默认就是root
# %(levelname)s 文本形式的日志级别(debug调试, info信息, warning警告, error错误, critical危险)
# %(module)s 调用日志输出函数的模块名
# %(message)s 输出的消息
format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
# 3、时间格式
# 这里的时间格式的指定是为了用来替代上面的asctime的时间格式
datefmt='%Y-%m-%d %H:%M:%S %p',
# 4、日志级别
# 级别数字对应的关系: 默认是warning级别,级别是对应的数字是30。由级别控制输出效果, 30级别只能输出30, 40, 50级别的内容及结果.
# 10 --> debug
# 20 --> info
# 30 --> warning
# 40 --> error
# 50 --> critical
level=10,
)
logging.debug('调试debug')
logging.info('消息info')
logging.warning('警告warning')
logging.error('错误error')
logging.critical('危险critical')
'''
# 注意: 下面的root是默认的日志名字, 没有指定,默认就是root。
WARNING:root:警告warn
ERROR:root:错误error
CRITICAL:root:严重critical
'''
二. 日志配置字典
# 1、定义三种日志输出格式,日志中可能用到的格式化串如下
"""
%(name)s Logger的名字, 没有指定默认就是root
%(levelno)s 数字形式的日志级别(10, 20, 30, 40, 50)
%(levelname)s 文本形式的日志级别(debug调试, info信息, warning警告, error错误, critical危险)
%(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”。逗号后面的是毫秒
%(thread)d 线程ID。可能没有
%(threadName)s 线程名。可能没有
%(process)d 进程ID。可能没有
%(message)s 用户输出的消息
"""
# 2. 定义日志的输出格式: 强调!! 其中的%(name)s为调用logging模块后, 使用logging.getlogger()时指定的日志名
standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \
'[%(levelname)s][%(message)s]'
simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
test_format = '%(asctime)s] %(message)s'
# 3、日志配置字典
LOGGING_DIC = {
# version 指定的是你的版本信息。
'version': 1,
# disable_existing_loggers 关闭已存在日志。默认False
'disable_existing_loggers': False,
# formatters 加s代表可以设置很多个不同的日志格式。(注意: 这个不能改,这个是固定的。)
'formatters': {
# standard, simple, test 主要目的是通过自定义这些名字让"handlers"中拿到下面自定义的日志格式的表现形式(提示: 自定义的日志格式命名可以修改)。
'standard': {
# format (注意: 这个不能改,这是固定的格式。) # standard_format 这里可以指定你自定义的日志格式表现的形式。这里是一个变量, 代指的就是步骤2中定义的日志的输出格式.
'format': standard_format
},
'simple': {
'format': simple_format
},
'test': {
'format': test_format
},
},
'filters': {},
# handlers 它是日志的接收者, 它用于控制日志的输出位置。不同的handler可以将日志输出到不同的位置.
'handlers': {
# console, default, other 这是你自定义的handler名(注意: 这里可以修改, 是你自定义的名字)
# 输出位置: 打印到终端的日志, 由下面的class对应的logging.StreamHandler控制
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler', # class 指定日志输出的形式。(注意不能改。)打印到屏幕
'formatter': 'simple' # formatter 指定日志格式输出的形式, 会跑到上面formatters找到你之前所定义的格式simple。
},
# 输出位置: 打印到文件的日志, 由下面的class对应的logging.handlers.RotatingFileHandler控制
'default': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler', # RotatingFileHandler 指定日志轮转, 由下面的maxBytes与backupCount互相组合使用, 防止日志文件内容过大, 读取困难(补充: 内部的底层原理就是当达到了轮转的要求, 就会把你指定的文件"a1.log"重命名, 再新建一个"a1.log"文件, 存放最新的日志内容.)。 # 日志轮转,的重要的意义在于当你的日志文件存储数据过大取的情况。不应该让你的日志在日志文件里不断的累加。如果你的日志文件过大几的话,你打开文件的话就会非常的慢。所以我们需要定期的分割。
'formatter': 'standard',
'filename': 'a1.log',
# maxBytes 最大轮转值, 当达到了这个值, 日志文件就会轮转.默认单位是字节Bytes。这里计算出来是: 5M
'maxBytes': 1024 * 1024 * 5,
'backupCount': 5, # backupCount 指的是最多给你保存几份, 当达到了保存限制, 会删除你最老的日志文件。
'encoding': 'utf-8', # 指定日志文件写入硬盘的编码.
},
# 输出位置: 你指定的文件"a2.log", 由下面的class对应的logging.FileHandler控制
'other': {
'level': 'DEBUG',
'class': 'logging.FileHandler', # FileHandler 指定日志输出的形式。输出到文件中。
'formatter': 'test',
'filename': 'a2.log', # filename 既然要输出到文件中,那必须要指定文件路径,如果是在项目中,我们需要使用os.path等规范化路径。
'encoding': 'utf-8', # encoding 这里指定指定日志文件写入硬盘的编码.
},
},
# loggers 它是日志的产生者, 负责产生不同级别的日志, 产生的日志会传递给上面的handlers中, 让handlers中的每个自定义的"handler"控制输出的位置。
'loggers': {
# logger
# "logger" 指定''这种形式, 在执行logging.getLogger(key)时会判断,如果指定的key在下面的这些"logger"中都没找到, 就会把自定义key交给''中的"logger"处理, 处理以后, 交给上面的handlers进行处理
'': {
'handlers': ['default', 'console'],
# handlers 这里指定你要交给的Handler路径, 交给"default"和"console"上面我们"handlers"中自定义的"handler"处理.
'level': 'DEBUG', # 这里又设置了日志级别,而handler中又设置了日志级别,这里有两层关卡。当使用logger_obj.info()这样的功能输入内容的时候. 会进行判断。如果日志级别满足,那么就会被收取到。满足以后会交给handlers中你自定义的"handler"来进行第二次筛选, 如果又满足,那么就会被你相应的"handler"功能, 进行处理。loggers(第一层日志级别关限制)--->handlers(第二层日志级别关卡限制)
'propagate': False, # 默认为True,向上(更高level的logger)传递,通常设置为False即可,否则会将日志向上层层传递
},
# 这里为你专门的日志名进行提供服务, 在使用loggin.getlogger("日志名")时, 会跑到这里来匹配, 如果当时你指定的"日志名"与下面的key一致的时候就用使用下面的处理方式, 处理当前的日志. 当然没有匹配的情况下会跑到上面你什么都没指定''的里面去, 处理当前的日志, 以你指定的日志名作为你的日志名.
'专门的采集': {
'handlers': ['other', ],
'level': 'DEBUG',
'propagate': False,
},
},
}
三. 使用
# !!!强调!!!
# 1、logging是一个包,需要使用其下的config、getLogger,可以如下导入
# from logging import config # 这里的config是logging下面的包。
# from logging import getLogger
# 2、也可以使用如下导入
import logging.config # 这样连同logging.getLogger都一起导入了,然后使用前缀logging.config
import settings
# import logging.config
# 3、加载配置字典
logging.config.dictConfig(settings.LOGGING_DIC)
# 4、输出日志
logger1 = logging.getLogger('用户交易') # getLogger: 可以拿到你定义的所有的loggers中定义的每个"logger"。
logger1.info('egon儿子alex转账3亿冥币')
# logger2=logging.getLogger('专门的采集') # 名字传入的必须是'专门的采集',与LOGGING_DIC中的配置唯一对应
# logger2.debug('专门采集的日志')