Skip to content

Commit b270710

Browse files
authored
更新数据库连接和日志配置 (#55)
1 parent b25c957 commit b270710

File tree

7 files changed

+68
-143
lines changed

7 files changed

+68
-143
lines changed

backend/common/log.py

+24-28
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
import inspect
44
import logging
55
import os
6+
import sys
67

7-
from sys import stderr, stdout
88

99
from loguru import logger
1010

@@ -41,7 +41,7 @@ def setup_logging():
4141
"""
4242
# Intercept everything at the root logger
4343
logging.root.handlers = [InterceptHandler()]
44-
logging.root.setLevel(settings.LOG_ROOT_LEVEL)
44+
logging.root.setLevel(settings.LOG_STD_LEVEL)
4545

4646
# Remove all log handlers and propagate to root logger
4747
for name in logging.root.manager.loggerDict.keys():
@@ -54,62 +54,58 @@ def setup_logging():
5454
# Debug log handlers
5555
# logging.debug(f'{logging.getLogger(name)}, {logging.getLogger(name).propagate}')
5656

57-
# Remove every other logger's handlers
57+
# Remove default loguru logger
5858
logger.remove()
5959

60-
# Configure loguru logger before starts logging
60+
# Set the loguru default handlers
6161
logger.configure(
6262
handlers=[
6363
{
64-
'sink': stdout,
65-
'level': settings.LOG_STDOUT_LEVEL,
66-
'filter': lambda record: record['level'].no <= 25,
64+
'sink': sys.stdout,
65+
'level': settings.LOG_STD_LEVEL,
6766
'format': settings.LOG_STD_FORMAT,
68-
},
69-
{
70-
'sink': stderr,
71-
'level': settings.LOG_STDERR_LEVEL,
72-
'filter': lambda record: record['level'].no >= 30,
73-
'format': settings.LOG_STD_FORMAT,
74-
},
67+
}
7568
]
7669
)
7770

7871

79-
def set_customize_logfile():
72+
def set_custom_logfile():
8073
log_path = path_conf.LOG_DIR
8174
if not os.path.exists(log_path):
8275
os.mkdir(log_path)
8376

8477
# log files
85-
log_stdout_file = os.path.join(log_path, settings.LOG_STDOUT_FILENAME)
86-
log_stderr_file = os.path.join(log_path, settings.LOG_STDERR_FILENAME)
78+
log_access_file = os.path.join(log_path, settings.LOG_ACCESS_FILENAME)
79+
log_error_file = os.path.join(log_path, settings.LOG_ERROR_FILENAME)
8780

88-
# loguru logger: https://loguru.readthedocs.io/en/stable/api/logger.html#loguru._logger.Logger.add
81+
# set loguru logger default config
82+
# https://loguru.readthedocs.io/en/stable/api/logger.html#loguru._logger.Logger.add
8983
log_config = {
90-
'rotation': '10 MB',
91-
'retention': '15 days',
92-
'compression': 'tar.gz',
93-
'enqueue': True,
9484
'format': settings.LOG_FILE_FORMAT,
85+
'enqueue': True,
86+
'rotation': '5 MB',
87+
'retention': '7 days',
88+
'compression': 'tar.gz',
9589
}
9690

9791
# stdout file
9892
logger.add(
99-
str(log_stdout_file),
100-
level=settings.LOG_STDOUT_LEVEL,
101-
**log_config,
93+
str(log_access_file),
94+
level=settings.LOG_ACCESS_FILE_LEVEL,
95+
filter=lambda record: record['level'].no <= 25,
10296
backtrace=False,
10397
diagnose=False,
98+
**log_config,
10499
)
105100

106101
# stderr file
107102
logger.add(
108-
str(log_stderr_file),
109-
level=settings.LOG_STDERR_LEVEL,
110-
**log_config,
103+
str(log_error_file),
104+
level=settings.LOG_ERROR_FILE_LEVEL,
105+
filter=lambda record: record['level'].no >= 30,
111106
backtrace=True,
112107
diagnose=True,
108+
**log_config,
113109
)
114110

115111

backend/common/model.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from datetime import datetime
44
from typing import Annotated
55

6+
from sqlalchemy.ext.asyncio import AsyncAttrs
67
from sqlalchemy.orm import DeclarativeBase, Mapped, MappedAsDataclass, declared_attr, mapped_column
78

89
from backend.utils.timezone import timezone
@@ -34,10 +35,11 @@ class DateTimeMixin(MappedAsDataclass):
3435
)
3536

3637

37-
class MappedBase(DeclarativeBase):
38+
class MappedBase(AsyncAttrs, DeclarativeBase):
3839
"""
39-
声明性基类, 原始 DeclarativeBase 类, 作为所有基类或数据模型类的父类而存在
40+
声明式基类, 作为所有基类或数据模型类的父类而存在
4041
42+
`AsyncAttrs <https://docs.sqlalchemy.org/en/20/orm/extensions/asyncio.html#sqlalchemy.ext.asyncio.AsyncAttrs>`__
4143
`DeclarativeBase <https://docs.sqlalchemy.org/en/20/orm/declarative_config.html>`__
4244
`mapped_column() <https://docs.sqlalchemy.org/en/20/orm/mapping_api.html#sqlalchemy.orm.mapped_column>`__
4345
"""

backend/core/conf.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ def validator_api_url(cls, values):
5050

5151
# MYSQL
5252
DATABASE_ECHO: bool = False
53+
DATABASE_POOL_ECHO: bool = False
5354
DATABASE_SCHEMA: str = 'fsm'
5455
DATABASE_CHARSET: str = 'utf8mb4'
5556

@@ -66,13 +67,13 @@ def validator_api_url(cls, values):
6667
TOKEN_URL_SWAGGER: str = f'{FASTAPI_API_V1_PATH}/auth/login/swagger'
6768

6869
# Log
69-
LOG_ROOT_LEVEL: str = 'NOTSET'
70+
LOG_STD_LEVEL: str = 'INFO'
71+
LOG_ACCESS_FILE_LEVEL: str = 'INFO'
72+
LOG_ERROR_FILE_LEVEL: str = 'ERROR'
7073
LOG_STD_FORMAT: str = '<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</> | <lvl>{level: <8}</> | <lvl>{message}</>'
7174
LOG_FILE_FORMAT: str = '<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</> | <lvl>{level: <8}</> | <lvl>{message}</>'
72-
LOG_STDOUT_LEVEL: str = 'INFO'
73-
LOG_STDERR_LEVEL: str = 'ERROR'
74-
LOG_STDOUT_FILENAME: str = 'fba_access.log'
75-
LOG_STDERR_FILENAME: str = 'fba_error.log'
75+
LOG_ACCESS_FILENAME: str = 'fba_access.log'
76+
LOG_ERROR_FILENAME: str = 'fba_error.log'
7677

7778
# 中间件
7879
MIDDLEWARE_CORS: bool = True

backend/core/registrar.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
from backend.app.router import route
1111
from backend.common.exception.exception_handler import register_exception
12-
from backend.common.log import setup_logging, set_customize_logfile
12+
from backend.common.log import setup_logging, set_custom_logfile
1313
from backend.core.path_conf import STATIC_DIR
1414
from backend.database.redis import redis_client
1515
from backend.core.conf import settings
@@ -82,7 +82,7 @@ def register_logger() -> None:
8282
:return:
8383
"""
8484
setup_logging()
85-
set_customize_logfile()
85+
set_custom_logfile()
8686

8787

8888
def register_static_file(app: FastAPI):

backend/database/db.py

+28-25
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,29 @@
77

88
from fastapi import Depends
99
from sqlalchemy import URL
10-
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
10+
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine, AsyncEngine
1111

1212
from backend.common.log import log
1313
from backend.common.model import MappedBase
1414
from backend.core.conf import settings
1515

1616

17-
def create_engine_and_session(url: str | URL):
17+
def create_async_engine_and_session(url: str | URL) -> tuple[AsyncEngine, async_sessionmaker[AsyncSession]]:
1818
try:
1919
# 数据库引擎
20-
engine = create_async_engine(url, echo=settings.DATABASE_ECHO, future=True, pool_pre_ping=True)
21-
# log.success('数据库连接成功')
20+
engine = create_async_engine(
21+
url,
22+
echo=settings.DATABASE_ECHO,
23+
echo_pool=settings.DATABASE_POOL_ECHO,
24+
future=True,
25+
# 中等并发
26+
pool_size=10, # 低:- 高:+
27+
max_overflow=20, # 低:- 高:+
28+
pool_timeout=30, # 低:+ 高:-
29+
pool_recycle=3600, # 低:+ 高:-
30+
pool_pre_ping=True, # 低:False 高:True
31+
pool_use_lifo=False, # 低:False 高:True
32+
)
2233
except Exception as e:
2334
log.error('❌ 数据库链接失败 {}', e)
2435
sys.exit()
@@ -27,31 +38,13 @@ def create_engine_and_session(url: str | URL):
2738
return engine, db_session
2839

2940

30-
SQLALCHEMY_DATABASE_URL = (
31-
f'mysql+asyncmy://{settings.DATABASE_USER}:{settings.DATABASE_PASSWORD}@{settings.DATABASE_HOST}:'
32-
f'{settings.DATABASE_PORT}/{settings.DATABASE_SCHEMA}?charset={settings.DATABASE_CHARSET}'
33-
)
34-
35-
async_engine, async_db_session = create_engine_and_session(SQLALCHEMY_DATABASE_URL)
36-
37-
38-
async def get_db() -> AsyncSession:
41+
async def get_db():
3942
"""session 生成器"""
40-
session = async_db_session()
41-
try:
43+
async with async_db_session() as session:
4244
yield session
43-
except Exception as se:
44-
await session.rollback()
45-
raise se
46-
finally:
47-
await session.close()
48-
4945

50-
# Session Annotated
51-
CurrentSession = Annotated[AsyncSession, Depends(get_db)]
5246

53-
54-
async def create_table():
47+
async def create_table() -> None:
5548
"""创建数据库表"""
5649
async with async_engine.begin() as coon:
5750
await coon.run_sync(MappedBase.metadata.create_all)
@@ -60,3 +53,13 @@ async def create_table():
6053
def uuid4_str() -> str:
6154
"""数据库引擎 UUID 类型兼容性解决方案"""
6255
return str(uuid4())
56+
57+
58+
SQLALCHEMY_DATABASE_URL = (
59+
f'mysql+asyncmy://{settings.DATABASE_USER}:{settings.DATABASE_PASSWORD}@{settings.DATABASE_HOST}:'
60+
f'{settings.DATABASE_PORT}/{settings.DATABASE_SCHEMA}?charset={settings.DATABASE_CHARSET}'
61+
)
62+
63+
async_engine, async_db_session = create_async_engine_and_session(SQLALCHEMY_DATABASE_URL)
64+
# Session Annotated
65+
CurrentSession = Annotated[AsyncSession, Depends(get_db)]

pdm.lock

+4-78
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)