Files
common-telemetry/README.md
2026-01-29 16:04:57 +08:00

233 lines
7.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Microservice Common Lib (Rust)
这是微服务架构的通用基础库 (`common-telemetry`),旨在统一所有服务的错误处理标准、日志格式以及分布式链路追踪。
## ✨ 核心特性
* **统一错误处理 (Error)**:
* 基于 `thiserror``anyhow` 的最佳实践。
* **双 Token 支持**: 明确区分 `AccessTokenExpired` (20001) 和 `RefreshTokenExpired` (20002)。
* **Axum 集成**: 实现了 `IntoResponse`,自动将错误转换为标准 JSON 格式并设置正确的 HTTP 状态码。
* **第三方库适配**: 提供了 `sqlx`, `redis`, `validator` 的可选集成。
* *智能转换*: 例如 `sqlx::Error::RowNotFound` 会自动转换为 **404 Not Found**,而不是 500 Database Error。
* **可观测性 (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` 中,你可以根据需要开启 `sqlx``redis` 支持:
```toml
[dependencies]
# 引入基础功能 + SQLX 支持
common-telemetry = { version = "0.1", registry = "kellnr", features = ["with-sqlx", "with-validator"] }
# 注意:你需要确保服务本身引用的 sqlx 版本与 common-telemetry 兼容
sqlx = { version = "0.7", features = ["postgres", "runtime-tokio"] }
```
*注意:使用此方式,`user-service` 项目也需要在 `.cargo/config.toml` 中配置 registry 地址。*
#### 方式 B: 通过 Gitea (Git) 引入
```toml
[dependencies]
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)
由于实现了 `From<T>`,你可以直接使用 `?` 操作符,库会自动处理类型转换和 HTTP 映射。
```rust
use axum::{Json, response::IntoResponse};
use common_telemetry::AppError; // 引入统一错误
use validator::Validate;
#[derive(serde::Deserialize, Validate)]
struct CreateUserReq {
#[validate(email)]
email: String,
}
async fn create_user(
Json(payload): Json<CreateUserReq>,
) -> Result<Json<String>, AppError> {
// 1. 校验错误 (自动转 AppError::ValidationError -> HTTP 400)
payload.validate()?;
// 2. 数据库查询 (自动转 AppError::DbError -> HTTP 500)
// 特殊情况:如果是 RowNotFound会自动转为 AppError::NotFound -> HTTP 404
let _user = sqlx::query!("SELECT * FROM users WHERE email = $1", payload.email)
.fetch_optional(&pool)
.await?;
// 3. 业务逻辑错误 (手动返回)
if _user.is_some() {
return Err(AppError::AlreadyExists(format!("User {} already exists", payload.email)));
}
Ok(Json("Created".into()))
}
```
---
## ⚙️ 功能模块说明 (Feature Flags)
本库采用高度模块化设计,建议按需开启 Feature 以减少编译体积:
| Feature | 说明 | 包含依赖 |
| :--- | :--- | :--- |
| **`default`** | 默认开启全功能 | `full` |
| **`full`** | 包含基础功能及所有第三方集成 | `error`, `telemetry`, `with-sqlx`, `with-redis`, `with-anyhow`, `with-validator` |
| **`error`** | 仅使用基础错误处理 | `thiserror`, `axum`, `serde` |
| **`telemetry`** | 仅使用日志与链路追踪 | `tracing` 全家桶 |
| **`with-sqlx`** | 集成 `sqlx` 错误转换 | `sqlx` (自动处理 RowNotFound) |
| **`with-redis`** | 集成 `redis` 错误转换 | `redis` |
| **`with-validator`** | 集成 `validator` 错误转换 | `validator` |
| **`with-anyhow`** | 集成 `anyhow` 兜底错误 | `anyhow` |
**示例 (只用错误 + SQLX支持):**
```toml
common-telemetry = { version = "0.1", default-features = false, features = ["error", "with-sqlx"] }
```
---
## 📝 错误码对照表
前端开发请参考以下业务状态码 (Code)
| Code | 枚举 | HTTP | 含义 | 前端建议动作 |
| :--- | :--- | :--- | :--- | :--- |
| `0` | `Success` | 200 | 成功 | - |
| **10xxx: 基础设施** | | | | |
| `10000` | `ServerError` | 500 | 服务器内部错误 | 提示“系统繁忙” |
| `10001` | `DbError` | 500 | 数据库错误 | 提示“系统繁忙” |
| `10002` | `CacheError` | 500 | 缓存服务错误 | 提示“系统繁忙” |
| **20xxx: 认证授权** | | | | |
| `20000` | `Unauthorized` | 401 | 未授权/签名无效 | 跳转登录 |
| **`20001`** | **`AccessTokenExpired`** | **401** | **Access Token 过期** | **使用 Refresh Token 静默刷新** |
| **`20002`** | **`RefreshTokenExpired`** | **401** | **Refresh Token 过期** | **强制登出,跳转登录页** |
| `20003` | `PermissionDenied` | 403 | 权限不足 | 提示无权访问 |
| **30xxx: 客户端错误** | | | | |
| `30000` | `BadRequest` | 400 | 请求参数通用错误 | 提示错误信息 |
| `30001` | `ValidationError` | 400 | 表单校验失败 | 提示具体字段错误 |
| `30002` | `ResourceNotFound` | 404 | 资源不存在 | 提示“未找到数据” |
| `30003` | `ResourceAlreadyExists`| 409 | 资源已存在 | 提示“重复创建” |
---
## 🛠 开发注意事项
1. **Cargo.lock**: 本项目已将 `Cargo.lock` 加入 `.gitignore`,这是作为 Library 的最佳实践。
2. **测试**: 运行集成测试以验证全链路功能。
```bash
# 使用 --nocapture 查看详细步骤打印
cargo test -- --nocapture
```