39 logging 模块

294次阅读
没有评论

共计 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,
        },
    },
}

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

39 logging 模块

🍚先导入 "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 简单项目实现

Github 完整项目下载

正文完
 
shawn
版权声明:本站原创文章,由 shawn 2023-06-16发表,共计4954字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)