目前从flask框架转fastapi,之前flask框架日志很好用。这次学习了fastapi的日志使用,第一种是自定义日志,这个不讲了,自己封装就好,第二种是使用uvicorn自带日志, Uvicorn 是 fastapi 框架的默认ASGI服务器,它提供了强大的异步能力和高性能。
一、配置输出格式化
uvicorn 其实已经有日志,只是没有格式化输出,我们希望可以加点东西丰富输出。
找到 uvicorn.config 里的源码, LOGGING_CONFIG配置如下:
LOGGING_CONFIG: Dict[str, Any] = {"version": 1,"disable_existing_loggers": False,"formatters": {"default": {"()": "uvicorn.logging.DefaultFormatter","fmt": "%(levelprefix)s %(message)s","use_colors": None,},"access": {"()": "uvicorn.logging.AccessFormatter","fmt": '%(levelprefix)s %(client_addr)s - "%(request_line)s" %(status_code)s', # noqa: E501},},"handlers": {"default": {"formatter": "default","class": "logging.StreamHandler","stream": "ext://sys.stderr",},"access": {"formatter": "access","class": "logging.StreamHandler","stream": "ext://sys.stdout",},},"loggers": {"uvicorn": {"handlers": ["default"], "level": "INFO", "propagate": False},"uvicorn.error": {"level": "INFO"},"uvicorn.access": {"handlers": ["access"], "level": "INFO", "propagate": False},},
}
这段默认配置我们可以自定义,不过不是改源码,是初始化时加载我们新建的配置。比如在用 uvicorn 启动时,加上参数 log_config,uvicorn 自定义日志配置文件支持 json、yaml、ini 三种格式。
uvicorn.run(app='main:app',host="0.0.0.0",log_config='./uvicorn_config.json',port=8000,loop="asyncio")
以下这段 json 实现了,格式化输出控制台,日志输出到本地文件。首先创建 uvicorn_config.json 存放项目根目录:
{"version": 1,"disable_existing_loggers": false,"formatters": {"default": {"()": "uvicorn.logging.DefaultFormatter","fmt": "%(asctime)s %(threadName)s %(levelprefix)s %(message)s", # 增加了asctime和threadName"use_colors": null},"access": {"()": "uvicorn.logging.AccessFormatter","fmt": "%(asctime)s %(threadName)s %(levelprefix)s %(client_addr)s - '%(request_line)s' %(status_code)s" # 增加了asctime和threadName}},"handlers": {"default": {"formatter": "default","class": "logging.StreamHandler","stream": "ext://sys.stderr"},# default日志输出到本地文件,定义了日志路径、备份数量"default_file": {"formatter": "default","class": "logging.handlers.TimedRotatingFileHandler","filename": "./logs/app.log","when": "midnight","encoding": "utf-8","backupCount": 10},"access": {"formatter": "access","class": "logging.StreamHandler","stream": "ext://sys.stdout"},# access日志输出到本地文件,定义了日志路径、备份数量"access_file": {"formatter": "access","class": "logging.handlers.TimedRotatingFileHandler","filename": "./logs/app.log","when": "midnight","encoding": "utf-8","backupCount": 10}},"loggers": {# 添加handler,default_file"uvicorn": {"handlers": ["default","default_file"], "level": "INFO", "propagate": false},"uvicorn.error": {"level": "INFO"},# 添加handler,access_file"uvicorn.access": {"handlers": ["access","access_file"], "level": "INFO", "propagate": false}}
}
main.py文件
from api.aiserver_v3 import ai_server_v3
from fastapi import FastAPI
import uvicornapp = FastAPI()@app.get("/home")
async def get():return {'message':'OK'}@app.get("/test")
async def get():return {'message':'OK'}@app.get("/dev")
async def get():return {'message':'OK'}if __name__ == "__main__":uvicorn.run(app='main:app',host="0.0.0.0",log_config='./uvicorn_config.json',port=8000,loop="asyncio")
运行main.py
控制台
app.log
二、业务代码调用 uvicorn 日志
查看 uvicorn 日志源码处理机制发现,本质上还是 logger.addHandler 方法添加 handler,所以可以用以下方法调用:
from api.aiserver_v3 import ai_server_v3
from fastapi import FastAPI
import uvicorn,loggingapp = FastAPI()log = logging.getLogger("uvicorn")@app.get("/home")
async def get():log.info('this is a test')return {'message':'OK'}@app.get("/test")
async def get():return {'message':'OK'}@app.get("/dev")
async def get():return {'message':'OK'}app.include_router(ai_server_v3,prefix='/ai',tags=['person'])if __name__ == "__main__":uvicorn.run(app='main:app',host="0.0.0.0",log_config='./uvicorn_config.json',port=8000,loop="asyncio")
输出: