diff --git a/config/fastapi_config.py b/config/fastapi_config.py index ac85a61..b3aa5d7 100644 --- a/config/fastapi_config.py +++ b/config/fastapi_config.py @@ -36,8 +36,8 @@ async def lifespan(app: FastAPI): # FastAPI应用初始化 app = FastAPI( - title="DataBuilder API", - description="数据工厂 api", + title="Fast API", + description="FastAPI", version="1.0.0", lifespan=lifespan ) @@ -48,9 +48,9 @@ def custom_openapi(): return app.openapi_schema openapi_schema = get_openapi( - title="数据工厂", + title="Fast API", version="1.0.0", - description="数据工厂接口文档", + description="Fast API", routes=app.routes, ) diff --git a/entity/__init__.py b/entity/__init__.py index dbe57d5..07b9622 100644 --- a/entity/__init__.py +++ b/entity/__init__.py @@ -59,9 +59,9 @@ class EnhanceAsyncSession(AsyncSession): if execution_options is None: default_execution_options = sig.parameters['execution_options'].default execution_options = default_execution_options - print("type(statement):{}", type(statement)) + # print("type(statement):{}", type(statement)) if isinstance(statement, Select): - print("这是查询语句,过滤逻辑删除") + # print("这是查询语句,过滤逻辑删除") delete_condition = column(Constant.LOGICAL_DELETE_FIELD) == IsDelete.NO_DELETE # 获取现有条件 existing_condition = statement.whereclause diff --git a/entity/dto/UserDto.py b/entity/dto/UserDto.py index c2c8184..e5fe3ea 100644 --- a/entity/dto/UserDto.py +++ b/entity/dto/UserDto.py @@ -8,5 +8,6 @@ from entity.dto.base import BasePageQueryReq, BaseQueryReq class UserQueryReq(BaseQueryReq): username: Optional[str]= Field(default=None,description="名称") + class UserQueryPageReq(UserQueryReq, BasePageQueryReq): pass diff --git a/entity/dto/__init__.py b/entity/dto/__init__.py index a1655f6..57dca47 100644 --- a/entity/dto/__init__.py +++ b/entity/dto/__init__.py @@ -1,3 +1,27 @@ +from collections import namedtuple + from beartype.claw import beartype_this_package beartype_this_package() +HttpCode = namedtuple('HttpResp', ['code', 'msg']) + +class HttpResp: + """HTTP响应结果 + """ + SUCCESS = HttpCode(200, '成功') + FAILED = HttpCode(300, '失败') + PARAMS_VALID_ERROR = HttpCode(310, '参数校验错误') + PARAMS_TYPE_ERROR = HttpCode(311, '参数类型错误') + REQUEST_METHOD_ERROR = HttpCode(312, '请求方法错误') + ASSERT_ARGUMENT_ERROR = HttpCode(313, '断言参数错误') + + LOGIN_ACCOUNT_ERROR = HttpCode(330, '登录账号或密码错误') + LOGIN_DISABLE_ERROR = HttpCode(331, '登录账号已被禁用了') + TOKEN_EMPTY = HttpCode(332, 'token参数为空') + TOKEN_INVALID = HttpCode(333, 'token参数无效') + + NO_PERMISSION = HttpCode(403, '无相关权限') + REQUEST_404_ERROR = HttpCode(404, '请求接口不存在') + DATA_ALREADY_EXISTS = HttpCode(409, '数据已存在') + SYSTEM_ERROR = HttpCode(500, '系统错误') + SYSTEM_TIMEOUT_ERROR = HttpCode(504, '请求超时') \ No newline at end of file diff --git a/exceptions/global_exc.py b/exceptions/global_exc.py index 8929541..9b2ae0b 100644 --- a/exceptions/global_exc.py +++ b/exceptions/global_exc.py @@ -4,7 +4,7 @@ from fastapi import FastAPI, Request from fastapi.exceptions import RequestValidationError from fastapi.responses import JSONResponse -from utils.api_utils import server_error_response +from entity.dto import HttpResp from .base import AppException logger = logging.getLogger(__name__) @@ -35,4 +35,6 @@ def configure_exception(app: FastAPI): @app.exception_handler(Exception) async def global_exception_handler(request: Request, exc: Exception): - return server_error_response(exc) + return JSONResponse( + status_code=200, + content={'code': HttpResp.SYSTEM_ERROR.code, 'msg': HttpResp.SYSTEM_ERROR.msg}) diff --git a/main.py b/main.py index 09bfceb..45e3c3d 100644 --- a/main.py +++ b/main.py @@ -6,9 +6,11 @@ import threading import time import traceback -from config import settings, show_configs -from utils import file_utils +from utils.log_utils import init_root_logger +init_root_logger("fastapi-template") +from utils import file_utils +from config import settings, show_configs stop_event = threading.Event() RAGFLOW_DEBUGPY_LISTEN = int(os.environ.get('RAGFLOW_DEBUGPY_LISTEN', "0")) @@ -22,14 +24,6 @@ def signal_handler(sig, frame): if __name__ == '__main__': - logging.info(r""" - _____ _ ____ _ _ _ - | __ \ | | | _ \ (_) | | | - | | | | __ _| |_ __ _| |_) |_ _ _| | __| | ___ _ __ - | | | |/ _` | __/ _` | _ <| | | | | |/ _` |/ _ \ '__| - | |__| | (_| | || (_| | |_) | |_| | | | (_| | __/ | - |_____/ \__,_|\__\__,_|____/ \__,_|_|_|\__,_|\___|_| - """) logging.info( f'project base: {file_utils.get_project_base_directory()}' @@ -43,6 +37,17 @@ if __name__ == '__main__': signal.signal(signal.SIGTERM, signal_handler) try: logging.info("服务启动ing...") + logging.info(r""" + ______ _ ___ ______ _____ _____ _ _ + | ___| | | / _ \ | ___ \|_ _| |_ _| | | | | + | |_ __ _ ___ | |_ / /_\ \| |_/ / | | ______ | | ___ _ __ ___ _ __ | | __ _ | |_ ___ + | _| / _` |/ __|| __|| _ || __/ | | |______| | | / _ \| '_ ` _ \ | '_ \ | | / _` || __| / _ \ + | | | (_| |\__ \| |_ | | | || | _| |_ | | | __/| | | | | || |_) || || (_| || |_ | __/ + \_| \__,_||___/ \__|\_| |_/\_| \___/ \_/ \___||_| |_| |_|| .__/ |_| \__,_| \__| \___| + | | + |_| + """) + import uvicorn # 配置Uvicorn参数 uvicorn_config = { diff --git a/middleware/__init__.py b/middleware/__init__.py index d8214a4..ba50d88 100644 --- a/middleware/__init__.py +++ b/middleware/__init__.py @@ -9,7 +9,6 @@ from middleware.db_session import DbSessionMiddleWare beartype_this_package() def add_middleware(app: FastAPI): - app.add_middleware(SessionMiddleware, secret_key=secrets.token_hex(32)) app.add_middleware( CORSMiddleware, allow_origins=["*"], @@ -18,6 +17,7 @@ def add_middleware(app: FastAPI): allow_headers=["*"], max_age=2592000 ) + app.add_middleware(SessionMiddleware, secret_key=secrets.token_hex(32)) app.add_middleware(DbSessionMiddleWare) diff --git a/utils/log_utils.py b/utils/log_utils.py new file mode 100644 index 0000000..941d68d --- /dev/null +++ b/utils/log_utils.py @@ -0,0 +1,78 @@ +import logging +import os +import os.path +from logging.handlers import RotatingFileHandler + +initialized_root_logger = False + + +def get_project_base_directory(): + PROJECT_BASE = os.path.abspath( + os.path.join( + os.path.dirname(os.path.realpath(__file__)), + os.pardir, + os.pardir, + ) + ) + return PROJECT_BASE + + +def init_root_logger(logfile_basename: str, log_format: str = "%(asctime)-15s %(levelname)-8s %(process)d %(message)s"): + global initialized_root_logger + if initialized_root_logger: + return + initialized_root_logger = True + + logger = logging.getLogger() + logger.handlers.clear() + log_path = os.path.abspath(os.path.join(get_project_base_directory(), "logs", f"{logfile_basename}.log")) + + os.makedirs(os.path.dirname(log_path), exist_ok=True) + formatter = logging.Formatter(log_format) + + handler1 = RotatingFileHandler(log_path, maxBytes=10 * 1024 * 1024, backupCount=5) + handler1.setFormatter(formatter) + logger.addHandler(handler1) + + handler2 = logging.StreamHandler() + handler2.setFormatter(formatter) + logger.addHandler(handler2) + + logging.captureWarnings(True) + + LOG_LEVELS = os.environ.get("LOG_LEVELS", "") + pkg_levels = {} + for pkg_name_level in LOG_LEVELS.split(","): + terms = pkg_name_level.split("=") + if len(terms) != 2: + continue + pkg_name, pkg_level = terms[0], terms[1] + pkg_name = pkg_name.strip() + pkg_level = logging.getLevelName(pkg_level.strip().upper()) + if not isinstance(pkg_level, int): + pkg_level = logging.INFO + pkg_levels[pkg_name] = logging.getLevelName(pkg_level) + + # for pkg_name in ['peewee', 'pdfminer']: + # if pkg_name not in pkg_levels: + # pkg_levels[pkg_name] = logging.getLevelName(logging.WARNING) + if 'root' not in pkg_levels: + pkg_levels['root'] = logging.getLevelName(logging.INFO) + + for pkg_name, pkg_level in pkg_levels.items(): + pkg_logger = logging.getLogger(pkg_name) + pkg_logger.setLevel(pkg_level) + + msg = f"{logfile_basename} log path: {log_path}, log levels: {pkg_levels}" + logger.info(msg) + + +def log_exception(e, *args): + logging.exception(e) + for a in args: + if hasattr(a, "text"): + logging.error(a.text) + raise Exception(a.text) + else: + logging.error(str(a)) + raise e