Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 75756dd5fb | |||
| 8421e06fa8 | |||
| 18e4f7e891 |
+60
-1
@@ -14,6 +14,64 @@ xlgo 框架更新日志。本文档遵循 [Keep a Changelog](https://keepachange
|
||||
|
||||
---
|
||||
|
||||
## [1.1.1] - 2026-06-23
|
||||
|
||||
> 本版本为 v1.1.0 的补丁发布:补 ServerConfig.Host 字段、统一面向用户文案为中文、修正 README 过时/错误描述。
|
||||
|
||||
### Added ✨
|
||||
|
||||
#### ServerConfig.Host(绑定地址)
|
||||
|
||||
`server` 新增 `host` 字段,控制监听地址:
|
||||
|
||||
- `host: ""`(默认)→ `:8080`,监听所有接口(0.0.0.0),向后兼容
|
||||
- `host: "127.0.0.1"` → `127.0.0.1:8080`,仅本机(前面有 nginx 时常用)
|
||||
- `host: "10.0.0.5"` → 绑定内网网卡
|
||||
|
||||
避免生产环境无意暴露在 0.0.0.0。启动日志相应区分"所有接口"/指定地址。
|
||||
|
||||
### Changed 🔄
|
||||
|
||||
#### 面向用户文案统一中文
|
||||
|
||||
v1.1.0 前部分面向用户/调用的文案为英文,与其余中文文案不一致。本次统一为中文:
|
||||
|
||||
- `middleware/recover.go`:`"Panic recovered"` → `"panic 已恢复"`;`"Panic: %v"` → `"服务器内部错误: %v"`(消除同文件内中英矛盾)
|
||||
- `middleware/logger.go`:5 处日志消息(慢请求/请求错误/客户端请求错误/API 请求/请求)改中文
|
||||
- `middleware/metrics.go`:3 个 Prometheus `Help` 文本改中文
|
||||
- `app.go` / `database/manager.go` / `logger/logger.go`:英文 error 改中文
|
||||
|
||||
**保留英文**(非文案,属协议/约定/技术必需):JSON 字段名(`code`/`msg`/`data`)、health 探针状态枚举(`ok`/`error`/`disabled`)、Prometheus metric `Name`(命名规则限制)、`database/manager.go` 中匹配 MySQL 驱动错误串的英文(`"Access denied"` 等,改了会失效)、Redis/CSRF Token/JWT/OSS 等技术专有名词。
|
||||
|
||||
### Fixed 🐛
|
||||
|
||||
#### README 错误描述修正
|
||||
|
||||
v1.1.0 后 README 存在过时/错误描述,照抄会导致新用户启动失败,本次修正:
|
||||
|
||||
- **删除目录结构里已移除的 `wire/` 段**(wire 包 v1.1.0 已删)
|
||||
- **快速开始配置示例**:`jwt.secret` 补足 ≥32 字节(否则被 v1.1.0 `Validate` 拦截启动失败);`expire: 86400`(int 秒)改为 `expire: "24h"`(`time.Duration`),补 `refresh_expire`/`issuer`/`algorithm`
|
||||
- `server` 段补 `host`/`read_timeout`/`write_timeout`/`idle_timeout`/`shutdown_timeout`/`response_mode` 字段
|
||||
- v1.0.2 更新日志标注 `WithWire` 已于 v1.1.0 移除
|
||||
- 目录结构补 v1.1.0 新文件:`middleware/metrics.go`、`middleware/timeout.go`、`router/metrics.go`、`config/validate.go`、`response/mode.go`
|
||||
- 框架特性段重写为三组(架构可注入 / 生产就绪 / 基础功能),补全 v1.1.0 能力
|
||||
- 响应格式段补 `Mode` 开关(`ModeBusiness`/`ModeREST`)与 `Custom` API
|
||||
|
||||
#### README 首段重写
|
||||
|
||||
原首段描述("轻量级 Web 开发框架,提供完整后端基础设施")过于普通化,适用于多数 Gin 脚手架,无辨识度。重写为:
|
||||
|
||||
- tagline 点明核心差异:组件全部 Manager 化,简单调用与注入实例兼得
|
||||
- "为什么是 xlgo"段:对比一般 Gin 脚手架的包级单例痛点 + 对照代码
|
||||
- 5 条差异化卖点(可注入 / 生产就绪内置 / 零 Fatal / 默认轻量 / 可插拔方言)
|
||||
- 30 秒上手极简可跑示例
|
||||
|
||||
### 升级说明 🛠️
|
||||
|
||||
从 v1.1.0 升级无破坏性变更,`go get github.com/EthanCodeCraft/xlgo-core@v1.1.1` 即可。`host` 字段默认空,行为与 v1.1.0 一致。
|
||||
|
||||
---
|
||||
|
||||
## [1.1.0] - 2026-06-23
|
||||
|
||||
> 本版本定位为 **HA & Manager 化 release**:高可用与生产就绪改进 + 组件 Manager 化。对应体检报告 #10-#24。
|
||||
@@ -516,7 +574,8 @@ v1.0.2 引入可插拔方言注册表后,`gorm.io/driver/postgres` 成为直
|
||||
- 基础框架功能
|
||||
- 完整示例代码
|
||||
|
||||
[Unreleased]: https://github.com/EthanCodeCraft/xlgo-core/compare/v1.1.0...HEAD
|
||||
[Unreleased]: https://github.com/EthanCodeCraft/xlgo-core/compare/v1.1.1...HEAD
|
||||
[1.1.1]: https://github.com/EthanCodeCraft/xlgo-core/releases/tag/v1.1.1
|
||||
[1.1.0]: https://github.com/EthanCodeCraft/xlgo-core/releases/tag/v1.1.0
|
||||
[1.0.4]: https://github.com/EthanCodeCraft/xlgo-core/releases/tag/v1.0.4
|
||||
[1.0.3]: https://github.com/EthanCodeCraft/xlgo-core/releases/tag/v1.0.3
|
||||
|
||||
@@ -6,22 +6,85 @@
|
||||
<img src="https://img.shields.io/badge/License-MIT-green?style=for-the-badge" alt="License">
|
||||
</p>
|
||||
|
||||
xlgo 是一个基于 Go + Gin 的轻量级 Web 开发框架,提供了完整的后端开发基础设施,包括配置管理、数据库访问、缓存、认证、日志、文件存储等常用功能。
|
||||
> 基于 Go + Gin 的后端开发框架。**组件全部 Manager 化**——既能像脚本一样用包级函数简单调用,又能像正经框架一样注入实例、跑多套、塞 mock 做单测。
|
||||
|
||||
## 为什么是 xlgo
|
||||
|
||||
多数 Gin 脚手架把数据库、Redis、缓存、JWT、日志做成**包级全局单例**:写小项目顺手,但一旦要做单元测试、同进程跑多套实例、或替换实现,就动弹不得。xlgo 把这些组件全部抽象成 `XxxManager`,同时保留包级便捷函数做 facade——**简单用法零成本,复杂场景不封顶**:
|
||||
|
||||
```go
|
||||
// 简单用法:包级函数,跟单例脚手架一样直接
|
||||
database.InitDB(cfg)
|
||||
db := database.GetDB()
|
||||
|
||||
// 同一份代码,也能注入实例 / 跑多套 / 塞 mock
|
||||
myDB := database.NewManager(cfg)
|
||||
myDB.Open(ctx) // 独立实例,不受全局影响
|
||||
database.SetDefaultManager(myDB) // 或提升为全局默认
|
||||
mockCache := &fakeCacheSvc{}
|
||||
cache.SetDefaultCacheManager(&cache.CacheManager{}) // 测试注入
|
||||
```
|
||||
|
||||
### 区别于一般 Gin 脚手架的几点
|
||||
|
||||
- **组件可注入** — database / redis / cache / jwt / storage / logger 均为 `Manager` + 全局 facade 双轨,支持多实例与 mock 注入,而非写死的包级单例
|
||||
- **生产就绪内置** — `/livez` `/readyz`、Prometheus `/metrics`、主库探活自愈、请求级超时、优雅关闭(等待 in-flight goroutine)开箱即用,不用自己搭
|
||||
- **框架内零 Fatal** — 错误一律返回由调用方处理,框架代码不 `panic` 杀进程
|
||||
- **默认轻量、按需启用** — `New()` 什么都不开,`NewFullStack()` 一键全开,中间任意组合;`Without*` 精细排除
|
||||
- **可插拔数据库方言** — GORM 方言注册表,内置 MySQL / PostgreSQL,可扩展 SQLite / ClickHouse 等
|
||||
|
||||
### 30 秒上手
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
xlgo "github.com/EthanCodeCraft/xlgo-core"
|
||||
"github.com/EthanCodeCraft/xlgo-core/response"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := xlgo.New(
|
||||
xlgo.WithConfigPath("./config.yaml"),
|
||||
xlgo.WithLogger(),
|
||||
xlgo.WithHealthRoutes(),
|
||||
)
|
||||
app.GetRouter().GET("/", func(c *gin.Context) {
|
||||
response.Success(c, gin.H{"hello": "xlgo"})
|
||||
})
|
||||
_ = app.Run()
|
||||
}
|
||||
```
|
||||
|
||||
## 框架特性
|
||||
|
||||
- **配置管理** - 支持 YAML 配置文件,环境变量覆盖,配置热更新
|
||||
- **数据库** - 基于 GORM 的可插拔方言注册表,内置 MySQL / PostgreSQL,可注册任意 GORM 驱动;支持自动迁移、重试、连接池、读写分离
|
||||
- **缓存** - Redis 缓存,支持分布式缓存、键前缀、TTL,SCAN 优化
|
||||
- **认证** - JWT 认证,支持 Token 黑名单、刷新机制
|
||||
- **日志** - 分级日志(API、数据库),日志轮转
|
||||
- **中间件** - CORS、限流、日志、认证、CSRF 防护
|
||||
- **文件存储** - 本地存储 + 阿里云 OSS 支持
|
||||
- **实时通信** - SSE 流式响应 + WebSocket 支持
|
||||
- **定时任务** - 内置任务调度器
|
||||
- **验证器** - 请求参数验证,支持自定义错误消息
|
||||
- **错误处理** - 统一错误码体系
|
||||
- **CLI 工具** - 脚手架工具,快速创建项目和代码
|
||||
**架构与可注入性**
|
||||
- **组件 Manager 化** - database / redis / cache / jwt / storage / logger 均为 `XxxManager` + 全局 facade 双轨,支持多实例与测试注入 mock
|
||||
- **可插拔数据库方言** - GORM 方言注册表,内置 MySQL / PostgreSQL,可注册 SQLite / ClickHouse 等任意驱动
|
||||
- **读写分离** - 主库 + 多副本,`ReplicaPicker` 策略可插拔(轮询 / 随机 / 自定义),context 路由强制主库
|
||||
- **Lifecycle Hooks** - `OnInit / OnStart / OnReady / OnStop` 生命周期钩子,可插拔启动/关闭逻辑
|
||||
|
||||
**生产就绪**
|
||||
- **健康探针** - `/livez`(存活)+ `/readyz`(就绪)+ `/health`(兼容),K8s probe 友好
|
||||
- **Prometheus 指标** - `/metrics` 端点 + 请求计数 / 耗时 / 在飞数采集中间件
|
||||
- **依赖健康自愈** - 主库后台探活,连续失败标记不健康联动 503;从库失败临时剔除、恢复自动纳入
|
||||
- **请求级超时** - `middleware.Timeout` 级联取消下游 GORM/Redis
|
||||
- **优雅关闭** - `App.Go` 管理后台 goroutine,Shutdown 时 cancel + 等待退出(带超时)
|
||||
- **配置校验** - 启动期 `Validate` 拦截非法配置(端口/密钥/必填字段),错误前置
|
||||
|
||||
**基础功能**
|
||||
- **配置管理** - YAML + 环境变量覆盖 + 热更新,`time.Duration` 字符串解析(`"24h"`)
|
||||
- **缓存** - Redis 缓存,键前缀、TTL、SCAN 优化、分布式锁
|
||||
- **认证** - JWT 认证,Token 黑名单、刷新机制,HMAC 算法可选
|
||||
- **日志** - 分级日志(通用 / API / DB 三分流),lumberjack 轮转
|
||||
- **中间件** - CORS、限流(内存 + Redis 版)、请求日志、认证、CSRF、RequestID、Recover
|
||||
- **文件存储** - 本地 + 阿里云 OSS
|
||||
- **实时通信** - SSE 流式响应 + WebSocket
|
||||
- **定时任务** - 内置调度器(interval / daily / weekly / cron)
|
||||
- **验证器** - 请求参数验证,自定义错误消息
|
||||
- **响应模式** - `ModeBusiness`(业务码,默认)/ `ModeREST`(按错误码映射 HTTP status)一键切换
|
||||
- **CLI 工具** - 脚手架 + 代码生成(handler/repository/model/service)
|
||||
|
||||
## 快速开始
|
||||
|
||||
@@ -47,8 +110,14 @@ go mod tidy
|
||||
|
||||
```yaml
|
||||
server:
|
||||
host: "" # 绑定地址,空=监听所有接口;127.0.0.1=仅本机
|
||||
port: 8080
|
||||
mode: development
|
||||
read_timeout: 15s
|
||||
write_timeout: 30s
|
||||
idle_timeout: 60s
|
||||
shutdown_timeout: 30s
|
||||
response_mode: business # business(默认,全200+业务码) 或 rest(按错误码映射HTTP status)
|
||||
|
||||
database:
|
||||
driver: mysql # mysql(默认)或 postgres
|
||||
@@ -68,8 +137,11 @@ redis:
|
||||
db: 0
|
||||
|
||||
jwt:
|
||||
secret: your_jwt_secret_key
|
||||
expire: 86400
|
||||
secret: your_jwt_secret_key_at_least_32_bytes # ≥32 字节,否则启动期被 Validate 拦截
|
||||
expire: "24h" # time.Duration,支持 "24h"/"30m" 等
|
||||
refresh_expire: "168h" # 刷新 token 过期时间
|
||||
issuer: xlgo
|
||||
algorithm: HS256 # HS256(默认)/HS384/HS512
|
||||
|
||||
storage:
|
||||
driver: local
|
||||
@@ -574,6 +646,16 @@ response.Unauthorized(c, "请先登录")
|
||||
response.NotFound(c, "资源不存在")
|
||||
response.ServerError(c, "服务器错误")
|
||||
response.RateLimit(c)
|
||||
|
||||
// 显式指定 HTTP status(不受 Mode 影响)
|
||||
response.Custom(c, http.StatusBadRequest, response.CodeFail, "参数错误", nil)
|
||||
```
|
||||
|
||||
**响应模式**(v1.1.0):默认 `ModeBusiness`,所有响应 HTTP 200 + 业务码(兼容存量)。切换 `ModeREST` 后,失败响应按错误码映射对应 HTTP status(401/404/429/500...),body 仍带业务码,便于 APM / Prometheus / 网关按 status 区分异常:
|
||||
|
||||
```go
|
||||
response.SetMode(response.ModeREST) // 代码切换
|
||||
// 或在 config.yaml 配置:server.response_mode: rest
|
||||
```
|
||||
|
||||
---
|
||||
@@ -638,15 +720,16 @@ xlgo/
|
||||
├── compress/
|
||||
│ └── compress.go # Gzip/Zip 压缩解压
|
||||
├── config/
|
||||
│ └── config.go # 配置管理(支持热更新)
|
||||
│ ├── config.go # 配置管理(支持热更新、time.Duration 解析)
|
||||
│ └── validate.go # 配置校验(启动期拦截非法配置)
|
||||
├── console/
|
||||
│ └── console.go # 彩色控制台输出
|
||||
├── cron/
|
||||
│ └── cron.go # 定时任务调度
|
||||
├── database/
|
||||
│ ├── manager.go # 数据库管理器(主从、Picker、Init/Close/HealthCheck)
|
||||
│ ├── manager.go # 数据库管理器(主从、Picker、探活自愈、Init/Close/HealthCheck)
|
||||
│ ├── dialect.go # GORM 方言注册表(mysql / postgres,可扩展)
|
||||
│ └── redis.go # Redis 连接
|
||||
│ └── redis.go # Redis 连接管理器(RedisManager)
|
||||
├── handler/
|
||||
│ └── handler.go # 基础处理器(类型安全参数获取)
|
||||
├── jwt/
|
||||
@@ -659,18 +742,22 @@ xlgo/
|
||||
│ ├── cors.go # CORS 跨域中间件
|
||||
│ ├── csrf.go # CSRF 防护中间件
|
||||
│ ├── logger.go # 请求日志中间件
|
||||
│ ├── metrics.go # Prometheus 指标中间件
|
||||
│ ├── ratelimit.go # 限流中间件
|
||||
│ ├── requestid.go # 请求ID中间件
|
||||
│ └── recover.go # Panic恢复中间件
|
||||
│ ├── recover.go # Panic恢复中间件
|
||||
│ └── timeout.go # 请求级超时中间件
|
||||
├── model/
|
||||
│ └── base.go # 基础模型
|
||||
├── repository/
|
||||
│ └── repository.go # 基础仓库(泛型CRUD)
|
||||
├── response/
|
||||
│ ├── response.go # 统一响应格式
|
||||
│ ├── mode.go # 响应模式开关(business / REST)
|
||||
│ └── error.go # 统一错误码
|
||||
├── router/
|
||||
│ └── router.go # 路由注册中心(模块化/版本化)
|
||||
│ ├── router.go # 路由注册中心(模块化/版本化、livez/readyz/health)
|
||||
│ └── metrics.go # Prometheus /metrics 端点
|
||||
├── sse/
|
||||
│ └── sse.go # SSE 流式响应
|
||||
├── storage/
|
||||
@@ -694,8 +781,6 @@ xlgo/
|
||||
│ ├── validator.go # 请求验证器
|
||||
│ ├── password.go # 密码强度验证
|
||||
│ └── hash.go # 密码加密
|
||||
├── wire/
|
||||
│ └── wire.go # 依赖注入
|
||||
└── ws/
|
||||
└── ws.go # WebSocket 支持
|
||||
```
|
||||
@@ -734,6 +819,16 @@ docker run -d -p 8080:8080 xlgo-app:latest
|
||||
|
||||
> 完整变更历史见 [CHANGELOG.md](./CHANGELOG.md)。
|
||||
|
||||
### v1.1.1 (2026-06-23)
|
||||
|
||||
> v1.1.0 的补丁发布:补 `ServerConfig.Host` 绑定地址、面向用户文案统一中文、修正 README 过时/错误描述(含会致启动失败的配置示例)。
|
||||
|
||||
- **ServerConfig.Host** - `server.host` 控制监听地址,空=所有接口(兼容),`127.0.0.1`=仅本机,内网 IP=绑定指定网卡
|
||||
- **文案统一中文** - recover/logger/metrics 等面向用户文案统一中文(保留协议字段名、Prometheus metric Name、MySQL 错误串匹配等英文)
|
||||
- **README 修正** - 删 wire 段、修配置示例(secret≥32 字节 + expire 改 Duration)、补 v1.1.0 新文件、重写首段介绍
|
||||
|
||||
升级:`go get github.com/EthanCodeCraft/xlgo-core@v1.1.1`(无破坏性变更)
|
||||
|
||||
### v1.1.0 (2026-06-23)
|
||||
|
||||
> 本版本定位为 **HA & Manager 化 release**:高可用与生产就绪改进 + 组件 Manager 化。含少量破坏性变更,升级前请阅读 [CHANGELOG 升级说明](./CHANGELOG.md#升级说明)。
|
||||
@@ -907,7 +1002,7 @@ response.Fail(c, "用户名格式错误")
|
||||
|
||||
#### App 启动流程
|
||||
- **轻量默认** - `xlgo.New()` 默认不再初始化 MySQL / Redis / Storage,也不注册 `/health` 与 `/swagger/*`;通过 Option 显式启用
|
||||
- **组件 Option** - 新增 `WithLogger / WithMySQL / WithRedis / WithStorage / WithWire / WithHealthRoutes / WithSwaggerRoutes / WithDefaultRoutes / WithAutoMigrate` 及对应 `WithoutXxx` 关闭项
|
||||
- **组件 Option** - 新增 `WithLogger / WithMySQL / WithRedis / WithStorage / WithHealthRoutes / WithSwaggerRoutes / WithDefaultRoutes / WithAutoMigrate` 及对应 `WithoutXxx` 关闭项(注:`WithWire` 曾在此版本新增,已于 v1.1.0 随 wire 包删除而移除)
|
||||
- **迁移控制** - 新增 `Migrator` 类型与 `WithMigrator / WithModels`,注册时自动开启 `WithAutoMigrate`,`WithoutAutoMigrate` 可显式关闭;不再强制调用空的 `database.AutoMigrate()`
|
||||
- **batteries-included** - 新增 `WithFullStack` / `NewFullStack` / `RunFullStack`,一键启用全部默认组件
|
||||
- **错误传播** - 框架初始化失败一律 `return error`,不再在框架内部直接 `Fatalf` 退出进程
|
||||
|
||||
@@ -27,7 +27,7 @@ import (
|
||||
|
||||
// Version 框架版本号。发版时只改这一处,避免版本字面量散落各处。
|
||||
// CLI(xlgo version)、脚手架生成的 go.mod 等均引用此常量。
|
||||
const Version = "1.1.0"
|
||||
const Version = "1.1.1"
|
||||
|
||||
// HealthCheckFunc 健康检查函数
|
||||
type HealthCheckFunc func(context.Context) error
|
||||
@@ -377,11 +377,11 @@ func (a *App) Init() error {
|
||||
a.healthChecks = append(a.healthChecks, router.HealthCheck{Name: "mysql", Check: func(ctx context.Context) error {
|
||||
// 优先读探活缓存标记(#21),避免每次探针都同步 ping
|
||||
if !database.IsDBHealthy() {
|
||||
return errors.New("mysql master unhealthy (probe)")
|
||||
return errors.New("mysql 主库探活不健康")
|
||||
}
|
||||
status := database.HealthCheck()
|
||||
if !status["master"] {
|
||||
return errors.New("mysql master unavailable")
|
||||
return errors.New("mysql 主库不可用")
|
||||
}
|
||||
return nil
|
||||
}})
|
||||
@@ -537,7 +537,9 @@ func (a *App) StartServer() error {
|
||||
if useUnix {
|
||||
a.server.Addr = srvCfg.UnixSocket
|
||||
} else {
|
||||
a.server.Addr = fmt.Sprintf(":%d", srvCfg.Port)
|
||||
// Host 为空时监听所有接口(":port");设值时绑定指定地址("host:port"),
|
||||
// 用于仅本机(127.0.0.1)或绑定内网网卡的场景
|
||||
a.server.Addr = fmt.Sprintf("%s:%d", srvCfg.Host, srvCfg.Port)
|
||||
}
|
||||
|
||||
// OnStart hooks:监听端口前
|
||||
@@ -553,8 +555,10 @@ func (a *App) StartServer() error {
|
||||
go func() {
|
||||
if useUnix {
|
||||
logger.Infof("服务器启动,监听 unix socket %s", srvCfg.UnixSocket)
|
||||
} else if srvCfg.Host != "" {
|
||||
logger.Infof("服务器启动,监听 %s:%d", srvCfg.Host, srvCfg.Port)
|
||||
} else {
|
||||
logger.Infof("服务器启动,监听端口 %d", srvCfg.Port)
|
||||
logger.Infof("服务器启动,监听端口 %d(所有接口)", srvCfg.Port)
|
||||
}
|
||||
var err error
|
||||
if srvCfg.TLS.Enabled {
|
||||
|
||||
@@ -77,6 +77,7 @@ func registerRoutes(r *gin.RouterGroup) {
|
||||
base_url: "http://localhost:8080"
|
||||
|
||||
server:
|
||||
host: "" # 绑定地址,空=监听所有接口;127.0.0.1=仅本机;内网IP=绑定指定网卡
|
||||
port: 8080
|
||||
mode: development # development 或 production
|
||||
read_timeout: 15s # 读超时
|
||||
@@ -247,6 +248,7 @@ func registerRoutes(r *gin.RouterGroup) {
|
||||
base_url: "http://localhost:8080"
|
||||
|
||||
server:
|
||||
host: "" # 绑定地址,空=监听所有接口;127.0.0.1=仅本机
|
||||
port: 8080
|
||||
mode: development
|
||||
read_timeout: 15s
|
||||
|
||||
@@ -91,6 +91,7 @@ type TLSConfig struct {
|
||||
|
||||
// ServerConfig 服务配置
|
||||
type ServerConfig struct {
|
||||
Host string `mapstructure:"host"` // 绑定地址,空=监听所有接口(0.0.0.0);"127.0.0.1"=仅本机;内网IP=绑定指定网卡
|
||||
Port int `mapstructure:"port"`
|
||||
Mode string `mapstructure:"mode"` // development 或 production
|
||||
ReadTimeout time.Duration `mapstructure:"read_timeout"` // 读超时,如 "15s"
|
||||
|
||||
+1
-1
@@ -309,7 +309,7 @@ func (m *Manager) Close() error {
|
||||
// HealthCheck 健康检查,主库不可达时返回错误
|
||||
func (m *Manager) HealthCheck(ctx context.Context) error {
|
||||
if m.master == nil {
|
||||
return errors.New("database master not initialized")
|
||||
return errors.New("数据库主库未初始化")
|
||||
}
|
||||
sqlDB, err := m.master.DB()
|
||||
if err != nil {
|
||||
|
||||
@@ -4,6 +4,7 @@ app:
|
||||
debug: true
|
||||
|
||||
server:
|
||||
host: "" # 绑定地址,空=监听所有接口;127.0.0.1=仅本机
|
||||
port: 8082
|
||||
mode: development
|
||||
read_timeout: 15s
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@ func SetDefaultLogManager(m *LogManager) {
|
||||
// 三份,磁盘占用翻倍且分流形同虚设。新实现通用 Logger 只走独立的 app.log。
|
||||
func (m *LogManager) Init(cfg *config.Config) error {
|
||||
if cfg == nil {
|
||||
return errors.New("logger: config is nil")
|
||||
return errors.New("logger: 配置为空")
|
||||
}
|
||||
|
||||
// 确保日志目录存在
|
||||
|
||||
@@ -124,13 +124,13 @@ func LoggerWithConfig(cfg LoggerConfig) gin.HandlerFunc {
|
||||
if latency > cfg.SlowRequestThreshold {
|
||||
// 慢请求警告
|
||||
fields = append(fields, zap.Bool("slow_request", true))
|
||||
logger.APILog().Warn("Slow API Request", fields...)
|
||||
logger.APILog().Warn("慢请求", fields...)
|
||||
} else if status >= 500 {
|
||||
logger.APILog().Error("API Request Error", fields...)
|
||||
logger.APILog().Error("请求错误", fields...)
|
||||
} else if status >= 400 {
|
||||
logger.APILog().Warn("API Request Client Error", fields...)
|
||||
logger.APILog().Warn("客户端请求错误", fields...)
|
||||
} else {
|
||||
logger.APILog().Info("API Request", fields...)
|
||||
logger.APILog().Info("API 请求", fields...)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -232,7 +232,7 @@ func LoggerMinimal() gin.HandlerFunc {
|
||||
start := time.Now()
|
||||
c.Next()
|
||||
|
||||
logger.APILog().Info("Request",
|
||||
logger.APILog().Info("请求",
|
||||
zap.Int("status", c.Writer.Status()),
|
||||
zap.String("method", c.Request.Method),
|
||||
zap.String("path", path),
|
||||
|
||||
@@ -18,7 +18,7 @@ var (
|
||||
httpRequestsTotal = promauto.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "http_requests_total",
|
||||
Help: "Total number of HTTP requests.",
|
||||
Help: "HTTP 请求总数。",
|
||||
},
|
||||
[]string{"method", "route", "status"},
|
||||
)
|
||||
@@ -26,7 +26,7 @@ var (
|
||||
httpRequestDuration = promauto.NewHistogramVec(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "http_request_duration_seconds",
|
||||
Help: "HTTP request latency in seconds.",
|
||||
Help: "HTTP 请求耗时(秒)。",
|
||||
Buckets: prometheus.DefBuckets,
|
||||
},
|
||||
[]string{"method", "route"},
|
||||
@@ -35,7 +35,7 @@ var (
|
||||
httpRequestsInFlight = promauto.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "http_requests_in_flight",
|
||||
Help: "Current number of in-flight HTTP requests.",
|
||||
Help: "正在处理的 HTTP 请求数。",
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
@@ -20,7 +20,7 @@ func Recover() gin.HandlerFunc {
|
||||
requestID := GetRequestID(c)
|
||||
|
||||
// 记录错误日志
|
||||
logger.Error("Panic recovered",
|
||||
logger.Error("panic 已恢复",
|
||||
zap.String("request_id", requestID),
|
||||
zap.String("error", fmt.Sprintf("%v", err)),
|
||||
zap.String("path", c.Request.URL.Path),
|
||||
@@ -45,7 +45,7 @@ func RecoverWithDetail() gin.HandlerFunc {
|
||||
if err := recover(); err != nil {
|
||||
requestID := GetRequestID(c)
|
||||
|
||||
logger.Error("Panic recovered",
|
||||
logger.Error("panic 已恢复",
|
||||
zap.String("request_id", requestID),
|
||||
zap.String("error", fmt.Sprintf("%v", err)),
|
||||
zap.String("path", c.Request.URL.Path),
|
||||
@@ -54,7 +54,7 @@ func RecoverWithDetail() gin.HandlerFunc {
|
||||
)
|
||||
|
||||
// 开发环境返回详细错误
|
||||
response.FailWithCode(c, response.CodeServerError, fmt.Sprintf("Panic: %v", err))
|
||||
response.FailWithCode(c, response.CodeServerError, fmt.Sprintf("服务器内部错误: %v", err))
|
||||
c.AbortWithStatus(http.StatusInternalServerError)
|
||||
}
|
||||
}()
|
||||
|
||||
Reference in New Issue
Block a user