feat:更新架构
This commit is contained in:
@@ -20,12 +20,52 @@ export default defineConfig({
|
|||||||
// https://vitepress.dev/reference/default-theme-config
|
// https://vitepress.dev/reference/default-theme-config
|
||||||
nav: [
|
nav: [
|
||||||
{ text: 'Home', link: '/' },
|
{ text: 'Home', link: '/' },
|
||||||
{ text: 'Web前端', link: '/Web-Front/' },
|
{ text: 'Web前端',
|
||||||
{ text: 'Web后端', link: '/Web-Backend/' },
|
items: [
|
||||||
{ text: 'DevOps', link: '/DevOps/' },
|
{ text: 'Vue3-Common', link: '/Web-Front/Vue3-Common' },
|
||||||
{ text: 'SpringBoot', link: '/SpringBoot/' },
|
{ text: 'JavaScript知识点整理', link: '/Web-Front/JavaScript-Guide' }
|
||||||
{ text: 'FastAPI', link: '/FastAPI/' },
|
]
|
||||||
{ text: 'Flutter', link: '/Flutter/' },
|
},
|
||||||
|
{ text: 'Web后端',
|
||||||
|
items: [
|
||||||
|
{ text: 'MySQL知识点', link: '/Web-Backend/MySQL-Knowledge' },
|
||||||
|
{ text: 'Flyway简单使用', link: '/Web-Backend/Flyway' },
|
||||||
|
{ text: 'MyBatis简介和使用', link: '/Web-Backend/MyBatis' },
|
||||||
|
{ text: 'RustFS简介和使用', link: '/Web-Backend/RustFS' },
|
||||||
|
{
|
||||||
|
text: 'SpringBoot',
|
||||||
|
items: [
|
||||||
|
{ text: 'Spring IOC简介', link: '/Web-Backend/SpringBoot/SpringIOC' },
|
||||||
|
{ text: 'SpringBoot启动流程', link: '/Web-Backend/SpringBoot/SpringBoot-Start-Process' },
|
||||||
|
{ text: 'Spring MVC简介', link: '/Web-Backend/SpringBoot/SpringMVC' },
|
||||||
|
{ text: 'SpringBoot Starter原理', link: '/Web-Backend/SpringBoot/SpringBootStarter' },
|
||||||
|
{ text: 'SpringBoot Bean简介', link: '/Web-Backend/SpringBoot/SpringBootBean' },
|
||||||
|
{ text: 'SpringBoot3原生镜像', link: '/Web-Backend/SpringBoot/SpringBoot3-GraalVM' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'FastAPI',
|
||||||
|
items: [
|
||||||
|
{ text: 'FastAPI基础教程', link: '/Web-Backend/FastAPI/FastAPI-Guide' },
|
||||||
|
{ text: '基于OAuth2的安全验证', link: '/Web-Backend/FastAPI/OAuth2' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{ text: 'DevOps',
|
||||||
|
items: [
|
||||||
|
{ text: 'OpenObserve部署和使用', link: '/DevOps/OpenObserve' },
|
||||||
|
{ text: 'Jenkins部署和使用', link: '/DevOps/Jenkins' },
|
||||||
|
{ text: 'ElasticSearch部署和使用', link: '/DevOps/ElasticSearch' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{ text: 'Flutter',
|
||||||
|
items: [
|
||||||
|
{ text: 'Dart基础教程', link: '/Flutter/DartGuide' },
|
||||||
|
{ text: 'Flutter基础教程', link: '/Flutter/FlutterGuide' },
|
||||||
|
{ text: '实战技巧', link: '/Flutter/Practice' }
|
||||||
|
]
|
||||||
|
},
|
||||||
],
|
],
|
||||||
sidebar: {
|
sidebar: {
|
||||||
'/Web-Front/': [
|
'/Web-Front/': [
|
||||||
@@ -33,6 +73,7 @@ export default defineConfig({
|
|||||||
text: 'Web前端',
|
text: 'Web前端',
|
||||||
items: [
|
items: [
|
||||||
{ text: 'Vue3-Common', link: '/Web-Front/Vue3-Common' },
|
{ text: 'Vue3-Common', link: '/Web-Front/Vue3-Common' },
|
||||||
|
{ text: 'JavaScript知识点整理', link: '/Web-Front/JavaScript-Guide' }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -43,8 +84,24 @@ export default defineConfig({
|
|||||||
{ text: 'MySQL知识点', link: '/Web-Backend/MySQL-Knowledge' },
|
{ text: 'MySQL知识点', link: '/Web-Backend/MySQL-Knowledge' },
|
||||||
{ text: 'Flyway简单使用', link: '/Web-Backend/Flyway' },
|
{ text: 'Flyway简单使用', link: '/Web-Backend/Flyway' },
|
||||||
{ text: 'MyBatis简介和使用', link: '/Web-Backend/MyBatis' },
|
{ text: 'MyBatis简介和使用', link: '/Web-Backend/MyBatis' },
|
||||||
{ text: 'RustFS简介和使用', link: '/Web-Backend/RustFS' }
|
{ text: 'RustFS简介和使用', link: '/Web-Backend/RustFS' },
|
||||||
]
|
{ text: 'SpringBoot',
|
||||||
|
items: [
|
||||||
|
{ text: 'Spring IOC简介', link: '/Web-Backend/SpringBoot/SpringIOC' },
|
||||||
|
{ text: 'SpringBoot启动流程', link: '/Web-Backend/SpringBoot/SpringBoot-Start-Process' },
|
||||||
|
{ text: 'Spring MVC简介', link: '/Web-Backend/SpringBoot/SpringMVC' },
|
||||||
|
{ text: 'SpringBoot Starter原理', link: '/Web-Backend/SpringBoot/SpringBootStarter' },
|
||||||
|
{ text: 'SpringBoot Bean简介', link: '/Web-Backend/SpringBoot/SpringBootBean' },
|
||||||
|
{ text: 'SpringBoot3原生镜像', link: '/Web-Backend/SpringBoot/SpringBoot3-GraalVM' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{ text: 'FastAPI',
|
||||||
|
items: [
|
||||||
|
{ text: 'FastAPI基础教程', link: '/Web-Backend/FastAPI/FastAPI-Guide' },
|
||||||
|
{ text: '基于OAuth2的安全验证', link: '/Web-Backend/FastAPI/OAuth2' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
'/DevOps/': [
|
'/DevOps/': [
|
||||||
@@ -56,38 +113,6 @@ export default defineConfig({
|
|||||||
{ text: 'ElasticSearch部署和使用', link: '/DevOps/ElasticSearch' }
|
{ text: 'ElasticSearch部署和使用', link: '/DevOps/ElasticSearch' }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
|
||||||
'/SpringBoot/': [
|
|
||||||
{
|
|
||||||
text: 'SpringBoot',
|
|
||||||
items: [
|
|
||||||
{ text: 'Spring IOC简介', link: '/SpringBoot/SpringIOC' },
|
|
||||||
{ text: 'SpringBoot启动流程', link: '/SpringBoot/SpringBoot-Start-Process' },
|
|
||||||
{ text: 'Spring MVC简介', link: '/SpringBoot/SpringMVC' },
|
|
||||||
{ text: 'SpringBoot Starter原理', link: '/SpringBoot/SpringBootStarter' },
|
|
||||||
{ text: 'SpringBoot Bean简介', link: '/SpringBoot/SpringBootBean' },
|
|
||||||
{ text: 'SpringBoot3原生镜像', link: '/SpringBoot/SpringBoot3-GraalVM' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
'/FastAPI/': [
|
|
||||||
{
|
|
||||||
text: 'FastAPI',
|
|
||||||
items: [
|
|
||||||
{ text: 'FastAPI基础教程', link: '/FastAPI/FastAPIGuide' },
|
|
||||||
{ text: '基于OAuth2的FastApi安全验证', link: '/FastAPI/OAuth2' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
'/Flutter/': [
|
|
||||||
{
|
|
||||||
text: 'Flutter',
|
|
||||||
items: [
|
|
||||||
{ text: 'Dart基础教程', link: '/Flutter/DartGuide' },
|
|
||||||
{ text: 'Flutter基础教程', link: '/Flutter/FlutterGuide' },
|
|
||||||
{ text: '实战技巧', link: '/Flutter/Practice' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
---
|
|
||||||
layout: doc
|
|
||||||
title: FastAPI
|
|
||||||
---
|
|
||||||
|
|
||||||
# 内容导航
|
|
||||||
|
|
||||||
- [FastAPI基础教程](/FastAPI/FastAPIGuide)
|
|
||||||
- [基于OAuth2的FastApi安全验证](/FastAPI/OAuth2)
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
layout: doc
|
|
||||||
title: SpringBoot
|
|
||||||
---
|
|
||||||
|
|
||||||
# 内容导航
|
|
||||||
|
|
||||||
- [Spring IOC简介](/SpringBoot/SpringIOC)
|
|
||||||
- [SpringBoot启动流程](/SpringBoot/SpringBoot-Start-Process)
|
|
||||||
- [Spring MVC简介](/SpringBoot/SpringMVC)
|
|
||||||
- [SpringBoot Starter原理](/SpringBoot/SpringBootStarter)
|
|
||||||
- [SpringBoot Bean简介](/SpringBoot/SpringBootBean)
|
|
||||||
- [SpringBoot3原生镜像](/SpringBoot/SpringBoot3-GraalVM)
|
|
||||||
@@ -260,7 +260,7 @@ class BlogComment(AuditBase):
|
|||||||
```python
|
```python
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from pydantic import BaseModel, Field, field_validator
|
from pydantic import BaseModel, Field, field_validator, ConfigDict
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
@@ -316,22 +316,23 @@ class BlogResponse(BlogBase):
|
|||||||
create_time: datetime = Field(..., description="创建时间", alias="createTime")
|
create_time: datetime = Field(..., description="创建时间", alias="createTime")
|
||||||
update_time: datetime = Field(..., description="更新时间", alias="updateTime")
|
update_time: datetime = Field(..., description="更新时间", alias="updateTime")
|
||||||
|
|
||||||
class Config:
|
model_config = ConfigDict(
|
||||||
from_attributes = True
|
from_attributes=True,
|
||||||
populate_by_name = True
|
populate_by_name=True,
|
||||||
json_encoders = {
|
json_encoders={
|
||||||
# 自定义 datetime 类型的序列化格式
|
|
||||||
datetime: lambda dt: dt.strftime('%Y-%m-%d %H:%M:%S')
|
datetime: lambda dt: dt.strftime('%Y-%m-%d %H:%M:%S')
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class BlogCategoryResponse(BaseModel):
|
class BlogCategoryResponse(BaseModel):
|
||||||
name: str = Field(..., description="分类名称")
|
name: str = Field(..., description="分类名称")
|
||||||
count: int = Field(..., description="博客数量")
|
count: int = Field(..., description="博客数量")
|
||||||
|
|
||||||
class Config:
|
model_config = ConfigDict(
|
||||||
from_attributes = True
|
from_attributes=True,
|
||||||
populate_by_name = True
|
populate_by_name=True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class BlogStatsResponse(BaseModel):
|
class BlogStatsResponse(BaseModel):
|
||||||
@@ -348,30 +349,33 @@ class BlogVisitResponse(BaseModel):
|
|||||||
title: str = Field(None, description="博客标题")
|
title: str = Field(None, description="博客标题")
|
||||||
visit_time: datetime = Field(..., description="访问时间", alias="visitTime")
|
visit_time: datetime = Field(..., description="访问时间", alias="visitTime")
|
||||||
|
|
||||||
class Config:
|
model_config = ConfigDict(
|
||||||
from_attributes = True
|
from_attributes=True,
|
||||||
populate_by_name = True
|
populate_by_name=True,
|
||||||
json_encoders = {
|
json_encoders={
|
||||||
datetime: lambda dt: dt.strftime('%Y-%m-%d %H:%M:%S')
|
datetime: lambda dt: dt.strftime('%Y-%m-%d %H:%M:%S')
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class BlogLatestResponse(BaseModel):
|
class BlogLatestResponse(BaseModel):
|
||||||
id: int = Field(..., description="博客ID")
|
id: int = Field(..., description="博客ID")
|
||||||
title: str = Field(..., description="博客标题")
|
title: str = Field(..., description="博客标题")
|
||||||
|
|
||||||
class Config:
|
model_config = ConfigDict(
|
||||||
from_attributes = True
|
from_attributes=True,
|
||||||
populate_by_name = True
|
populate_by_name=True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class BlogAdjacentResponse(BaseModel):
|
class BlogAdjacentResponse(BaseModel):
|
||||||
id: int = Field(..., description="博客ID")
|
id: int = Field(..., description="博客ID")
|
||||||
title: str = Field(..., description="博客标题")
|
title: str = Field(..., description="博客标题")
|
||||||
|
|
||||||
class Config:
|
model_config = ConfigDict(
|
||||||
from_attributes = True
|
from_attributes=True,
|
||||||
populate_by_name = True
|
populate_by_name=True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class BlogCommentCreate(BaseModel):
|
class BlogCommentCreate(BaseModel):
|
||||||
@@ -399,18 +403,17 @@ class BlogCommentResponse(BlogCommentCreate):
|
|||||||
user_agent: str = Field(..., description="浏览器信息", alias="userAgent")
|
user_agent: str = Field(..., description="浏览器信息", alias="userAgent")
|
||||||
create_time: datetime = Field(..., description="创建时间", alias="createTime")
|
create_time: datetime = Field(..., description="创建时间", alias="createTime")
|
||||||
|
|
||||||
class Config:
|
model_config = ConfigDict(
|
||||||
from_attributes = True
|
from_attributes=True,
|
||||||
populate_by_name = True
|
populate_by_name=True,
|
||||||
json_encoders = {
|
json_encoders={
|
||||||
# 自定义 datetime 类型的序列化格式
|
|
||||||
datetime: lambda dt: dt.strftime('%Y-%m-%d %H:%M:%S')
|
datetime: lambda dt: dt.strftime('%Y-%m-%d %H:%M:%S')
|
||||||
}
|
}
|
||||||
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
  `@field_validator`为Pydantic V2的验证器装饰器。
|
  `@field_validator`为Pydantic V2的验证器装饰器。
|
||||||
  `class Config`为全局配置类,`from_attributes=True`表示允许从SQLAlchemy等ORM对象创建。
|
  `ConfigDict`为全局配置类,`from_attributes=True`表示允许从SQLAlchemy等ORM对象创建。`populate_by_name=True`表示允许通过字段的别名(alias)来赋值 `json_encoders`表示自定义特定类型的 JSON 序列化方式。
|
||||||
|
|
||||||
# 三、服务层
|
# 三、服务层
|
||||||
## 3.1 查询操作
|
## 3.1 查询操作
|
||||||
@@ -584,3 +587,234 @@ def delete_blog(db: Session, blog_id: int) -> bool:
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
```
|
```
|
||||||
|
|
||||||
|
# 四、路由层
|
||||||
|
```python
|
||||||
|
router = APIRouter(
|
||||||
|
prefix="/blog",
|
||||||
|
tags=["博客管理"],
|
||||||
|
responses={404: {"description": "Not found"}}
|
||||||
|
)
|
||||||
|
|
||||||
|
@router.get("/page", summary="分页查询博客", response_model=PageResult[BlogResponse])
|
||||||
|
def query_blog_by_page(
|
||||||
|
current_page: int = Query(1, ge=1, alias="currentPage", description="当前页码,从1开始"),
|
||||||
|
page_size: int = Query(10, ge=1, le=100, alias="pageSize", description="每页显示数量,1-100之间"),
|
||||||
|
db: Session = Depends(get_db)
|
||||||
|
):
|
||||||
|
return blog_service.query_blog_by_page(db, current_page, page_size)
|
||||||
|
|
||||||
|
@router.get("/condition", summary="条件查询博客", response_model=List[BlogResponse])
|
||||||
|
def query_blog_by_condition(query: BlogQuery = Depends(), db: Session = Depends(get_db)):
|
||||||
|
return blog_service.query_blog_by_condition(db, query)
|
||||||
|
|
||||||
|
@router.post("", summary="新增博客内容", response_model=bool)
|
||||||
|
def add_blog(
|
||||||
|
blog: BlogCreate = Body(..., description="博客创建数据"),
|
||||||
|
db: Session = Depends(get_db),
|
||||||
|
_=Depends(verify_token)
|
||||||
|
):
|
||||||
|
return blog_service.add_blog(db, blog)
|
||||||
|
|
||||||
|
@router.put("/{blog_id}", summary="更新博客内容", response_model=bool)
|
||||||
|
def update_blog(
|
||||||
|
blog_id: int = Path(..., ge=1, description="博客ID"),
|
||||||
|
blog: BlogUpdate = Body(..., description="博客更新数据"),
|
||||||
|
db: Session = Depends(get_db),
|
||||||
|
_=Depends(verify_token)
|
||||||
|
):
|
||||||
|
return blog_service.update_blog(db, blog_id, blog)
|
||||||
|
|
||||||
|
@router.delete("/{blog_id}", summary="删除博客内容", response_model=bool)
|
||||||
|
def delete_blog(
|
||||||
|
blog_id: int = Path(..., ge=1, description="博客ID"),
|
||||||
|
db: Session = Depends(get_db),
|
||||||
|
_=Depends(verify_token)
|
||||||
|
):
|
||||||
|
return blog_service.delete_blog(db, blog_id)
|
||||||
|
|
||||||
|
@router.put("/{blog_id}/comment", summary="新增博客评论", response_model=bool)
|
||||||
|
def add_blog_comment(
|
||||||
|
request: Request,
|
||||||
|
blog_id: int = Path(..., ge=1, description="博客ID"),
|
||||||
|
blog_comment: BlogCommentCreate = Body(..., description="博客评论数据"),
|
||||||
|
db: Session = Depends(get_db)
|
||||||
|
):
|
||||||
|
return blog_service.add_blog_comment(db, request, blog_id, blog_comment)
|
||||||
|
```
|
||||||
|
|
||||||
|
  路由装饰器参数中的`response_model`表示定义接口返回的数据模型。
|
||||||
|
  参数注解中的`Query()`表示参数来自URL查询字符串,`Path/Query/Body`分别对应路径参数、查询参数、请求体参数。
|
||||||
|
  `Depends()`表示依赖注入,自动解析参数或执行依赖函数。
|
||||||
|
  `db: Session = Depends(get_db)`表示获取数据库连接,`_=Depends(verify_token)`表示验证用户身份。
|
||||||
|
  `request: Request`可以获取到HTTP请求的完整上下文信息。
|
||||||
|
|
||||||
|
>[!TIP]
|
||||||
|
>这里的`query: BlogQuery = Depends()`会从查询参数中自动实例化`BlogQuery`对象,并进行数据验证和类型转换。
|
||||||
|
|
||||||
|
  注册路由:
|
||||||
|
```python
|
||||||
|
from fastapi import FastAPI
|
||||||
|
from .blog import router as blog_router
|
||||||
|
|
||||||
|
def register_routers(app: FastAPI):
|
||||||
|
app.include_router(blog_router, prefix="")
|
||||||
|
|
||||||
|
|
||||||
|
# main.py
|
||||||
|
app = FastAPI(title="Blog Service")
|
||||||
|
register_routers(app)
|
||||||
|
```
|
||||||
|
|
||||||
|
# 五、中间件
|
||||||
|
## 5.1 全局异常处理器
|
||||||
|
```python
|
||||||
|
from fastapi import Request, HTTPException, status
|
||||||
|
from fastapi.responses import JSONResponse
|
||||||
|
from sqlalchemy.exc import SQLAlchemyError
|
||||||
|
from config.logging import logger
|
||||||
|
|
||||||
|
|
||||||
|
# 自定义异常类
|
||||||
|
class AppException(Exception):
|
||||||
|
def __init__(self, message: str, details=None):
|
||||||
|
self.message = message
|
||||||
|
self.details = details
|
||||||
|
|
||||||
|
|
||||||
|
# 全局异常处理中间件
|
||||||
|
async def global_exception_handler(request: Request, call_next):
|
||||||
|
try:
|
||||||
|
# 记录请求信息(可选)
|
||||||
|
logger.info(f"请求: {request.method} {request.url}")
|
||||||
|
if request.query_params:
|
||||||
|
logger.info(f"查询参数: {dict(request.query_params)}")
|
||||||
|
|
||||||
|
response = await call_next(request)
|
||||||
|
|
||||||
|
# 记录响应信息(可选)
|
||||||
|
if response.status_code >= 400:
|
||||||
|
logger.warning(f"响应: {response.status_code}")
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
except AppException as e:
|
||||||
|
# 记录业务异常
|
||||||
|
logger.error(f"业务异常: {e.message} - 详情: {e.details}")
|
||||||
|
return JSONResponse(status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
content={"message": e.message, "details": e.details})
|
||||||
|
|
||||||
|
except SQLAlchemyError as e:
|
||||||
|
# 记录数据库异常
|
||||||
|
logger.critical(f"数据库异常: {str(e)}")
|
||||||
|
return JSONResponse(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
content={"message": "数据库操作失败", "details": str(e)})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
# 记录未知异常(带堆栈信息)
|
||||||
|
logger.critical(f"未知异常: {str(e)}")
|
||||||
|
return JSONResponse(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
content={"code": 500, "message": "服务器内部错误", "details": str(e)})
|
||||||
|
|
||||||
|
|
||||||
|
def get_credentials_exception() -> HTTPException:
|
||||||
|
return HTTPException(
|
||||||
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||||
|
detail="Could not validate credentials",
|
||||||
|
headers={"WWW-Authenticate": "Bearer"},
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5.2 日志处理器
|
||||||
|
```python
|
||||||
|
import atexit
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from fluent import sender
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
|
from config.setting import settings
|
||||||
|
|
||||||
|
FLUENTD_HOST = settings.FLUENTD_HOST
|
||||||
|
FLUENTD_PORT = 24224
|
||||||
|
TOPIC_TAG = 'blog-service'
|
||||||
|
|
||||||
|
# 日志级别
|
||||||
|
LOG_LEVEL = settings.LOG_LEVEL.upper()
|
||||||
|
|
||||||
|
# 日志格式
|
||||||
|
STDOUT_FORMAT = (
|
||||||
|
"<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | "
|
||||||
|
"<level>{level: <8}</level> | "
|
||||||
|
"<cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - "
|
||||||
|
"<level>{message}</level>"
|
||||||
|
)
|
||||||
|
|
||||||
|
FILE_FORMAT = (
|
||||||
|
"{time:YYYY-MM-DD HH:mm:ss.SSS} | "
|
||||||
|
"{level: <8} | "
|
||||||
|
"{name}:{function}:{line} - {message}"
|
||||||
|
)
|
||||||
|
|
||||||
|
fluent_sender = sender.FluentSender(
|
||||||
|
tag=TOPIC_TAG,
|
||||||
|
host=FLUENTD_HOST,
|
||||||
|
port=FLUENTD_PORT,
|
||||||
|
buffer_max_size=8 * 1024 * 1024,
|
||||||
|
timeout=3.0,
|
||||||
|
retry_timeout=60
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def log_to_fluent(message):
|
||||||
|
try:
|
||||||
|
record = message.record
|
||||||
|
|
||||||
|
# 构建结构化日志数据
|
||||||
|
log_data = {
|
||||||
|
'topic': TOPIC_TAG,
|
||||||
|
'timestamp': record['time'].timestamp(),
|
||||||
|
'level': record['level'].name.lower(),
|
||||||
|
'message': record['message'],
|
||||||
|
'source': f"{record['file'].path}:{record['line']}",
|
||||||
|
'module': record['module'],
|
||||||
|
'function': record['function'],
|
||||||
|
'process_id': record['process'].id,
|
||||||
|
'thread_id': record['thread'].id,
|
||||||
|
**record['extra']
|
||||||
|
}
|
||||||
|
|
||||||
|
if not fluent_sender.emit(TOPIC_TAG, log_data):
|
||||||
|
print(f"Fluentd 发送失败: {fluent_sender.last_error}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"日志处理异常: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
|
# 移除默认处理器
|
||||||
|
logger.remove()
|
||||||
|
|
||||||
|
# 添加控制台处理器
|
||||||
|
logger.add(
|
||||||
|
sink=sys.stdout,
|
||||||
|
level=LOG_LEVEL,
|
||||||
|
format=STDOUT_FORMAT,
|
||||||
|
colorize=True,
|
||||||
|
backtrace=True, # 显示完整异常堆栈
|
||||||
|
diagnose=True, # 显示详细异常信息
|
||||||
|
)
|
||||||
|
|
||||||
|
if settings.ENVIRONMENT == 'docker':
|
||||||
|
logger.add(
|
||||||
|
log_to_fluent,
|
||||||
|
level=LOG_LEVEL, # 处理 INFO 及以上级别
|
||||||
|
format="{message}", # 原始消息(实际使用结构化数据)
|
||||||
|
backtrace=True, # 启用堆栈回溯
|
||||||
|
diagnose=True # 显示诊断信息
|
||||||
|
)
|
||||||
|
|
||||||
|
atexit.register(fluent_sender.close)
|
||||||
|
|
||||||
|
# 导出配置好的logger
|
||||||
|
__all__ = ["logger"]
|
||||||
|
```
|
||||||
@@ -1,11 +1,32 @@
|
|||||||
---
|
---
|
||||||
layout: doc
|
layout: doc
|
||||||
title: Web后端
|
title: Web后端
|
||||||
|
description: Web后端开发技术文档,包含数据库、框架、中间件等
|
||||||
---
|
---
|
||||||
|
|
||||||
# 内容导航
|
# Web 后端开发
|
||||||
|
|
||||||
|
后端开发技术栈的学习笔记和总结。
|
||||||
|
|
||||||
|
## 主要内容
|
||||||
|
|
||||||
- [MySQL知识点](/Web-Backend/MySQL-Knowledge)
|
- [MySQL知识点](/Web-Backend/MySQL-Knowledge)
|
||||||
- [Flyway简单使用](/Web-Backend/Flyway)
|
- [Flyway简单使用](/Web-Backend/Flyway)
|
||||||
- [MyBatis简介和使用](/Web-Backend/MyBatis)
|
- [MyBatis简介和使用](/Web-Backend/MyBatis)
|
||||||
- [RustFS简介和使用](/Web-Backend/RustFS)
|
- [RustFS简介和使用](/Web-Backend/RustFS)
|
||||||
|
|
||||||
|
### 🍃 SpringBoot
|
||||||
|
SpringBoot 框架学习系列:
|
||||||
|
|
||||||
|
- [Spring IOC简介](/SpringBoot/SpringIOC)
|
||||||
|
- [SpringBoot启动流程](/SpringBoot/SpringBoot-Start-Process)
|
||||||
|
- [Spring MVC简介](/SpringBoot/SpringMVC)
|
||||||
|
- [SpringBoot Starter原理](/SpringBoot/SpringBootStarter)
|
||||||
|
- [SpringBoot Bean简介](/SpringBoot/SpringBootBean)
|
||||||
|
- [SpringBoot3原生镜像](/SpringBoot/SpringBoot3-GraalVM)
|
||||||
|
|
||||||
|
### 🐍 FastAPI
|
||||||
|
Python FastAPI 框架学习:
|
||||||
|
|
||||||
|
- [FastAPI基础教程](/FastAPI/FastAPI-Guide)
|
||||||
|
- [基于OAuth2的FastApi安全验证](/FastAPI/OAuth2)
|
||||||
1761
docs/Web-Front/JavaScript-Guide.md
Normal file
1761
docs/Web-Front/JavaScript-Guide.md
Normal file
File diff suppressed because it is too large
Load Diff
BIN
docs/Web-Front/images/promise基础.png
Normal file
BIN
docs/Web-Front/images/promise基础.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.3 KiB |
BIN
docs/Web-Front/images/普通函数作用域链.png
Normal file
BIN
docs/Web-Front/images/普通函数作用域链.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
BIN
docs/Web-Front/images/理解原型.png
Normal file
BIN
docs/Web-Front/images/理解原型.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
BIN
docs/Web-Front/images/闭包函数作用域链.png
Normal file
BIN
docs/Web-Front/images/闭包函数作用域链.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 64 KiB |
@@ -1,8 +1,14 @@
|
|||||||
---
|
---
|
||||||
layout: doc
|
layout: doc
|
||||||
title: Web前端
|
title: Web前端
|
||||||
|
description: Web前端开发技术文档
|
||||||
---
|
---
|
||||||
|
|
||||||
# 内容导航
|
# Web 前端开发
|
||||||
|
|
||||||
|
前端开发技术栈的学习笔记和总结。
|
||||||
|
|
||||||
|
## 主要内容
|
||||||
|
|
||||||
- [Vue3-Common](/Web-Front/Vue3-Common)
|
- [Vue3-Common](/Web-Front/Vue3-Common)
|
||||||
|
- [JavaScript知识点整理](/Web-Front/JavaScript-Guide)
|
||||||
Reference in New Issue
Block a user