python logging模块
logging模块的使用方式
logging模块提供了两种记录日志的方式:
- 第一种是logging提供的模块级别函数
- 第二种是使用Logging日志系统的四大组件
其实,logging所提供的模块级别的日志记录函数也是对logging日志系统相关类的封装而已。
一、使用logging提供的模块级别函数
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
# coding: utf-8 """ 使用模块级别的函数记录日志 配置logging.basicConfig函数,把日志输出到文件 """ import logging import os BASE_DIR = os.path.dirname(os.path.abspath(__file__)) LOG_FILE_PATH = os.path.join(BASE_DIR, "my.log") LOG_FORMAT = "%(asctime)s - %(levelname)s - %(message)s" # 不提供filename则默认输出到控制台 logging.basicConfig(filename=LOG_FILE_PATH, level=logging.DEBUG, format=LOG_FORMAT) logging.debug("This is a debug log.") logging.info("This is a info log.") logging.warning("This is a warning log.") logging.error("This is a error log.") logging.critical("This is a critical log.")
1、logging.basicConfig(**kwargs)函数说明
参数名称 | 描述 |
---|---|
filename | 指定日志输出目标文件的文件名,指定该设置后日志信息就不会被输出到控制台了 |
filemode | 指定日志文件的打开模式,默认为'a'。需要注意的是,该选项要在filename指定时才有效 |
format | 指定日志格式字符串,即指定日志输出时所包含的字段信息以及它们的顺序。logging模块定义的格式字段下面会列出。 |
datefmt | 指定日期/时间格式。需要注意的是,该选项要在format中包含时间字段%(asctime)s时才有效 |
level | 指定日志器的日志级别 |
stream | 指定日志输出目标stream,如sys.stdout、sys.stderr以及网络stream。需要说明的是,stream和filename不能同时提供,否则会引发 ValueError 异常 |
style | Python 3.2中新添加的配置项。指定format格式字符串的风格,可取值为'%'、'{'和'$',默认为'%' |
handlers | Python 3.3中新添加的配置项。该选项如果被指定,它应该是一个创建了多个Handler的可迭代对象,这些handler将会被添加到root logger。需要说明的是:filename、stream和handlers这三个配置项只能有一个存在,不能同时出现2个或3个,否则会引发ValueError异常。 |
2、logging模块定义的格式字符串
字段/属性名称 | 使用格式 | 描述 |
---|---|---|
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 | %(threadName)s | 线程名称 |
logging.info("name: %s" % "Mikle")和logging.info("name: %s", "Mikle")这两种是一样的,因为message是通过msg % args
计算得到的。
3、logging日志级别
日志等级(level) | 描述 |
---|---|
DEBUG | 最详细的日志信息,典型应用场景是 问题诊断 |
INFO | 信息详细程度仅次于DEBUG,通常只记录关键节点信息,用于确认一切都是按照我们预期的那样进行工作 |
WARNING | 当某些不期望的事情发生时记录的信息(如,磁盘可用空间较低),但是此时应用程序还是正常运行的 |
ERROR | 由于一个更严重的问题导致某些功能不能正常运行时记录的信息 |
CRITICAL | 当发生严重错误,导致应用程序不能继续运行时记录的信息 |
二、logging四大组件
组件名称 | 对应类名 | 功能描述 |
---|---|---|
日志器 | Logger | 提供了应用程序可一直使用的接口 |
处理器 | Handler | 将logger创建的日志记录发送到合适的目的输出 |
过滤器 | Filter | 提供了更细粒度的控制工具来决定输出哪条日志记录,丢弃哪条日志记录 |
格式器 | Formatter | 决定日志记录的最终输出格式 |
logging组件记录日志流程
- 定义日志器对象logger
- 设置日志器对象的日志等级,log等级总开关
- 定义处理器对象handler,一个logger可以对应多个处理器对象
- 定义格式器对象Formatter
- 把格式器对象添加到处理器对象
- 把处理器对象添加到日志器对象
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
# coding: utf-8 """ 1)将所有级别的所有日志都写入磁盘文件中 2)all.log文件中记录所有的日志信息,日志格式为:日期和时间 - 日志级别 - 日志信息 3)error.log文件中单独记录error及以上级别的日志信息,日志格式为:日期和时间 - 日志级别 - 文件名[:行号] - 日志信息 4)要求all.log在每天凌晨进行日志切割(TimedRotatingFileHandler) """ import logging import logging.handlers logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) # 1、TimedRotatingFileHandler rf_handler = logging.handlers.TimedRotatingFileHandler('all.log', when='midnight', interval=1, backupCount=7) fmt = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') rf_handler.setFormatter(fmt) # 2、FileHandler f_handler = logging.FileHandler('error.log') f_handler.setLevel(logging.ERROR) fmt2 = logging.Formatter("%(asctime)s - %(levelname)s - %(filename)s[:%(lineno)d] - %(message)s") f_handler.setFormatter(fmt2) logger.addHandler(rf_handler) logger.addHandler(f_handler) logger.debug('debug message') logger.info('info message') logger.warning('warning message') logger.error('error message') logger.critical('critical message')
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#! /usr/bin/env python # -*- coding: utf-8 -*- """ log模块第一次导入的时候,是作为一个文件被查找到的。查找成功后,文件会跑一个生成log实例的逻辑,然后把它加入到全局sys.modules字典里面。 以后所有模块的`import log`动作都会绕开文件查找的过程,直接在sys.modules里面找这个模块。 """ """ 可以直接使用 import log log.info() log.error() ... """ import os import sys import logging import logging.handlers # 当前目录下会生成对应的log文件 BASE_DIR = os.path.dirname(os.path.abspath(__file__)) ACCESS_LOG_PATH = os.path.join(BASE_DIR, "access.log") ERROR_LOG_PATH = os.path.join(BASE_DIR, "error.log") class Log(object): ACCESS_LOG_PATH = ACCESS_LOG_PATH ERROR_LOG_PATH = ERROR_LOG_PATH FMT = ( '[%(levelname)s][%(name)s:%(process)d][%(asctime)s]' + ': %(message)s') def __init__(self, name): logger = logging.getLogger(name) fmt = logging.Formatter(self.FMT) trf_handler = logging.handlers.TimedRotatingFileHandler( self.ACCESS_LOG_PATH, 'D', 1, 7) trf_handler.setLevel(logging.INFO) trf_handler.setFormatter(fmt) rf_handler = logging.handlers.RotatingFileHandler( self.ERROR_LOG_PATH, maxBytes=1024*1024, backupCount=5) rf_handler.setLevel(logging.ERROR) rf_handler.setFormatter(fmt) logger.addHandler(trf_handler) logger.addHandler(rf_handler) self.logger = logger def __call__(self): return self.logger sys.modules[__name__] = Log(__name__)()
RotatingFileHandler
日志回滚
比如日志文件是chat.log,当chat.log达到指定的大小之后,RotatingFileHandler自动把文件改名为chat.log.1。不过,如果chat.log.1已经存在,会先把chat.log.1重命名为chat.log.2。最后重新创建 chat.log,继续输出日志信息。【这样保证了chat.log里面是最新的日志】
(原文链接:https://blog.csdn.net/chpllp/article/details/72649506)
RotatingFileHandler参数说明
def __init__(self, filename, mode='a', maxBytes=0, backupCount=0, encoding=None, delay=0)
参数 | 描述 |
---|---|
filename | log文件名 |
mode | 写入日志文件的模式,默认'a',追加 |
maxBytes |
日志文件大小,即大于多少时切割日志。如果是0,则不切割。 比如50M,maxBytes=1024*1024*50 |
backupCount | 文件备份数量,比如日志文件是chat.log,当chat.log达到指定大小后,RotatingFileHandler自动把文件改名为chat.log.1,如果backupCount=5,则文件名一直到chat.log.5 |
encoding | 写入日志编码,默认None |
delay | 写入log文件的延迟时间,默认0 |
TimedRotatingFileHandler
按时间切割日志
TimedRotatingFileHandler参数说明
def __init__(self, filename, when='h', interval=1, backupCount=0, encoding=None, delay=False, utc=False)
参数 | 描述 |
---|---|
filename | log文件名 |
when |
切割日志的时间 "S": 每秒 "M": 每分钟 "H": 每小时 "D": 每天(每天的0:00) "MIDNIGHT": 与"D"相同 "W{0~6}": 每个星期,W0 表示周日 when参数忽略大小写,即用大小写都行,因为参数会先upper()转换成大写。用"M"和"m"是相同的。 |
interval |
间隔,间隔多少个when执行一次。如果when="D", interval=2,则每隔两天切割一次。默认1。 |
backupCount | 备份数量,备份的log文件后缀会跟上时间 |
encoding | 写入日志编码,默认None |
delay | 写入log文件的延迟时间,默认0 |
utc | 当when是"D"或"W{0~6}"时,是否以UTC的时间来切割,默认False,表示本地时间。 |
RotatingFileHandler存在的问题
参考文档