python 的 logging 模块就是为了记录日志使用的,而且线程是安全的
logging主要是以下组件组成:
- 日志器组件 logger : 记录器,应用程序代码能直接使用的接口
- 处理器组件 handler : 处理器,将(记录器产生的)日志记录发送至合适的目的地
- 格式化组件 formatter : 格式化器,指明了最终输出中日志记录的布局
- 过滤组件 filter : 过滤器, 提供了更好的粒度控制,可以决定输出那些日志记录
-
- 日志时间信息在记录器、处理器、过滤器、格式化器之间通过一个日志记录实例来传递
通过调用记录器实例的方法来记录日志,每个记录器实例都有一个名字,名字相当于其命名空间,是一个树状结构
记录器 logger :
- 一个记录器叫: scan, 记录器scan.txt、scan.html、scan.pdf的父节点,记录器的名称,可以随便取。如下
logger = logging.getLogger(__name__)
- 上面这条语句意味着记录器的名字会通过搜索包的层级来获取,根记录器叫: root logger < 如果不指定记录器名称,默认使用根记录器名称
- 记录器通过debug() info() warning() error() critical()方法记录相应级别的日志,根记录器也一样的
处理器 Handler:
- StreamHandler: 将日志输出到终端
- FileHandler (常用): 将日志输出到文件中,根据basicConfig配置的文件路径来输出日志
- BaseRotaingHandler: 循环日志处理器的基类,不能直接被实例化,可使用 RotaingHandler 和 TimedRotaingHandler
- RotaingHandler: 将日志文件记录到磁盘文件,可以设置每个日志文件的最大占用空间
- TimedRotaingHandler: 将日志文件记录到磁盘文件,按固定的时间间隔来循环记录日志
- TimedRotaingFileHandler: 将日志文件记录到文件中,按固定的时间间隔来循环记录日志
- SocketHandler: 将日志信息发送到 TCP/IP 套接字
- DatagramHandler: 将日志信息发送到 UDP 套接字
- SMTPHandler: 将日志文件发送到邮箱
- SysLogHandler: 系统日志处理器,可以将日志文件发送到Windowsx系统时间日志中
- NTEventLogHandler: Windows系统事件处理器,可以将日志发送到Windows系统事件日志中
- MemoryHandler: 实例向内存中的缓存区发送消息,只要满足特定的条件,缓冲区就会被刷新
- HTTPHandler: 是同GET 或 POST 方法向HTTP服务器发送消息
- WatchedFileHandler: 实例监视它们登录到文件,如果文件发生更改,则使用文件名关闭并重新打开
- QueueHandler: 实例向队列发送消息,比如在队列或多处理模块中实现的消息
- NullHandler: 实例不使用错误消息,库开发人员使用日志激励,但希望避免在库用户未配置日志记录时显示“日志记录器 xxx 无法找到任何处理程序”的消息
格式化器 formatter参数
- %(name)s : Logger 的名字
- %(levelno)d : 数字形式的日志级别
- %(levelname)s : 文本形式的日志级别
- %(filename)s : 调用日志输出函数的模块的文件名
- %(lineno)d : 调用日志输出函数的语句所在代码行
- %(asctime)s : 字符串形式的当前时间,默认格式"0000-00-00 00:00:00,000" 逗号后面是毫秒
- %(message)s : 用户输出的信息
- %(pathname)s : 调用日志输出函数的模块的完整路径,可能没有!
- %(module)s : 调用日志输出函数的模块名
- %(funcName)s : 调用日志输出函数的函数名
- %(created)f : 当前时间,用UNIX标准表示时间的浮点数
- %(relativeCreated)d : 输出日志信息,自Logger创建以来的毫秒数
- %(thread)d : 线程ID
- %(threadName)s : 线程名
- %(process)d : 进程ID
日志 basicConfig 函数: 用来配置改变log文件的写入方式,日志级别,时间戳等信息
可通过logging.basicConfig()函数中通过具体参数来更改logging模块的默认行为
- format: 自定义日志打印内容
- filename: 用指定的文件名创建 FildeHandler,这样日志会被存储在指定的文件中
- filemode: 文件打开方式,在指定了 filename 时使用这个参数,默认值为a
- datefmt: 指定日期格式
- level: 设置rootlogger的日志级别
- stream: 用指定的 stream 创建 StreamHandler,可以指定输出到sys.stderr, sys.stdout 或者文件,默认为sys.stderr,
若同时列出了 filename和stream两项参数,则stream参数会被忽略
日志级别:
- DEBUG : 调试时的信息打印
- INFO : 正常的日志信息记录
- WARNING : 发生告警信息,但程序仍正常工作
- ERROR : 发生了错误,部分功能已不正常
- CRITICAL : 发生严重错误,程序可能已经崩溃
示例:简单的将日志打印到终端
import logging
logging.debug("DEBUG Message!")
logging.info("INFO Message!")
logging.warning("WARNING Message!")
logging.error("ERROR Message")
logging.critical("CRITICAL Message!")
示例:通过basicConfig函数配置日志打印格式和内容
import logging
logging.basicConfig(
level=logging.DEBUG, # 指定日志打印级别
format='%(asctime)s %(name)s %(filename)s [line:%(lineno)d] %(levelname)s %(message)s', # 日志打印内容
datefmt="%Y-%m-%d %H:%M:%S", # 时间格式
filename='python_log1.log', # 指定文件位置
filemode='w' # 指定写入模式
)
logging.debug("DEBUG Message!")
logging.info("INFO Message!")
logging.warning("WARNING Message!")
logging.error("ERROR Message")
logging.critical("CRITICAL Message!")
示例:通过日志器、处理器、格式化器构建一个日志器对象
import logging
# 获取日志器组件 : 创建 logger 其名称为 log_module_study,名称任意,也可以为空,默认是:root
logger = logging.getLogger('log_module_study')
# 配置日志文件地址,测试配置在当前目录下
log_file = 'log_module.log'
# 设置 logger 的日志级别 => 全局
logger.setLevel(logging.DEBUG)
# 构建处理器对象:控制台输出流
sh = logging.StreamHandler()
# 设置终端打印最低日志级别 => 局部 当自定义局部日志级别后,不受全局日志级别影响
sh.setLevel(logging.DEBUG)
# 构建处理器对象: 文件输出流,并配置文件路径及写入模式和文件字符格式
fh = logging.FileHandler(filename=log_file, mode="a", encoding="utf-8")
# 设置文件打印最低级别日志 => 局部 当自定义局部日志级别后,不受全局日志级别影响
fh.setLevel(logging.DEBUG)
# 创建一个格式化器,可以创关键不同的格式化器用于不同的handler,当前测试就使用一个
formatter = logging.Formatter(
fmt='%(asctime)s %(name)s %(filename)s Line:%(lineno)d Level: %(levelname)s Massage:%(message)s',
datefmt="%Y-%m-%d %H:%M:%S" # 自定义日期格式
)
# 处理组件添加格式化组件
sh.setFormatter(formatter)
fh.setFormatter(formatter)
# 日志器对象添加处理器对象
logger.addHandler(sh)
logger.addHandler(fh)
# 测试记录日志
logger.debug("DEBUG Message!")
logger.info("INFO Message!")
logger.warning("WARNING Message!")
logger.error("ERROR Message")
logger.critical("CRITICAL Message!")
示例:构建一个日志器函数对象
# *-- coding:utf-8 --*
import logging
def get_logger():
# 获取日志器组件
logger = logging.getLogger()
# 当多个应用调用日志器会出现日志打印多遍的问题,解决方案如下:
# 添加判断: 判断当前日志器对象是否拥有处理器组件
if not logger.handlers: # 如果处理器列表为空,则添加日志
# # 设置日志输出级别=>全局
logger.setLevel(logging.DEBUG)
# 构建处理器对象: 文件输出流
fh = logging.FileHandler(filename='log_func.log', encoding="utf-8")
# 构建处理器对象: 控制台输出流
sh = logging.StreamHandler()
# 设置日志输出级别=>局部 当自定义局部日志级别后,不受全局日志级别影响
sh.setLevel(logging.WARNING)
# 构建格式化组件
fmt = logging.Formatter(
fmt='%(asctime)s %(name)s %(filename)s Line:%(lineno)d Level: %(levelname)s Massage:%(message)s',
datefmt="%Y-%m-%d %H:%M:%S"
)
# 处理组件添加格式化组件
fh.setFormatter(fmt)
sh.setFormatter(fmt)
# 日志器对象添加处理器对象
logger.addHandler(fh)
logger.addHandler(sh)
return logger
logger = get_logger()
# 测试
logger.debug("DEBUG Message!")
logger.info("INFO Message!")
logger.warning("WARNING Message!")
logger.error("ERROR Message")
logger.critical("CRITICAL Message!")