3 Commits

Author SHA1 Message Date
杭州明婳科技 75756dd5fb release: v1.1.1 补丁发布
- ServerConfig.Host 绑定地址字段
- 面向用户文案统一中文
- 修正 README 过时/错误描述(含会致启动失败的配置示例)+ 重写首段介绍

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 23:19:26 +08:00
杭州明婳科技 8421e06fa8 docs: README 修正过时描述 + 重写首段介绍
修正 v1.1.0 后的过时/错误描述:
- 删除目录结构里已移除的 wire/ 段
- 快速开始配置示例:jwt.secret 补足 32 字节(否则被 Validate 拦截),
  expire 由 86400(秒,int) 改 "24h"(time.Duration),补 refresh_expire/issuer/algorithm
- server 段补 host/timeout/response_mode 字段
- v1.0.2 更新日志标注 WithWire 已于 v1.1.0 移除
- 目录结构补 v1.1.0 新文件:metrics/timeout/metrics route/validate/mode
- 框架特性段重写为三组(架构可注入/生产就绪/基础功能),补全 v1.1.0 能力
- 响应格式段补 Mode 开关(ModeBusiness/ModeREST)与 Custom API

重写首段介绍(原描述过于普通化、无辨识度):
- 加 tagline 点明核心差异:组件全部 Manager 化,简单调用与注入实例兼得
- 新增"为什么是 xlgo"段:对比一般 Gin 脚手架的包级单例痛点 + 对照代码
- 5 条差异化卖点(可注入/生产就绪内置/零 Fatal/默认轻量/可插拔方言)
- 30 秒上手极简可跑示例

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 23:13:11 +08:00
杭州明婳科技 18e4f7e891 fix: ServerConfig 加 Host 字段 + 面向用户文案统一中文
- ServerConfig 新增 Host 字段:空=监听所有接口(兼容),设值=绑定指定地址
  (127.0.0.1 仅本机 / 内网IP 绑定指定网卡),避免生产暴露 0.0.0.0
- app.go 启动地址改 host:port,日志区分"所有接口"/指定地址
- 面向用户/调用的文案统一中文:
  - middleware/recover.go: "Panic recovered"→"panic 已恢复","Panic: %v"→"服务器内部错误: %v"
  - middleware/logger.go: 5 处日志消息改中文
  - middleware/metrics.go: 3 个 Prometheus Help 改中文
  - app.go/database/manager.go/logger.go: 英文 error 改中文
- 保留英文:JSON 协议字段名、Prometheus metric Name、MySQL 错误串匹配、技术专有名词
- CLI 模板与 example 配置加 host 注释

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 23:12:40 +08:00
11 changed files with 204 additions and 42 deletions
+60 -1
View File
@@ -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
+118 -23
View File
@@ -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` 管理后台 goroutineShutdown 时 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 status401/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` 退出进程
+9 -5
View File
@@ -27,7 +27,7 @@ import (
// Version 框架版本号。发版时只改这一处,避免版本字面量散落各处。
// CLIxlgo 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 {
+2
View File
@@ -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
+1
View File
@@ -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
View File
@@ -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 {
+1
View File
@@ -4,6 +4,7 @@ app:
debug: true
server:
host: "" # 绑定地址,空=监听所有接口;127.0.0.1=仅本机
port: 8082
mode: development
read_timeout: 15s
+1 -1
View File
@@ -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: 配置为空")
}
// 确保日志目录存在
+5 -5
View File
@@ -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),
+3 -3
View File
@@ -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 请求数。",
},
)
)
+3 -3
View File
@@ -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)
}
}()