Python 的 logging
模块是标准库的一部分,提供了一个灵活且强大的框架,用于记录应用程序的运行日志。它不仅能帮助开发者调试和分析代码,还能在生产环境中监控应用程序的状态。
1. 基本用法
1.1 导入模块和基本配置
在开始使用 logging
模块之前,需要先导入它并进行基本配置。
python
import logging
# 基本配置
logging.basicConfig(level=logging.DEBUG)
1.2 记录日志
使用不同级别的日志记录函数,可以记录不同严重程度的日志信息。常用的日志级别从低到高依次为:DEBUG、INFO、WARNING、ERROR、CRITICAL。
python
logging.debug("这是一个调试信息")
logging.info("这是一个信息")
logging.warning("这是一个警告信息")
logging.error("这是一个错误信息")
logging.critical("这是一个严重错误信息")
2. 日志配置
2.1 配置日志格式
可以通过 basicConfig
函数设置日志的输出格式,包括时间、日志级别、消息等。
python
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
2.2 输出到文件
将日志信息输出到文件,而不仅仅是控制台。
python
logging.basicConfig(
filename='app.log',
filemode='a',
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
3. 高级用法
3.1 日志器、处理器和格式器
logging
模块使用三个主要的组件来记录和管理日志:日志器(Logger)、处理器(Handler)和格式器(Formatter)。
3.1.1 创建日志器
日志器是日志记录的入口,通常会为每个模块或子系统创建不同的日志器。
python
logger = logging.getLogger('my_logger')
logger.setLevel(logging.DEBUG)
3.1.2 添加处理器
处理器决定了日志信息的输出位置,可以是控制台、文件、网络等。
python
# 控制台处理器
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG)
# 文件处理器
file_handler = logging.FileHandler('app.log')
file_handler.setLevel(logging.ERROR)
# 添加处理器到日志器
logger.addHandler(console_handler)
logger.addHandler(file_handler)
3.1.3 设置格式器
格式器定义了日志信息的输出格式。
python
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# 设置格式器到处理器
console_handler.setFormatter(formatter)
file_handler.setFormatter(formatter)
3.2 日志级别
每个日志器和处理器都有自己的日志级别,只有日志器的级别高于或等于处理器的级别时,日志信息才会被处理器处理。
python
logger.setLevel(logging.DEBUG)
console_handler.setLevel(logging.INFO)
file_handler.setLevel(logging.ERROR)
3.3 捕获异常信息
可以将异常信息记录到日志中,便于调试和问题排查。
python
try:
1 / 0
except ZeroDivisionError as e:
logger.error("除以零错误", exc_info=True)
3.4 多个日志器
可以创建多个日志器来记录不同模块的日志信息。
python
logger1 = logging.getLogger('module1')
logger2 = logging.getLogger('module2')
logger1.debug("这是模块1的调试信息")
logger2.info("这是模块2的信息")
4. 配置文件
4.1 使用配置文件
可以通过配置文件来设置日志记录,支持 .ini
、.json
、.yaml
等格式。
4.1.1 INI 配置文件
创建一个 logging.conf
文件:
python
[loggers]
keys=root,simpleExample
[handlers]
keys=consoleHandler,fileHandler
[formatters]
keys=defaultFormatter
[logger_root]
level=DEBUG
handlers=consoleHandler
[logger_simpleExample]
level=DEBUG
handlers=consoleHandler,fileHandler
qualname=simpleExample
propagate=0
[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=defaultFormatter
args=(sys.stdout,)
[handler_fileHandler]
class=FileHandler
level=ERROR
formatter=defaultFormatter
args=('app.log', 'a')
[formatter_defaultFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
datefmt=%Y-%m-%d %H:%M:%S
然后在代码中使用:
python
import logging
import logging.config
logging.config.fileConfig('logging.conf')
logger = logging.getLogger('simpleExample')
logger.debug("这是一个调试信息")
4.1.2 JSON 配置文件
创建一个 logging.json
文件:
python
{
"version": 1,
"disable_existing_loggers": false,
"formatters": {
"default": {
"format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
"datefmt": "%Y-%m-%d %H:%M:%S"
}
},
"handlers": {
"console": {
"class": "logging.StreamHandler",
"level": "DEBUG",
"formatter": "default",
"stream": "ext://sys.stdout"
},
"file": {
"class": "logging.FileHandler",
"level": "ERROR",
"formatter": "default",
"filename": "app.log",
"mode": "a"
}
},
"loggers": {
"simpleExample": {
"level": "DEBUG",
"handlers": ["console", "file"],
"propagate": "no"
}
},
"root": {
"level": "DEBUG",
"handlers": ["console"]
}
}
然后在代码中使用:
python
import logging
import logging.config
import json
with open('logging.json', 'r') as f:
config = json.load(f)
logging.config.dictConfig(config)
logger = logging.getLogger('simpleExample')
logger.debug("这是一个调试信息")
5. 性能优化
5.1 减少日志记录的开销
记录日志时会有一定的性能开销,尤其是在处理大量日志时。可以通过以下几种方法来减少开销:
5.1.1 合理设置日志级别
在生产环境中,通常只记录WARNING级别及以上的日志,以减少开销。
python
logging.basicConfig(level=logging.WARNING)
5.1.2 延迟格式化
在日志级别低于当前配置级别时,避免不必要的字符串格式化。
python
logger.debug("这是一条调试信息: %s", some_expensive_operation())
5.1.3 使用高效的处理器
选择合适的处理器和格式器,避免过多的I/O操作。
python
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.WARNING)
logger.addHandler(console_handler)
5.2 异步日志记录
对于高并发或大量日志记录的场景,可以使用异步日志记录来提高性能。
python
import logging
import logging.handlers
import queue
# 创建队列处理器
log_queue = queue.Queue(-1)
queue_handler = logging.handlers.QueueHandler(log_queue)
# 创建队列监听器
listener = logging.handlers.QueueListener(log_queue, console_handler)
# 添加处理器到日志器
logger.addHandler(queue_handler)
# 开始监听
listener.start()
# 记录日志
logger.debug("这是一个调试信息")
# 停止监听
listener.stop()
6. 最佳实践
6.1 使用单例模式
确保在应用程序中只创建一个日志器实例,避免重复日志记录。
python
class SingletonLogger:
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(SingletonLogger, cls).__new__(cls, *args, **kwargs)
cls._instance.logger = logging.getLogger('app')
cls._instance.logger.setLevel(logging.DEBUG)
handler = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
cls._instance.logger.addHandler(handler)
return cls._instance
logger = SingletonLogger().logger
logger.debug("这是一个调试信息")
6.2 将日志记录集成到应用中
在应用程序的各个模块中使用相同的日志配置,确保日志记录的一致性。
python
# main.py
import logging.config
import json
with open('logging.json', 'r') as f:
config = json.load(f)
logging.config.dictConfig(config)
# module1.py
import logging
logger = logging.getLogger('module1')
logger.debug("这是模块1的调试信息")
# module2.py
import logging
logger = logging.getLogger('module2')
logger.info("这是模块2的信息")
6.3 使用上下文管理器
可以通过上下文管理器更好地管理日志记录的生命周期。
python
import logging
class LogContext:
def __init__(self, name):
self.logger = logging.getLogger(name)
def __enter__(self):
return self.logger
def __exit__(self, exc_type, exc_val, exc_tb):
pass
with LogContext('my_context_logger') as logger:
logger.debug("这是上下文中的调试信息")
6.4 定期轮换日志文件
对于长期运行的应用程序,定期轮换日志文件可以防止日志文件过大。
python
from logging.handlers import TimedRotatingFileHandler
# 创建一个定期轮换的文件处理器
file_handler = TimedRotatingFileHandler('app.log', when='midnight', interval=1, backupCount=7)
file_handler.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
file_handler.setFormatter(formatter)
# 添加处理器到日志器
logger.addHandler(file_handler)
Python 的 logging
模块提供了一个灵活、强大且高效的日志记录框架,通过合理的配置和使用,可以大大提高应用程序的可维护性和可调试性。无论是基础用法还是高级配置,理解并熟练掌握 logging
模块的使用,对于开发和维护高质量的 Python 应用程序都是非常重要的。