Python自带的日志logging模块使用起来比较麻烦,配置繁琐,所有打算使用一个配置简单,可自定义输出日志颜色的日志库loguru,相比于python自带的日志框架方便多了,这里我将介绍FastApi中使用loguru,我们先看看loguru输出日志的样式:
安装:
pip install loguru
使用loguru输出的日志看上去是不是很不错,可以设置输出的时间格式,日志输出的颜色,还有当前进程信息,输生日志打印的行数等都可以设置,为不同日志级别设置不同的输出日志的颜色便于查找日志信息。
在FastApi刚加入loguru日志时,就是很简单的使用,在可能出现异常的地方加一句日志,这个我个人感觉就没很好的将loguru集成到FastAPI中,让loguru完全管理FastAPI的所有日志输出。
刚开始使用在FastApi中使用loguru时是这样做的,先配置一下loguru日志,创建一个log.py文件
log.py文件中的代码如下:
class Logger:
"""输出日志到文件和控制台"""
def __init__(self):
# 文件的命名
log_name = f"Fast_{time.strftime('%Y-%m-%d', time.localtime()).replace('-', '_')}.log"
log_path = os.path.join(LogPath, "Fast_{time:YYYY-MM-DD}.log")
self.logger = logger
# 清空所有设置
self.logger.remove()
# 判断日志文件夹是否存在,不存则创建
if not os.path.exists(LogPath):
os.makedirs(LogPath)
# 日志输出格式
formatter = "{time:YYYY-MM-DD HH:mm:ss} | {level}: {message}"
# 添加控制台输出的格式,sys.stdout为输出到屏幕;关于这些配置还需要自定义请移步官网查看相关参数说明
self.logger.add(sys.stdout,
format="<green>{time:YYYYMMDD HH:mm:ss}</green> | " # 颜色>时间
"{process.name} | " # 进程名
"{thread.name} | " # 进程名
"<cyan>{module}</cyan>.<cyan>{function}</cyan>" # 模块名.方法名
":<cyan>{line}</cyan> | " # 行号
"<level>{level}</level>: " # 等级
"<level>{message}</level>", # 日志内容
)
# 日志写入文件
self.logger.add(log_path, # 写入目录指定文件
format='{time:YYYYMMDD HH:mm:ss} - ' # 时间
"{process.name} | " # 进程名
"{thread.name} | " # 进程名
'{module}.{function}:{line} - {level} -{message}', # 模块名.方法名:行号
encoding='utf-8',
retention='7 days', # 设置历史保留时长
backtrace=True, # 回溯
diagnose=True, # 诊断
enqueue=True, # 异步写入
rotation="00:00", # 每日更新时间
# rotation="5kb", # 切割,设置文件大小,rotation="12:00",rotation="1 week"
# filter="my_module" # 过滤模块
# compression="zip" # 文件压缩
)
def get_logger(self):
return self.logger
log = Logger().get_logger()
调用的时候在其他Python文件中导入log就可以直接使用,
实例代码:
import uvicorn
from fastapi import FastAPI
from log import log
app = FastAPI()
@app.get("/")
def index():
log.error("/index")
return "Hello, World."
if __name__ == '__main__':
uvicorn.run("test7:app", host='0.0.0.0', port=9999)
输出结果图如下:
上面的结果图可以看出除了loguru日志输出的日志外还有uvicorn输出的日志信息,uvicorn输出的日志和loguru的日志是没有关系的,uvicorn的日志是输出到控制台的他不会输出的日志文件,如果要输出到文件要额外去配置,这样先一个项目就要去维护两个日志,这样对开发和维护就很麻烦,不好统一管理日志,使用要将uvicorn输出的日志全部交给loguru来管理,这样就很方便后期开发和维护。
整合后的代码log.py文件的修改如下:
import os
import sys
import time
import logging
from types import FrameType
from typing import cast
from loguru import logger
from .path_conf import LogPath
class Logger:
"""输出日志到文件和控制台"""
def __init__(self):
# 文件的命名
log_name = f"Fast_{time.strftime('%Y-%m-%d', time.localtime()).replace('-', '_')}.log"
log_path = os.path.join(LogPath, "Fast_{time:YYYY-MM-DD}.log")
self.logger = logger
# 清空所有设置
self.logger.remove()
# 判断日志文件夹是否存在,不存则创建
if not os.path.exists(LogPath):
os.makedirs(LogPath)
# 日志输出格式
formatter = "{time:YYYY-MM-DD HH:mm:ss} | {level}: {message}"
# 添加控制台输出的格式,sys.stdout为输出到屏幕;关于这些配置还需要自定义请移步官网查看相关参数说明
self.logger.add(sys.stdout,
format="<green>{time:YYYYMMDD HH:mm:ss}</green> | " # 颜色>时间
"{process.name} | " # 进程名
"{thread.name} | " # 进程名
"<cyan>{module}</cyan>.<cyan>{function}</cyan>" # 模块名.方法名
":<cyan>{line}</cyan> | " # 行号
"<level>{level}</level>: " # 等级
"<level>{message}</level>", # 日志内容
)
# 日志写入文件
self.logger.add(log_path, # 写入目录指定文件
format='{time:YYYYMMDD HH:mm:ss} - ' # 时间
"{process.name} | " # 进程名
"{thread.name} | " # 进程名
'{module}.{function}:{line} - {level} -{message}', # 模块名.方法名:行号
encoding='utf-8',
retention='7 days', # 设置历史保留时长
backtrace=True, # 回溯
diagnose=True, # 诊断
enqueue=True, # 异步写入
rotation="00:00", # 每日更新时间
# rotation="5kb", # 切割,设置文件大小,rotation="12:00",rotation="1 week"
# filter="my_module" # 过滤模块
# compression="zip" # 文件压缩
)
def init_config(self):
LOGGER_NAMES = ("uvicorn.asgi", "uvicorn.access", "uvicorn")
# change handler for default uvicorn logger
logging.getLogger().handlers = [InterceptHandler()]
for logger_name in LOGGER_NAMES:
logging_logger = logging.getLogger(logger_name)
logging_logger.handlers = [InterceptHandler()]
def get_logger(self):
return self.logger
class InterceptHandler(logging.Handler):
def emit(self, record: logging.LogRecord) -> None: # pragma: no cover
# Get corresponding Loguru level if it exists
try:
level = logger.level(record.levelname).name
except ValueError:
level = str(record.levelno)
# Find caller from where originated the logged message
frame, depth = logging.currentframe(), 2
while frame.f_code.co_filename == logging.__file__: # noqa: WPS609
frame = cast(FrameType, frame.f_back)
depth += 1
logger.opt(depth=depth, exception=record.exc_info).log(
level, record.getMessage(),
)
Loggers = Logger()
log = Loggers.get_logger()
FastApi启动的位置需要修改:
import uvicorn
from fastapi import FastAPI
from log import log, Loggers
app = FastAPI()
@app.get("/")
def index():
log.error("/index")
return "Hello, World."
if __name__ == '__main__':
config = uvicorn.Config("test7:app", host='0.0.0.0', port=9999)
server = uvicorn.Server(config)
# 将uvicorn输出的全部让loguru管理
Loggers.init_config()
server.run()
运行截图:
上面的FastAPI启动成功信息和访问接口的信息全部都由loguru打印出来了,这样loguru完全管理了FastApi的所有日志信息。这样就能很好的统一管理日志信息
个人博客网站,灵动空间,欢迎访问