一.什么是 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',  # 时间格式
)
  • 日志输出格式

属性名称格式说明
name%(name)s日志的名称
asctime%(asctime)s可读时间,默认格式‘2003-07-08 16:49:45,896’,逗号之后是毫秒
filename%(filename)s文件名,pathname的一部分
pathname%(pathname)s文件的全路径名称
funcName%(funcName)s调用日志多对应的方法名
levelname%(levelname)s日志的等级
levelno%(levelno)s数字化的日志等级
lineno%(lineno)d被记录日志在源码中的行数
module%(module)s模块名
msecs%(msecs)d时间中的毫秒部分
process%(process)d进程的ID
processName%(processName)s进程的名称
thread%(thread)d线程的ID
threadName%(threadName)s线程的名称
relativeCreated%(relativeCreated)d日志被创建的相对时间,以毫秒为单位

五.日志字典配置

import os#🍚自定义日志的输出格式
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_path1 = os.path.join(os.path.dirname(__file__),'a1.log')  # log文件名
logfile_path2 = os.path.join(os.path.dirname(__file__),'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,
        },
    },
}

六.导入字典模块来进行使用

image-20201211210815394

🍚先导入"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 commondef 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, '注册成功'