🚀 个人主页:xmp65535
🚀 专栏:python技术专栏
目录
一、Python Logging 模块概述
二、相关组件
Logger
Handler
Formatter
Filter
LogRecord
Level
三、基本配置
Formatters格式:
四、记录日志
五、日志记录者(Loggers)
logging.getLogger(name=None)
六、处理器(Handlers)
logging.Handler()
RotatingFileHandler和TimedRotatingFileHandler:
七、进阶使用
日志消息的过滤
日志流的重定向
日志的异步写入
八、propagate属性
九、结论
在软件开发过程中,了解应用程序的运行状态对于调试、监控和解决问题至关重要。日志记录是捕获这些信息的关键工具之一。Python提供了一个强大的日志记录系统,即
logging
模块,它为应用程序提供了一套标准的日志记录接口。
一、Python Logging 模块概述
logging
模块是Python的标准库的一部分,它使得追踪事件、诊断问题和调试应用程序变得容易。它提供了不同的日志级别,如DEBUG、INFO、WARNING、ERROR和CRITICAL,这可以帮助开发者根据重要性区分日志消息。
二、相关组件
在Python的logging
模块中,有几个重要的组件构成了日志系统的基础。下表概述了这些组件以及它们的作用:
组件 | 描述 |
---|---|
Logger | 日志记录器,提供了应用程序可直接使用的接口来记录消息。 |
Handler | 处理器负责将日志记录(由Logger创建)发送到合适的目的地。 |
Formatter | 格式化器决定日志记录的最终输出格式。 |
Filter | 过滤器提供了更细粒度的工具来确定输出哪些日志记录。 |
LogRecord | 日志记录对象,包含了所有日志信息的数据结构。 |
Level | 日志级别如DEBUG、INFO、WARNING、ERROR和CRITICAL,用于区分消息的严重性。 |
Logger
- 描述: Logger是日志记录的主体,提供了应用程序用来记录日志的接口。一个应用程序中可以有多个Logger实例,它们可以通过名称来区分。Logger的层级结构允许以继承和重载设置的方式对日志记录进行灵活管理。
- 用途: 记录应用程序的操作信息,如调试信息、执行流程、异常等。
- 方法示例:
debug()
,info()
,warning()
,error()
,critical()
等方法,对应不同的日志级别。Handler
- 描述: Handler用于将日志记录发送到指定的目的地。Python的
logging
模块提供了多种Handler,比如将日志写入文件的FileHandler
,使用网络协议发送日志的SocketHandler
,将日志输出到控制台的StreamHandler
等。- 用途: 控制日志的输出行为,包括日志存储的位置和方式。
- 类型示例:
StreamHandler
,FileHandler
,HTTPHandler
,SMTPHandler
等。Formatter
- 描述: Formatter定义了日志记录的输出格式。通过Formatter,可以控制日志信息的结构和内容,比如时间戳、日志级别、消息文本等的排列方式和格式。
- 用途: 定制日志信息的展示格式,以便更好地理解和分析日志。
- 配置方法: 通过设置格式字符串来定义日志的输出格式,如
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
。Filter
- 描述: Filter提供了一种过滤日志记录的机制。可以在Logger或Handler级别上应用Filter,只允许符合特定条件的日志记录通过。
- 用途: 实现更精细化的日志控制,比如只记录特定级别以上的日志,或者只记录包含特定文本的日志。
- 实现方式: 继承
logging.Filter
类并重写filter()
方法。LogRecord
- 描述: LogRecord是一个日志记录实例,包含了日志事件的所有信息,如日志消息、发生时间、日志级别等。
- 用途: 在内部传递日志信息。当Logger生成一条日志消息时,它会创建一个LogRecord对象,该对象随后被传递给相应的Handlers进行处理。
- 属性示例:
name
,levelno
,pathname
,msg
,args
等。Level
- 描述: 日志级别表示了日志消息的严重性。
logging
模块预定义了多个级别,包括DEBUG、INFO、WARNING、ERROR和CRITICAL。- 用途: 通过设置不同的日志级别,可以控制日志的输出粒度和范围,比如在开发过程中使用DEBUG级别以获得尽可能多的信息,在生产环境中使用WARNING或更高级别以避免信息泛滥。
- 级别值: DEBUG < INFO < WARNING < ERROR < CRITICAL,值越大表示日志级别越高。
DEBUG
: 10、INFO
: 20、WARNING
: 30、ERROR
: 40、CRITICAL
: 50- 注:级别的数值表明了它们的优先级:数值更低的级别表示更详细的、经常是用于调试目的的信息,而数值更高的级别表示更严重的情况。当你设置一个日志记录器(Logger)的级别时,它会记录该级别以及比该级别更高级别的所有日志消息。例如,如果设置日志级别为
INFO
,则记录器会记录INFO
,WARNING
,ERROR
和CRITICAL
级别的消息,而忽略DEBUG
级别的消息。
工作流程:
三、基本配置
在开始记录日志之前,需要了解如何配置日志系统。基本配置可以通过调用
logging.basicConfig()
函数来完成。这个函数可以指定日志级别、输出格式、输出位置等参数,从而自定义日志记录行为。需要注意的是,logging.basicConfig 方法只能在应用程序中调用一次。如果多次调用 logging.basicConfig 方法,它只会生效一次。因此,如果需要在应用程序中使用多个不同的日志记录器和处理器,最好使用 logging.getLogger() 和 logging.Handler() 方法手动进行配置。
logging.basicConfig() 方法有多个可选参数,用于自定义日志记录行为。下面是 logging.basicConfig 方法的参数详解:
- filename:将日志记录到指定的文件中。如果不指定此参数,则日志消息将被输出到标准输出流中(控制台)。
- filemode:指定日志文件的打开模式,默认为 'a'(追加模式)。如果设置为 'w',则每次运行程序都会清空日志文件中的内容。
- format:指定日志输出格式。默认格式为 '%(levelname)s:%(name)s:%(message)s'。常用格式包括:
- '%(asctime)s %(levelname)s %(message)s':显示时间、级别和消息。
- '%(levelname)s:%(name)s:%(message)s':显示级别、记录器名称和消息。
- '%(asctime)s %(levelname)s %(name)s:%(message)s':显示时间、级别、记录器名称和消息。
- datefmt:指定时间格式。默认格式为 '%Y-%m-%d %H:%M:%S'。具体的时间格式化代码可以参考 Python 的 datetime 模块。
- level:指定日志级别。低于此级别的日志消息将不会被记录。默认级别为 logging.WARNING。可以使用以下级别:
- logging.DEBUG:详细的调试信息。
- logging.INFO:普通的信息消息。
- logging.WARNING:警告消息。
- logging.ERROR:错误消息。
- logging.CRITICAL:严重的错误消息。
- stream:指定日志输出流。默认为 sys.stderr。
Formatters格式:
属性 |
格式 |
描述 |
asctime |
%(asctime)s |
日志产生的时间,默认格式为msecs2003-07-0816:49:45,896 |
msecs |
%(msecs)d |
日志生成时间的亳秒部分 |
created |
%(created)f |
time.tme)生成的日志创建时间戳 |
message |
%(message)s |
具体的日志信息内容 |
filename |
%(filename)s |
生成日志的程序名 |
name |
%(name)s |
日志调用者 |
funcname |
%(funcName)s |
调用日志的函数名 |
levelname |
%(levelname)s |
日志级別( DEBUG,INFO, WARNING, 'ERRORCRITICAL) |
levene |
%( leveling)s |
日志级别对应的数值 |
lineno |
%(lineno)d |
日志所针对的代码行号(如果可用的话) |
module |
%( module)s |
生成日志的模块名 |
pathname |
%( pathname)s |
生成日志的文件的完整路径 |
process |
%( (process)d |
生成日志的进程D(如果可用) |
processname |
%(processName)s |
进程名(如果可用) |
thread |
%(thread)d |
生成日志的线程D(如果可用) |
threadname |
%( threadName)s |
线程名(如果可用) |
exc_info |
%(exc_info)s |
如果日志消息由异常触发,则包括异常信息。 |
relativeCreated |
%(relativeCreated)d |
日志消息被创建的时间(以毫秒为单位),相对于 Logger 对象被创建的时间。 |
下面是一个logging.basicConfig
的使用示例:
import logging
# 配置日志记录器
logging.basicConfig(
filename='example.log',
filemode='w',
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
level=logging.DEBUG
)
# 记录日志
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')
在这个示例中,我们使用 logging.basicConfig 方法自定义了日志记录行为,将日志记录到文件 example.log 中,使用追加模式,指定了输出格式和时间格式,将日志级别设置为 DEBUG。最后,我们记录了不同级别的日志消息。
四、记录日志
配置完成后,可以使用不同的日志级别方法来记录消息:
logging.debug('这是一个debug信息')
logging.info('这是一个info信息')
logging.warning('这是一个warning信息')
logging.error('这是一个error信息')
logging.critical('这是一个critical信息')
五、日志记录者(Loggers)
日志记录者是日志操作的主要接口。可以创建多个记录者,它们可以有独立的配置和日志级别。默认情况下,可以使用
logging.getLogger()
获取一个记录者,并通过名称区分。
logging.getLogger(name=None)
getLogger()
方法用于获取一个日志记录器(Logger),这个记录器可以是一个新的记录器,也可以是一个已经存在的记录器。
- 如果你调用
getLogger()
并且不传递任何参数或者传递None
作为参数,那么你将会获取到一个名为'root'的日志记录器。- 如果传递了一个字符串作为参数,
getLogger(name)
将会返回一个以该字符串命名的日志记录器。
每个Logger都可以有独立的日志级别、处理器和格式化器。这样可以灵活配置日志信息的记录方式。例如:
import logging
# 获取名为'my_logger'的Logger
logger = logging.getLogger('my_logger')
logger.setLevel(logging.DEBUG) # 设置日志级别为DEBUG
# 创建一个Handler来将日志写入文件
file_handler = logging.FileHandler('my_logger.log')
file_handler.setLevel(logging.ERROR) # 该Handler只记录ERROR及以上级别的日志
# 创建一个Handler来将日志输出到控制台
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO) # 控制台仅记录INFO及以上级别的日志
# 设置日志格式
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
file_handler.setFormatter(formatter)
console_handler.setFormatter(formatter)
# 将Handler添加到Logger
logger.addHandler(file_handler)
logger.addHandler(console_handler)
# 使用不同的日志级别记录消息
logger.debug('这是一条DEBUG级别的消息') # 不会被任何处理器记录,因为它低于它们的设置级别
logger.info('这是一条INFO级别的消息') # 会被console_handler处理并显示在控制台
logger.warning('这是一条WARNING级别的消息') # 会被console_handler处理并显示在控制台
logger.error('这是一条ERROR级别的消息') # 会被file_handler和console_handler处理,并记录到文件和控制台
logger.critical('这是一条CRITICAL级别的消息') # 同上
六、处理器(Handlers)
如果要将日志记录发送到不同的目的地,比如文件或者网络,就需要使用处理器(Handlers)。每个处理器可以有自己的日志级别,格式化器(Formatter)和过滤器(Filter)。
logging.Handler()
Handler
是所有日志处理器(Handler)的基类。在logging
模块中,处理器用于定义日志的输出行为,比如将日志发送到控制台、文件、网络等。通过继承Handler
类,可以创建自定义的日志处理器。然而,在大多数情况下,你会使用Handler
的子类,如:
StreamHandler
: 将日志输出到像控制台这样的流。FileHandler
: 将日志写入到文件中。RotatingFileHandler
: 将日志写入到文件,并在文件到达一定大小后进行滚动。SocketHandler
: 将日志通过TCP协议发送到网络。SMTPHandler
: 通过电子邮件发送日志。
每个Handler可以有自己的日志级别和格式化器。如果不显式设置Handler级别,它将默认处理所有级别的日志。例如:
# 创建一个文件处理器,并设置级别为ERROR
file_handler = logging.FileHandler('error.log')
file_handler.setLevel(logging.ERROR)
# 创建一个格式化器,并设置相应的格式
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
file_handler.setFormatter(formatter)
# 将处理器添加到记录者
logger.addHandler(file_handler)
# 这条ERROR级别的信息将被写入'error.log'文件中
logger.error('这是一个error信息')
RotatingFileHandler和TimedRotatingFileHandler:
在Python的logging库中,RotatingFileHandler和TimedRotatingFileHandler都是用于将日志消息写入到文件中的处理器类。它们的主要区别在于如何管理日志文件的大小或数量。
RotatingFileHandler会按照一定的规则(比如文件大小或保留的文件数量)来自动滚动日志文件,从而避免单个文件过大或存储过多历史日志的问题。当达到指定条件时,RotatingFileHandler会自动将当前日志文件重命名为旧的备份文件,并创建一个新的日志文件来记录最新的日志消息。可以使用maxBytes和backupCount两个参数来控制每个日志文件的最大大小和保存的备份文件数目。
例如,下面是一个使用RotatingFileHandler的示例:
import logging
from logging.handlers import RotatingFileHandler
logger = logging.getLogger(__name__)
# 创建RotatingFileHandler对象,设置日志输出路径、最大文件大小和备份数量
handler = RotatingFileHandler('mylog.log', maxBytes=1024*1024, backupCount=5)
# 设置日志级别和输出格式
handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
# 将处理器添加到日志记录器中
logger.addHandler(handler)
# 记录日志
logger.info("This is a test message")
与RotatingFileHandler不同,TimedRotatingFileHandler会按照一定的时间间隔来自动滚动日志文件,从而避免存储过多历史日志的问题。TimedRotatingFileHandler会根据指定的时间间隔(比如每小时、每天或每周)创建新的日志文件,并将当前日志消息写入到这个最新的日志文件中。可以使用when和interval两个参数来控制时间间隔。
例如,下面是一个使用TimedRotatingFileHandler的示例:
import logging
from logging.handlers import TimedRotatingFileHandler
logger = logging.getLogger(__name__)
# 创建TimedRotatingFileHandler对象,设置日志输出路径、时间间隔和备份数量
handler = TimedRotatingFileHandler('mylog.log', when='D', interval=1, backupCount=5)
# 设置日志级别和输出格式
handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
# 将处理器添加到日志记录器中
logger.addHandler(handler)
# 记录日志
logger.info("This is a test message")
#在这个示例中,我们使用TimedRotatingFileHandler创建一个每天滚动一次的日志文件,最多保留5个历史日志文件。当时间间隔到达时,TimedRotatingFileHandler会自动将当前日志文件重命名为旧的备份文件,并创建一个新的日志文件来记录最新的日志消息。
七、进阶使用
日志系统的高级功能包括日志消息的过滤、日志流的重定向以及日志的异步写入等。可以利用过滤器按照具体需求筛选日志信息,或者创建自定义的日志处理器来扩展其功能。
日志消息的过滤
过滤器(Filter)可用于对日志消息进行额外的控制,它允许更精细的日志消息输出。比如,你可能只想记录特定条件下的日志消息。
import logging
class InfoFilter(logging.Filter):
def filter(self, record):
return record.levelno == logging.INFO
logger = logging.getLogger('my_advanced_logger')
logger.setLevel(logging.DEBUG)
# 创建一个流处理器,并设置级别为DEBUG
stream_handler = logging.StreamHandler()
stream_handler.setLevel(logging.DEBUG)
# 为流处理器设置过滤器,只记录INFO级别的日志
stream_handler.addFilter(InfoFilter())
# 为logger添加处理器
logger.addHandler(stream_handler)
# 下面的日志中,只有INFO级别的日志会被输出
logger.debug('这是一个debug信息')
logger.info('这是一个info信息')
logger.warning('这是一个warning信息')
logger.error('这是一个error信息')
日志流的重定向
有时候,将日志流重定向到除了标准输出之外的地方可能非常有用,比如一个文件或者网络。下面的代码示例展示了如何将日志输出到一个文件中。
import logging
# 创建logger
file_logger = logging.getLogger('fileLogger')
file_logger.setLevel(logging.DEBUG)
# 创建一个文件处理器
file_handler = logging.FileHandler('my_log.log')
file_handler.setLevel(logging.DEBUG)
# 创建一个格式化器,并添加到文件处理器上
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
file_handler.setFormatter(formatter)
# 将文件处理器添加到logger
file_logger.addHandler(file_handler)
# 记录一条信息
file_logger.info('这是保存到文件的信息')
日志的异步写入
在一些高性能要求的应用中,异步日志记录可以减少日志记录对应用性能的影响。Python的logging
模块自身不直接支持异步记录,但可以使用concurrent.futures
模块或其他异步框架来实现。以下是一个简单的使用concurrent.futures.ThreadPoolExecutor
来实现异步日志记录的示例。
import logging
from concurrent.futures import ThreadPoolExecutor
# 创建logger
async_logger = logging.getLogger('asyncLogger')
async_logger.setLevel(logging.DEBUG)
# 添加简单的流处理器
stream_handler = logging.StreamHandler()
async_logger.addHandler(stream_handler)
# 定义一个异步记录日志的函数
def async_log(message):
async_logger.info(message)
# 使用线程池执行器来异步记录日志
with ThreadPoolExecutor() as executor:
executor.submit(async_log, '这是异步记录的信息')
八、propagate属性
在Python的logging
模块中,propagate
是Logger对象的一个属性,用于控制日志信息是否传播(或称为“向上传递”)到Logger的父级。默认情况下,这个属性被设置为True
。
当一个Logger对象生成一条日志记录时,如果
propagate
设置为True
,那么除了在当前Logger配置的所有Handlers上处理这条日志记录外,它还会将这条日志记录传递给更高层次的Logger(即它的父级),由父级Logger的Handlers也对这条日志进行处理。这种机制允许创建一个日志处理的层次结构,使得可以很方便地控制不同模块(或不同部分代码)的日志处理方式。
例如,假设我们有一个“root”Logger,以及一个名为"module"的子Logger,子Logger的propagate
属性设置为True
:
import logging
# 配置root Logger
root_logger = logging.getLogger()
root_handler = logging.StreamHandler()
root_formatter = logging.Formatter('%(name)s - %(levelname)s - %(message)s')
root_handler.setFormatter(root_formatter)
root_logger.addHandler(root_handler)
root_logger.setLevel(logging.DEBUG)
# 配置module Logger
module_logger = logging.getLogger('module')
module_logger.setLevel(logging.DEBUG)
# 发送日志消息
module_logger.debug('这条消息将会在root_logger的handler中也被看到,因为propagate默认为True')
在这个例子中,当调用
module_logger.debug()
时,该消息会在module_logger
的Handlers上处理,若module_logger
没有配置任何Handler,消息会向上传递到root_logger
,并且在root_logger
配置的Handler(这里是root_handler
)中输出。
如果你不希望日志在层次结构中向上传递,可以将propagate
属性设置为False
:
module_logger.propagate = False
module_logger.debug('这条消息不会传播到root_logger,只会在module_logger的handler中被处理')
当设置
propagate
为False
时,module_logger
生成的日志记录将不会传递到root_logger
,只会在module_logger
配置的Handlers中被处理。如果module_logger
没有配置任何Handler,这条日志信息将不会被输出到任何地方。这样,可以对日志记录进行更精细的控制,避免不必要的重复日志或者控制特定Logger的日志不被上层Logger截获。文章来源:https://www.toymoban.com/news/detail-856023.html
九、结论
合理使用logging
模块可以极大提升应用程序的可维护性。通过不同的日志级别,格式化和处理器,可以创建出能够满足不同需求的灵活的日志记录方案。无论是进行问题排查还是系统行为分析,logging
模块都是Python开发者的得力助手。文章来源地址https://www.toymoban.com/news/detail-856023.html
到了这里,关于深入理解Python中的日志记录(Logging)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!