共计 4954 个字符,预计需要花费 13 分钟才能阅读完成。
一. 什么是 logging 模块
- logging 模块是 Python 自带的标准模块
二.logging 模块有什么作用
- 主要用于输出运行日志
- 可以控制输出日志的等级, 过滤一些重要信息, 不显示大量无关要紧的调试信息
- 日志保存的路径, 可以是输出到终端, 也可以是输出到文件
- 以及文件轮转等等, 日志文件轮转指的是设置保存日志文件个数, 当超过最大日志文件个数, 最早的那个日志文件会被删除
三.logging 模块的使用
1. 直接导入 logging 模块
import logging
🍚先进行日志的基本配置
logging.basicConfig(# filename='access.log', # 日志名字 (不指定默认输出到终端)
format='%(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s', # 日志格式
datefmt='%Y-%m-%d %H:%M:%S %p', # 时间格式
level=30, # 日志等级
)
🍚进行日志输出
logging.debug('在大楼使用电子设备') # 10 调试信息
logging.info('大楼里面使用打火机') # 20 正常运行信息
logging.warning('大楼里抽烟') # 30 警告 可能出错
logging.error('正在大楼里玩火') # 40 出错
logging.critical('拿着手榴弹在大楼里溜达') # 50 出错长时间不管会崩溃
''' 输出结果
2020-12-11 19:50:30 PM - root - WARNING - test: 大楼里抽烟
2020-12-11 19:50:30 PM - root - ERROR - test: 正在大楼里玩火
2020-12-11 19:50:30 PM - root - CRITICAL - test: 拿着手榴弹在大楼里溜达
'''
🍚通过日志等级过滤掉了 "debug" 以及 "info" 的日志信息 (大于以及等于你设置的那个等级才会输出)
四.logging 模块的四种对象
1.logger : 负责生产日志
logger1 = logging.getLogger('[日志名]')
2.fitter : 过滤日志 (不常用)
玉炉香 红蜡泪 偏照画堂秋思
3.handler : 控制日志输出的位置 (文件 or 终端)
fh1 = logging.FileHandler(filename='a1.log', encoding='utf-8') # 文件 a1
fh2 = logging.FileHandler(filename='a2.log', encoding='utf-8') # 文件 a2
sh = logging.StreamHandler() # 终端
4.formatter : 控制日志的格式
formatter1 = logging.Formatter(fmt='%(asctime)s - %(name)s - %(levelname)s - %(module)s: %(massage)s', # 日志输出格式
datefmt='%Y-%m-%d %H:%M:%S %p', # 时间格式
)
-
日志输出格式
属性名称 | 使用格式 | 作用 |
---|---|---|
asctime | %(asctime)s | 日志事件发生的时间 -- 人类可读时间,如:2003-07-08 16:49:45,896 |
created | %(created)f | 日志事件发生的时间 -- 时间戳,就是当时调用 time.time()函数返回的值 |
relativeCreated | %(relativeCreated)d | 日志事件发生的时间相对于 logging 模块加载时间的相对毫秒数(目前还不知道干嘛用的) |
msecs | %(msecs)d | 日志事件发生事件的毫秒部分 |
levelname | %(levelname)s | 该日志记录的文字形式的日志级别('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL') |
levelno | %(levelno)s | 该日志记录的数字形式的日志级别(10, 20, 30, 40, 50) |
name | %(name)s | 所使用的日志器名称,默认是 'root',因为默认使用的是 rootLogger |
message | %(message)s | 日志记录的文本内容,通过 msg % args 计算得到的 |
pathname | %(pathname)s | 调用日志记录函数的源码文件的全路径 |
filename | %(filename)s | pathname 的文件名部分,包含文件后缀 |
module | %(module)s | filename 的名称部分,不包含后缀 |
lineno | %(lineno)d | 调用日志记录函数的源代码所在的行号 |
funcName | %(funcName)s | 调用日志记录函数的函数名 |
process | %(process)d | 进程 ID |
processName | %(processName)s | 进程名称,Python 3.1 新增 |
thread | %(thread)d | 线程 ID |
threadName | %(thread)s | 线程名称 |
五. 日志字典配置
#🍚自定义日志的输出格式
formatter1_format = '%(asctime)s %(name)s %(filename)s:%(lineno)d %(levelname)s: %(message)s'
formatter2_format = '%(asctime)s %(name)s : %(message)s'
formatter3_format = '%(asctime)s : %(message)s'
#🍚通过变量的方式存放路径, 也可以使用 "os.path" 来规范路径
logfile_path1 = r'F:\Pycharm File\PycharmProjects\python 正课 \day18\a1.log' # log 文件名
logfile_path2 = r'F:\Pycharm File\PycharmProjects\python 正课 \day18\a2.log' # log 文件名
#🍚log 配置字典, 里面就是上面提到的四种对象
LOGGING_DIC = {
'version': 1, # 指定版本信息
'disable_existing_loggers': False, # 关闭已存在日志。默认 False
# 🔰控制日志的格式
'formatters': { # 固定格式不能修改
"formatter1": { # 开头自定义的日志输出格式名
'format': formatter1_format # "format" 固定格式不能修改
},
'formatter2': {'format': formatter2_format},
'formatter3': {'format': formatter3_format},
},
# 🔰过滤日志 (不常用)
'filters': {},
# 🔰控制日志输出的位置
'handlers': {
'file1_hanlder': { # 自定义 "handlers" 名字, 可以改
'level': 'DEBUG', # 日志过滤等级
'class': 'logging.FileHandler', # 保存到文件里面去(日志保存的形式)
'formatter': 'formatter1', # 绑定的日志输出格式
'filename': logfile_path1, # 制定日志文件路径
'encoding': 'utf-8', # 日志文件的编码,不再担心乱码问题
},
'file2_hanlder': {
'level': 'DEBUG',
'class': 'logging.FileHandler',
'formatter': 'formatter2',
'filename': logfile_path2,
'encoding': 'utf-8',
},
'terminal': {# 自定义的 "handlers" 名字(终端)
'level': 'DEBUG', # 日志过滤等级
'class': 'logging.StreamHandler',# 打印到屏幕
'formatter': 'formatter3' # 日志输出格式
},
},
# 🔰负责生产日志
'loggers': {# ''代表默认的, 在执行'logging.getLogger("key")'时, 在 "loggers" 里面没有找到这个 "key" 时就使用这个'': {
# 这里把上面定义的两个 handler 都加上,即 log 数据既写入文件又打印到屏幕
'handlers': ['file1_hanlder', 'file2_hanlder','terminal'],
'level': 'DEBUG',
'propagate': False, # 向上 (更高 level 的 logger) 传递, 默认 True, 通常设置为 False
},
# 在执行 'logging.getLogger("key")' 时, 在 "loggers" 里面找到这个 "key" 时就使用这个
'自定义日志名 1': {'handlers': ['terminal'],
'level': 'DEBUG',
'propagate': False,
},
'自定义日志名 2': {'handlers': ['file2_hanlder','terminal'],
'level': 'INFO',
'propagate': False,
},
},
}
六. 导入字典模块来进行使用
🍚先导入 "setting.py" 以及 "logging.config"
import logging.config
from conf import setting
🍚加载配置字典
logging.config.dictConfig(setting.LOGGING_DIC)
🔰测试一:
logger1 = logging.getLogger('自定义日志名 1') # 执行后回去日志字典的 "logger" 里面找这个 '自定义日志名 1'(key)
logger1.info('派大星向海绵宝宝转账 : $1000000 万')
🔰测试二:
logger2 = logging.getLogger('自定义日志名 2')
logger2.error('派大星向章鱼哥转账 : $1000000 万')
🔰测试三:
logger3 = logging.getLogger('找不到就默认')
logger3.info('派大星向蟹老板转账 : $1000000 万')
''' 日志输出结果
2020-12-11 21:13:10,758 : 派大星向海绵宝宝转账 : $1000000 万
2020-12-11 21:13:10,758 : 派大星向章鱼哥转账 : $1000000 万
2020-12-11 21:13:10,758 : 派大星向蟹老板转账 : $1000000 万
'''
七. 日志级别的两层关卡
-
第一层是 logger 中设置的日志级别
-
第二层是 handler 中设置的日志级别
🔰当使用 "logger_obj.info("XXXX")"/"logger_obj.error("XXXX")" 等等这样的功能输入内容的时候
🔰"logger" 中的日志等级会进行判断 / 过滤如果日志级别满足,那么就会被收取到
🔰满足以后会交给 "handlers" 中你自定义的 "handler" 日志等级来进行第二次过滤
🔰如果又满足,那么就会被你相应的 "handler" 功能进行处理
八. 日志功能在实际应用中的简单示例
- 以下只是截取了程序的一小段来做演示(倒数第二行为记录日志)
from db import db_handler
from lib import common
def register_interface(name, password, balance=15000):
'''
注册接口.
:param name: 用户名
:param password: 密码
:param balance: 确认密码
:return:True,False
'''
user_dic = db_handler.select(name)
if user_dic:
return False, '用户已存在'
else:
user_dic = {'name': name, 'password': password, 'balance': balance,
'locked': False, 'bankflow': [], 'shoppingcart': {}}
db_handler.save(user_dic)
user_logger.info('用户 %s 注册成功' % name) # 如果注册成功就会记录这个用户的注册信息日志
return True, '注册成功'
完整代码可参考 ATM 简单项目实现
正文完