Python日志 logging模块详细解析
1. 简介
Python的logging模块提供了一种灵活而强大的方式来记录应用程序的运行日志。它提供了一组组件来构建灵活的日志系统,使得开发者可以将日志记录到控制台、文件、邮件等目的地,并支持日志级别、日志轮换、日志格式化等特性。
2. 基本用法
2.1 logging模块概览
logging模块包含了四个主要的类:Logger、Handler、Filter和Formatter。详见下表:
| 类名 | 作用 |
| ------ | ------ |
| Logger | 提供应用程序可使用的接口 |
| Handler | 将日志记录发送到指定目的地 |
| Filter | 帮助用户过滤日志信息 |
| Formatter | 指定日志格式 |
2.2 创建Logger实例
Logger是应用程序代码可以直接使用的接口。它提供了许多方法来输出日志信息,例如:debug()、info()、warning()、error()和critical()。我们可以通过以下方式创建Logger实例:
import logging
logger = logging.getLogger('my_logger')
通过getLogger()创建的Logger实例可以设置层次结构。例如:
import logging
logger = logging.getLogger('my_logger.sub_logger')
在这个例子中,'my_logger.sub_logger'是Logger实例的名称。如果你不指定Logger实例的名称,则会默认从根Logger中获取一个。在这个例子中,根Logger的名称是'root'。
2.3 创建Handler实例
Handler将日志记录发送到指定目的地。在使用Logger时,我们需要为它配置Handler。常用的Handler有以下几种:
| Handler类型 | 作用 |
| ------ | ------ |
| StreamHandler | 将日志输出到控制台 |
| FileHandler | 将日志输出到文件 |
| SMTPHandler | 将日志发送到指定邮件地址 |
下面是创建StreamHandler的示例:
import logging
logger = logging.getLogger('my_logger')
# 创建一个StreamHandler实例
stream_handler = logging.StreamHandler()
# 将StreamHandler添加到Logger实例中
logger.addHandler(stream_handler)
这段代码将Logger和StreamHandler实例建立关联,日志信息将输出到控制台。
2.4 设置日志级别
Logger实例可以为不同类型的日志信息设置不同的级别。例如,可以将LEVEL设置为DEBUG、INFO、WARNING、ERROR、CRITICAL中的任意一个。只有设置的日志级别大于等于记录日志的级别,才会输出日志信息。例如,如果日志的级别为ERROR,则只会记录LEVEL >= ERROR的日志信息。以下是设置日志级别的示例:
import logging
logger = logging.getLogger('my_logger')
logger.setLevel(logging.DEBUG)
在这个示例中,日志级别被设置为DEBUG级别。
2.5 设置日志格式
Formatter类用于指定日志的格式。我们可以通过以下方式创建Formatter实例:
import logging
logger = logging.getLogger('my_logger')
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
这种格式包含了日志记录时间、Logger实例名称、日志级别和日志内容。
2.6 记录日志信息
Logger提供了丰富的方法来记录日志信息。我们可以使用以下方法记录不同类型的日志信息:
| 方法 | 作用 |
| ------ | ------ |
| debug(msg, *args, **kwargs) | 记录DEBUG级别的日志信息 |
| info(msg, *args, **kwargs) | 记录INFO级别的日志信息 |
| warning(msg, *args, **kwargs) | 记录WARNING级别的日志信息 |
| error(msg, *args, **kwargs) | 记录ERROR级别的日志信息 |
| critical(msg, *args, **kwargs) | 记录CRITICAL级别的日志信息 |
我们可以通过以下方式调用Logger的不同方法来记录不同类型的日志信息:
import logging
logger = logging.getLogger('my_logger')
logger.setLevel(logging.DEBUG)
stream_handler = logging.StreamHandler()
stream_handler.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
stream_handler.setFormatter(formatter)
logger.addHandler(stream_handler)
logger.debug('debug信息')
logger.info('info信息')
logger.warning('warning信息')
logger.error('error信息')
logger.critical('critical信息')
在这个示例中,我们建立了Logger、StreamHandler和Formatter之间的关联,并使用Logger实例的不同方法记录了不同类型的日志信息。
3. 进阶用法
3.1 日志轮换
有时需要在日志文件达到一定大小后,自动切换到新的日志文件继续记录。这种功能称为日志轮换。logging模块提供了多种轮换方式,包括时间轮换、大小轮换等。
下面是使用TimedRotatingFileHandler类实现日志轮换的示例:
import logging
from logging.handlers import TimedRotatingFileHandler
logger = logging.getLogger('my_logger')
logger.setLevel(logging.DEBUG)
handler = TimedRotatingFileHandler('myapp.log', when='midnight', backupCount=7)
handler.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.debug('debug信息')
logger.info('info信息')
logger.warning('warning信息')
logger.error('error信息')
logger.critical('critical信息')
在这个示例中,我们使用了TimedRotatingFileHandler类,当日志文件大小达到一定值或者到了一定时间后,会自动创建新的日志文件并记录日志信息。
3.2 记录异常信息
当程序出现异常时,我们需要对异常信息进行记录。logging模块提供了将捕捉到的异常信息记录到日志信息中的功能。通过捕捉try/except块中的异常信息,我们可以将其记录到日志文件中,以便后续排查问题。
下面是将异常信息记录到日志文件中的示例:
import logging
logger = logging.getLogger('my_logger')
logger.setLevel(logging.DEBUG)
stream_handler = logging.StreamHandler()
stream_handler.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
stream_handler.setFormatter(formatter)
logger.addHandler(stream_handler)
try:
1 / 0
except Exception as e:
logger.error('发生异常了:{}'.format(str(e)))
在这个示例中,我们使用try/except块捕捉了异常信息,并使用Logger实例的error()方法记录了异常信息。通过这种方式,我们可以很方便地记录程序运行中的异常信息,并且防止程序直接崩溃。
3.3 设置日志处理器和格式化器的格式
可以使用logging模块的LogRecord类控制各个处理器和格式化器的格式。例如,可以让所有的日志处理器和格式化器输出线程ID信息:
import logging
import logging.config
LOGGING = {
'version': 1,
'formatters': {
'default': {
'format': '%(asctime)s %(levelname)s [%(thread)d]:%(message)s'
},
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'level': 'INFO',
'formatter': 'default',
},
'file': {
'class': 'logging.FileHandler',
'filename': 'myapp.log',
'mode': 'w',
'level': 'DEBUG',
'formatter': 'default',
},
},
'loggers': {
'': {
'handlers': ['console', 'file'],
'level': 'DEBUG'
}
}
}
logging.config.dictConfig(LOGGING)
root_logger = logging.getLogger()
root_logger.debug('debug信息')
root_logger.info('info信息')
root_logger.warning('warning信息')
root_logger.error('error信息')
root_logger.critical('critical信息')
在这个示例中,我们使用了Logging字典配置文件,并设置了日志格式、处理器和Logger等信息。在格式化器中添加了[%(thread)d]格式控制符,以打印线程ID信息。
3.4 性能优化
日志模块耗费的时间和资源比较多。在一些要求性能的应用程序中,可能需要关闭日志或降低日志级别,以减少日志对性能的影响。可以通过以下方式关闭日志:
import logging
logging.basicConfig(level=logging.CRITICAL)
在这个示例中,我们将根Logger的日志级别设置为CRITICAL级别。这意味着除了CRITICAL日志信息以外,所有的日志信息都不会被记录到日志文件中。这可以帮助我们提高应用程序的性能。
4. 总结
logging模块提供了一种强大而灵活的方式记录应用程序的运行日志。通过了解logging模块的基本用法和进阶用法,可以更好地记录和管理应用程序的日志信息。此外,我们还介绍了如何设置日志轮换、记录异常信息、控制日志处理器和格式化器的格式以及性能优化等方面的内容。希望通过本文对logging模块有更深入的了解和掌握。