203 lines
6.0 KiB
Markdown
203 lines
6.0 KiB
Markdown
# Microservice Common Lib (Rust)
|
||
|
||
这是微服务架构的通用基础库,旨在统一所有服务的错误处理标准、日志格式以及分布式链路追踪。
|
||
|
||
## ✨ 核心特性
|
||
|
||
* **统一错误处理 (Error)**:
|
||
* 基于 `thiserror` 和 `anyhow` 的最佳实践。
|
||
* **双 Token 支持**: 明确区分 `AccessTokenExpired` (20001) 和 `RefreshTokenExpired` (20002)。
|
||
* **Axum 集成**: 实现了 `IntoResponse`,自动将错误转换为标准 JSON 格式并设置正确的 HTTP 状态码。
|
||
* **可观测性 (Telemetry)**:
|
||
* 基于 `tracing` 生态。
|
||
* 支持 **JSON 结构化日志** (适配 ELK/Loki)。
|
||
* 支持 **控制台 + 文件双写**。
|
||
* 支持 **非阻塞 (Non-blocking)** 异步日志写入与按天滚动。
|
||
* **模块化设计**: 通过 Feature Flags 按需引入。
|
||
|
||
---
|
||
|
||
## 🚀 发布指南
|
||
|
||
你可以选择将此库发布到私有 Cargo 仓库 (Kellnr),或者直接作为 Git 依赖发布到 Gitea。
|
||
|
||
### 方法一:发布到 Kellnr (推荐)
|
||
|
||
Kellnr 是一个私有的 Crates.io 镜像与仓库。
|
||
|
||
#### 1. 配置本地 Cargo
|
||
在本项目根目录(或全局 `~/.cargo/config.toml`)创建/修改 `.cargo/config.toml`,注册你的私有仓库:
|
||
|
||
```toml
|
||
# .cargo/config.toml
|
||
[registries.kellnr]
|
||
# 注册表名称自定义,这里叫 "kellnr"
|
||
index = "sparse+https://kellnr.shay7sev.site/api/v1/crates/"
|
||
|
||
[net]
|
||
git-fetch-with-cli = true
|
||
```
|
||
|
||
#### 2. 登录认证
|
||
使用你的 Kellnr 账户 Token 进行登录(只需执行一次):
|
||
|
||
```bash
|
||
cargo login --registry kellnr <YOUR_AUTH_TOKEN>
|
||
```
|
||
|
||
#### 3. 修改 Cargo.toml
|
||
确保 `Cargo.toml` 中配置了禁止发布到公网,并指定了私有仓库:
|
||
|
||
```toml
|
||
[package]
|
||
name = "common-telemetry"
|
||
version = "0.1.0"
|
||
# ...
|
||
publish = ["kellnr"] # 关键:防止误发到 crates.io
|
||
```
|
||
|
||
#### 4. 执行发布
|
||
```bash
|
||
cargo publish --registry kellnr
|
||
```
|
||
|
||
---
|
||
|
||
### 方法二:推送到 Gitea (Git 依赖)
|
||
|
||
如果你不想走 Cargo Registry 流程,可以直接作为 Git 仓库使用。
|
||
|
||
```bash
|
||
# 初始化 git (如果尚未初始化)
|
||
git init
|
||
git branch -M main
|
||
|
||
# 添加远程仓库 (替换为你的实际仓库地址)
|
||
git remote add origin ssh://git@gitea.shay7sev.site:2222/admin/common-telemetry.git
|
||
|
||
# 推送代码
|
||
git add .
|
||
git commit -m "Initial commit"
|
||
git push -u origin main
|
||
```
|
||
|
||
---
|
||
|
||
## 📦 如何在其他服务中使用
|
||
|
||
假设你要在 `user-service` 中使用此库。
|
||
|
||
### 1. 引入依赖
|
||
|
||
#### 方式 A: 通过 Kellnr 引入 (如果已发布)
|
||
在 `user-service` 的 `Cargo.toml` 中:
|
||
|
||
```toml
|
||
[dependencies]
|
||
# 指定 registry
|
||
common-telemetry = { version = "0.1", registry = "kellnr", features = ["full"] }
|
||
```
|
||
*注意:使用此方式,`user-service` 项目也需要在 `.cargo/config.toml` 中配置 registry 地址。*
|
||
|
||
#### 方式 B: 通过 Gitea (Git) 引入 (简单直接)
|
||
在 `user-service` 的 `Cargo.toml` 中:
|
||
|
||
```toml
|
||
[dependencies]
|
||
# 指定 git 地址
|
||
common-telemetry = { git = "ssh://git@gitea.shay7sev.site:2222/admin/common-telemetry.git", branch = "main", features = ["full"] }
|
||
```
|
||
|
||
### 2. 代码集成示例
|
||
|
||
#### A. 初始化日志 (main.rs)
|
||
|
||
```rust
|
||
use common_telemetry::telemetry::{self, TelemetryConfig};
|
||
|
||
#[tokio::main]
|
||
async fn main() {
|
||
// 1. 配置
|
||
let config = TelemetryConfig {
|
||
service_name: "user-service".into(),
|
||
log_level: "info".into(), // 或 "debug,sqlx=error"
|
||
log_to_file: true, // 生产环境建议开启
|
||
log_dir: Some("./logs".into()),
|
||
log_file: Some("user.log".into()),
|
||
};
|
||
|
||
// 2. 初始化 Tracing
|
||
// !!! 警告:必须将 guard 赋值给一个变量 (_guard),并保持它在 main 函数整个生命周期内存活
|
||
// 否则日志文件写入线程会被立即销毁!
|
||
let _guard = telemetry::init(config);
|
||
|
||
tracing::info!("User Service started success!");
|
||
|
||
// ... 启动 Axum ...
|
||
}
|
||
```
|
||
|
||
#### B. 错误处理与响应 (Handler)
|
||
|
||
```rust
|
||
use axum::{Json, response::IntoResponse};
|
||
use common_telemetry::AppError; // 引入统一错误
|
||
|
||
async fn get_profile(token: String) -> Result<Json<UserProfile>, AppError> {
|
||
// 模拟:Token 过期
|
||
if token_is_expired(&token) {
|
||
// 直接返回枚举,库会自动处理为 JSON Response (Code: 20001)
|
||
// 并且会自动打印 Error 级别的日志
|
||
return Err(AppError::AccessTokenExpired);
|
||
}
|
||
|
||
// 模拟:数据库错误
|
||
let user = db::find_user().await
|
||
.map_err(|e| AppError::DbError(e.to_string()))?;
|
||
|
||
Ok(Json(user))
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## ⚙️ 功能模块说明 (Feature Flags)
|
||
|
||
为了减少编译时间和依赖大小,你可以按需开启功能:
|
||
|
||
| Feature | 说明 | 包含依赖 |
|
||
| :--- | :--- | :--- |
|
||
| **`default`** | 默认开启所有功能 | `full` |
|
||
| **`full`** | 全功能集合 | `error`, `telemetry` |
|
||
| **`error`** | 仅使用错误处理与 HTTP 响应 | `thiserror`, `axum`, `serde` |
|
||
| **`telemetry`** | 仅使用日志与链路追踪 | `tracing`, `tracing-subscriber`, `tracing-appender` |
|
||
|
||
**示例 (只用日志模块):**
|
||
```toml
|
||
common-telemetry = { version = "0.1", default-features = false, features = ["telemetry"] }
|
||
```
|
||
|
||
## 📝 错误码对照表
|
||
|
||
前端开发请参考以下业务状态码 (Code):
|
||
|
||
| Code | 枚举 | 含义 | 前端建议动作 |
|
||
| :--- | :--- | :--- | :--- |
|
||
| `0` | `Success` | 成功 | - |
|
||
| `10000` | `ServerError` | 服务器内部错误 | 提示“系统繁忙” |
|
||
| `10001` | `BadRequest` | 请求参数错误 | 提示错误信息 |
|
||
| `20000` | `Unauthorized` | 未授权/签名无效 | 跳转登录 |
|
||
| **`20001`** | **`AccessTokenExpired`** | **Access Token 过期** | **使用 Refresh Token 静默刷新** |
|
||
| **`20002`** | **`RefreshTokenExpired`** | **Refresh Token 过期** | **强制登出,跳转登录页** |
|
||
| `20003` | `PermissionDenied` | 权限不足 | 提示无权访问 |
|
||
|
||
---
|
||
|
||
## 🛠 开发注意事项
|
||
|
||
1. **Cargo.lock**: 本项目已将 `Cargo.lock` 加入 `.gitignore`,这是作为 Library 的最佳实践。
|
||
2. **测试**: 运行集成测试以验证全链路功能。
|
||
```bash
|
||
# 使用 --nocapture 查看详细步骤打印
|
||
cargo test -- --nocapture
|
||
``` |