Skip to content

使用配置文件管理Python项目日志

874字约3分钟

Pythonlogging

2024-03-07

使用配置文件管理Python项目日志

logging 记录日志

使用 logging 模块能够灵活的进行日志的管理,如下是一个简单的日志示例:

# myapp.py
import logging
logger = logging.getLogger(__name__)

def main():
    logging.basicConfig(filename='myapp.log', level=logging.INFO)
    logger.info('Started')
    logger.info('Finished')

if __name__ == '__main__':
    main()

使用后,能够在日志文件 myapp.log 中看到如下内容:

INFO:__main__:Started
INFO:__main__:Finished

如果项目中 Python 文件较少,能够使用如上的方式进行日志管理,如果遇到项目中 Python 文件较多的场景,每个 Python 文件中单独指定日志文件,就很繁琐了,一旦遇到日志目录更改的情况,就需要修改使用 logging 模块的每个 Python 文件,不但工作复杂而且容器出错,这里记录一种 logging 模块使用配置文件管理日志的方式,也即日志的配置单独在一个文件中,而非每个文件单独指定。

logging 使用配置配置

logging 使用配置文件管理日志的核心是 logging.config.fileConfig,也即加载文件配置到日志模块,这里建议直接使用 log.conf 作为日志配置的文件名称,一个基础的日志配置文件示例如下:

[loggers]
keys=root

[logger_root]
# 日志级别:DEBUG、INFO、WARNING、ERROR、CRITICAL
level=DEBUG
# 处理器
handlers=consoleHandler,fileHandler

[logger_api]
level=ERROR
handlers=apiHandler
# 如果不是logger_root,这里一定要指定
qualname=api

[handlers]
keys=consoleHandler,fileHandler,apiHandler

[handler_consoleHandler]
# 处理类:StreamHandler(控制台)、FileHandler(文件)、NullHandler(无)
class=StreamHandler
level=DEBUG
formatter=default
args=(sys.stdout,)

[handler_fileHandler]
class=FileHandler
level=DEBUG
formatter=default
# 日志文件,写入的模式(追加),
args=('%LOG_DIR%/error.log', 'a')

[handler_apiHandler]
class=FileHandler
level=DEBUG
formatter=default
args=('%LOG_DIR%/api.log', 'a')

[formatters]
keys=default,error

[formatter_default]
# 日志输出的格式
format=%(asctime)s %(filename)s [line:%(lineno)d] %(levelname)s %(message)s

[formatter_error]
format=%(asctime)s %(filename)s [line:%(lineno)d] %(levelname)s %(message)s

如上配置文件中,有三个重要的概念:

  • loggers:定义了所有的日志器列表。
    • logger_*:定义日志器的配置,指定日志的级别和处理器。
  • handlers:定义了日志对应的处理器的列表。
    • handler_*:将日志输出到控制台或者文件,处理器都有对应的登记和格式。
  • formatters:定义了日志的格式的列表。
    • formatter_*:指定日志的输出样式的详细定义。

Flask 项目运行前,进行日志的配置,启动 Flask 项目前调用 setup_log ,如下所示:

import os
import logging.config
import configparser

def setup_log():
    """
    日志预处理:
    1.日志配置中环境变量的替换。
    """
    log_config_path = os.path.join(os.environ.get('PROJECT_ROOT'), 'conf', 'log.conf')
    # 读取日志配置文件内容
    with open(log_config_path, 'r', encoding='utf-8') as file:
        log_config_content = file.read()

    # 替换配置文件中的占位符 %LOG_DIR% 为环境变量 LOG_DIR 的值
    log_config_content = log_config_content.replace('%LOG_DIR%', os.environ.get('LOG_DIR'))

    # 将替换后的配置写入一个临时文件
    temp_log_config_path = os.path.join(os.environ.get('PROJECT_ROOT'), 'conf', 'tmp.conf')
    with open(temp_log_config_path, 'w', encoding='utf-8') as temp_file:
        temp_file.write(log_config_content)

    # 加载临时文件中的日志配置
    logging.config.fileConfig(temp_log_config_path)

    # 删除临时的日志文件
    os.remove(temp_log_config_path)

在需要记录日志的 Python 代码中,按照如下方式引用:

import logging

# 使用root日志处理器
LOG = logging.getLogger('root')

@api_bp.route('/execute', methods=['POST'])
def execute():
    # 日志打印
    LOG.exception("sql request")
    # ...

进行请求后,能够在 root 日志处理器对应的日志文件 error.log 中查看到 sql requestERROR 级别的日志打印,如下所示:

image-20250207145059281

日志文件和控制台均出现对应的日志打印。