最近使用到flask3.x,配置了全域的log,这边记录下
首先需要创建logging的配置文件,我是放在项目根目录的,
Logging 配置
logging.json
{
"version": 1, # 配置文件版本号
"formatters": {
"default": {
"format": "[%(asctime)s] %(levelname)s in %(module)s: %(message)s"
# 默认的日志格式,包含时间、日志级别、模块和消息
}
},
"handlers": {
"console": {
"class": "logging.StreamHandler",
# 日志处理器的类,将日志输出到控制台
"level": "DEBUG", # 控制台处理器的日志级别为 DEBUG
"formatter": "default", # 使用上面定义的 "default" 格式化器
"stream": "ext://sys.stdout" # 输出流为标准输出流
},
"file": {
"class": "logging.handlers.RotatingFileHandler",
# 日志处理器的类,将日志输出到文件
"level": "INFO", # 文件处理器的日志级别为 INFO
"formatter": "default", # 使用上面定义的 "default" 格式化器
"filename": "logs/log", # 日志文件的名称(logs 目录下的 log 文件)
"maxBytes": 10485760, # 每个日志文件的最大大小为 10 MB
"backupCount": 20, # 保留最近 20 个日志文件备份
"encoding": "utf8" # 使用 UTF-8 编码
}
},
"root": {
"level": "DEBUG", # 根日志记录器的级别为 DEBUG
"handlers": ["console", "file"]
# 根日志记录器使用上面定义的 "console" 和 "file" 两个处理器
}
}
application.py
然后在application.py中加载logging.json,并且用dictConfig加载到logging的配置中。
这里使用../logging.json是因为我的logging.json是在application.py的上一层,具体放的值,要参考具体的路径来配置
"""Application module."""
from logging.handlers import RotatingFileHandler
import os
from flask import Flask
from flask_bootstrap import Bootstrap
from main.web.route.views import xxx_bp
from main.containers import Container
from logging.config import dictConfig
import json
def create_app() -> Flask:
app = Flask(__name__,template_folder='webapp/templates',static_folder='webapp/content')
container = Container()
init_config_log()
app.register_blueprint(xxx_bp,url_prefix='/xxx')
app.container = container
bootstrap = Bootstrap()
bootstrap.init_app(app)
return app
def init_config_log() -> None:
with open(os.path.join(os.path.dirname(__file__), "../logging.json")) as f:
logging_config = json.load(f)
dictConfig(logging_config)
使用的时候就直接使用current_app.logger打印就可以了
from flask import current_app
class xxxxxService:
def __init__(self,...) -> None:
...
def test_log(self) -> None:
current_app.logger.error("Log something....")
还有记得根据你logging.json配置的filename建立他的父文件夹,对于我的配置就是建立logs文件夹,否则启动项目的时候就会报错:
并且所有的log也会被记录到配置的filename的文件里面。
pytest
pytest中有自己独立的log,但是如果加载了app,类似于这种
import datetime
import pytest
from main.application import create_app
from flask import current_app
@pytest.fixture
def app():
app = create_app()
app.config.update({
"TESTING": True,
})
yield app
@pytest.fixture
def xxxx_service(app):
with app.app_context():
xxxx_repo=xxxxRepositoryImpl()
yield xxxService(xxxx_repo=xxxx_repo)
# yield UserService(user_repository=user_repo,session_factory=db.session)
def test_create_user(xxxx_service):
current_app.logger.info("Log Something")
xxx=xxxx_service.xx_function()
assert xxx == "some value"
就会导致Flask应用程序和pytest都使用了logging模块,但是它们的log配置是独立的,不会相互覆盖。当在Flask中配置了log后,Flask会创建一个名为flask.app的logger对象,并将其添加到logging模块的logger列表中。当在pytest中使用log对象时,您实际上是使用了logging模块的root logger对象,它是默认的logger对象。由于Flask的logger对象的级别高于root logger对象的级别,所以Flask的logger对象会拦截root logger对象的日志消息,导致pytest中的log不打印。
所以呢,我们就统一使用current_app.logger,这种方式打印log。
但是这样会有一个问题,log会被正常记录,也会被放在tests/${filename}中(因为是test中会生成独立的${filename},记得也要提前创建父文件夹),但是console中没有log打印。
这种情况下,就需要修改我们的pytest.ini,如果没有的话,就需要在根目录中新建一个,
这里面的配置是显示
pytest.ini
[pytest]
addopts = -s
#addopts 是一个配置项,用于指定传递给 pytest 的额外命令行选项。
#-s 是 pytest 的一个命令行选项,表示禁用输出捕获,允许测试中的 print 语句将输出直接打印到控制台。
#因此,这个配置告诉 pytest 在运行时使用 -s 选项,使得测试中的输出能够直接显示在终端上,而不是被 #pytest 捕获并隐藏。这在调试和查看详细信息时很有用。
加上这个之后,print也会被显示在console,当然也包括我们的log。
之后就可以运行pytest了,不管是我们业务代码中的log,还是test中的log,都会根据我们log的配置打印在console里面,也会记录到test/${filename}中。