22 KiB
22 KiB
日志系统
**本文引用的文件** - [pkg/logger/logger.go](file://pkg/logger/logger.go) - [internal/middleware/logger.go](file://internal/middleware/logger.go) - [internal/middleware/request_id.go](file://internal/middleware/request_id.go) - [internal/middleware/cache_control.go](file://internal/middleware/cache_control.go) - [cmd/server/main.go](file://cmd/server/main.go) - [internal/router/router.go](file://internal/router/router.go) - [internal/handler/device.go](file://internal/handler/device.go) - [internal/handler/model.go](file://internal/handler/model.go) - [internal/handler/brand.go](file://internal/handler/brand.go) - [internal/config/config.go](file://internal/config/config.go) - [go.mod](file://go.mod)更新摘要
变更内容
- 新增缓存控制中间件的日志集成
- 增强健康检查路由的日志优化
- 扩展启动阶段的日志记录范围
- 完善缓存预热功能的日志记录
- 更新中间件注册顺序和配置
目录
简介
本文件面向 Luxsin 应用 API 项目的日志系统,围绕基于 Zap 的结构化日志进行系统性梳理。内容覆盖日志客户端初始化流程、配置选项与输出格式、日志级别使用场景、在中间件与处理器中的使用方式、以及与配置加载、请求链路追踪的集成。特别关注新增的缓存控制中间件日志集成、健康检查路由优化和启动阶段的增强日志记录。同时给出日志聚合、监控告警与故障排查的实践建议,帮助开发者建立完善且可维护的日志体系。
项目结构
日志系统在本项目中采用分层设计:
- 初始化层:在服务启动时根据环境变量创建全局日志器。
- 中间件层:统一记录请求生命周期的关键指标,按状态码选择日志级别,新增缓存控制中间件集成。
- 处理器层:在业务逻辑中记录关键事件与错误,携带上下文信息。
- 配置层:通过环境变量控制运行模式与端口等,间接影响日志输出风格。
graph TB
subgraph "启动阶段"
MAIN["cmd/server/main.go<br/>读取配置/创建日志器<br/>缓存预热/定时任务"]
CFG["internal/config/config.go<br/>环境与端口配置"]
end
subgraph "中间件层"
REQID["internal/middleware/request_id.go<br/>生成/透传请求ID"]
LOGMW["internal/middleware/logger.go<br/>请求日志中间件<br/>健康检查优化"]
CACHE["internal/middleware/cache_control.go<br/>缓存控制中间件<br/>不同路由策略"]
ROUTER["internal/router/router.go<br/>注册中间件与路由<br/>缓存控制集成"]
end
subgraph "处理器层"
DEV["internal/handler/device.go<br/>设备上报日志"]
MODEL["internal/handler/model.go<br/>模型查询日志"]
BRAND["internal/handler/brand.go<br/>品牌查询日志"]
end
subgraph "日志库封装"
ZAP["pkg/logger/logger.go<br/>Zap配置与构建"]
end
CFG --> MAIN
MAIN --> ZAP
MAIN --> ROUTER
ROUTER --> REQID
ROUTER --> CACHE
ROUTER --> LOGMW
LOGMW --> DEV
LOGMW --> MODEL
LOGMW --> BRAND
图表来源
- cmd/server/main.go:38-140
- internal/config/config.go:24-71
- pkg/logger/logger.go:8-19
- internal/router/router.go:22-81
- internal/middleware/request_id.go:20-30
- internal/middleware/logger.go:10-52
- internal/middleware/cache_control.go:11-17
- internal/handler/device.go:27-93
- internal/handler/model.go:25-60
- internal/handler/brand.go:25-58
章节来源
- cmd/server/main.go:38-140
- internal/config/config.go:24-71
- pkg/logger/logger.go:8-19
- internal/router/router.go:22-81
- internal/middleware/request_id.go:20-30
- internal/middleware/logger.go:10-52
- internal/middleware/cache_control.go:11-17
- internal/handler/device.go:27-93
- internal/handler/model.go:25-60
- internal/handler/brand.go:25-58
核心组件
- 日志器工厂(Zap 封装):根据环境变量选择生产或开发配置,定制时间键与编码器,返回全局日志器实例。
- 请求日志中间件:在请求完成后收集状态码、方法、路径、延迟、IP、请求ID、查询串与错误信息,按状态码映射到不同日志级别,新增健康检查路由跳过功能。
- 请求ID中间件:生成唯一请求ID并在请求头中透传,便于跨服务/模块关联日志。
- 缓存控制中间件:新增为不同路由设置合适的 Cache-Control 头部,支持公共缓存、最大年龄、S-maxage 和 stale-while-revalidate 策略。
- 启动入口:加载配置、设置 Gin 模式、创建日志器、连接数据库/缓存/搜索引擎、启动缓存预热和定时任务、启动 HTTP 服务器并优雅关闭。
- 处理器层:在业务关键点记录 Info/Warn/Error 等日志,携带上下文字段,如远程IP、时间戳、错误详情等。
章节来源
- pkg/logger/logger.go:8-19
- internal/middleware/logger.go:10-52
- internal/middleware/request_id.go:20-30
- internal/middleware/cache_control.go:11-17
- cmd/server/main.go:38-140
- internal/handler/device.go:56-93
- internal/handler/model.go:42-60
- internal/handler/brand.go:39-58
架构总览
下图展示了从启动到请求处理的完整日志链路,强调日志器的创建、中间件的注入与处理器中的使用,特别标注了缓存控制中间件的集成位置。
sequenceDiagram
participant Client as "客户端"
participant Server as "HTTP服务器"
participant Router as "Gin路由"
participant ReqID as "请求ID中间件"
participant Cache as "缓存控制中间件"
participant LogMW as "请求日志中间件"
participant Handler as "业务处理器"
participant Logger as "Zap日志器"
Client->>Server : "发起HTTP请求"
Server->>Router : "进入路由"
Router->>ReqID : "生成/透传请求ID"
ReqID->>Cache : "设置缓存控制头部"
Cache->>LogMW : "继续处理"
LogMW->>Handler : "调用业务处理器"
Handler->>Logger : "记录Info/Warn/Error"
Handler-->>Client : "返回响应"
LogMW->>Logger : "记录请求日志(按状态码)"
LogMW-->>Router : "完成"
图表来源
- cmd/server/main.go:119-140
- internal/router/router.go:25-27
- internal/middleware/request_id.go:20-30
- internal/middleware/cache_control.go:11-17
- internal/middleware/logger.go:10-52
- internal/handler/device.go:56-93
详细组件分析
日志器工厂(Zap 封装)
- 功能:根据环境变量选择生产或开发配置,定制时间键与编码器,构建并返回全局日志器。
- 关键点:
- 生产环境:使用生产配置,时间键为"time",时间编码为 ISO8601。
- 开发环境:使用开发配置,级别编码为带颜色的大写形式。
- 使用方式:在启动入口调用工厂创建日志器,并在退出前同步缓冲区。
flowchart TD
Start(["函数入口"]) --> CheckEnv{"环境是否为生产?"}
CheckEnv --> |是| ProdCfg["使用生产配置<br/>设置时间键与编码器"]
CheckEnv --> |否| DevCfg["使用开发配置<br/>设置级别编码为彩色"]
ProdCfg --> Build["构建日志器"]
DevCfg --> Build
Build --> Return(["返回日志器"])
图表来源
章节来源
请求日志中间件
- 功能:在请求完成后记录关键指标,按状态码选择日志级别,新增健康检查路由跳过功能。
- 字段规范:
- 状态码、方法、路径、延迟、客户端IP、请求ID。
- 可选字段:查询串、错误信息。
- 新增优化:跳过
/api/v1/health路径的日志记录,减少健康检查产生的日志噪音。 - 级别映射:
- 5xx:Error
- 4xx:Warn
- 其他:Info
flowchart TD
Enter(["进入中间件"]) --> HealthCheck{"是否为健康检查路由?"}
HealthCheck --> |是| Skip["跳过日志记录"]
HealthCheck --> |否| Collect["收集开始时间/路径/查询串"]
Collect --> Next["调用后续处理器"]
Next --> After["计算延迟/获取状态码/提取请求ID"]
After --> HasErrors{"是否存在错误?"}
HasErrors --> |是| AddErrors["附加错误字段"]
HasErrors --> |否| SkipErrors["跳过错误字段"]
AddErrors --> Level["按状态码选择级别"]
SkipErrors --> Level
Level --> Log["记录请求日志"]
Log --> Exit(["返回响应"])
Skip --> Exit
图表来源
章节来源
请求ID中间件
- 功能:生成随机十六进制字符串作为请求ID,若请求头未提供则自动生成并透传。
- 作用:贯穿请求链路,便于聚合与关联日志。
章节来源
缓存控制中间件
- 新增功能:为不同路由设置合适的 Cache-Control 头部,支持不同的缓存策略。
- 支持的缓存策略:
- 列表类路由:
public, max-age=300, s-maxage=1800, stale-while-revalidate=60 - 曲线类路由:
public, max-age=300, s-maxage=3600, stale-while-revalidate=120 - 模型列表路由:
public, max-age=30, s-maxage=300, stale-while-revalidate=30
- 列表类路由:
- 作用:优化前端缓存策略,减少不必要的请求,提高响应速度。
章节来源
启动入口与日志集成
- 加载配置:从环境变量读取运行环境、主机、端口等。
- 设置模式:生产环境设置 Gin 为 Release 模式。
- 创建日志器:根据配置环境调用日志工厂。
- 增强功能:
- 连接外部组件:数据库、搜索引擎、缓存;连接成功后记录 Info 日志。
- 缓存预热:启动时从数据库加载数据到 Redis,避免首次访问延迟。
- 定时任务:根据配置启动设备持久化任务和分享码持久化任务。
- S3 存储配置:记录 S3 存储配置信息。
- 启动服务器:记录启动日志,捕获异常并记录 Fatal 日志。
- 优雅关闭:记录关闭与停止日志。
sequenceDiagram
participant Main as "main.go"
participant Cfg as "config.Load()"
participant Log as "logger.New()"
participant DB as "database.Open()"
participant Redis as "cache.NewClient()"
participant MS as "search.NewClient()"
participant WarmUp as "warmUpCache()"
participant Engine as "router.New()"
Main->>Cfg : "加载配置"
Cfg-->>Main : "返回配置"
Main->>Log : "创建日志器"
Log-->>Main : "返回日志器"
Main->>DB : "连接数据库"
DB-->>Main : "连接结果"
Main->>MS : "配置搜索引擎"
MS-->>Main : "配置结果"
Main->>Redis : "连接缓存"
Redis-->>Main : "连接结果"
Main->>WarmUp : "缓存预热"
WarmUp-->>Main : "预热结果"
Main->>Engine : "创建路由引擎"
Engine-->>Main : "返回引擎"
图表来源
章节来源
处理器中的日志使用
- 设备上报处理器:记录上报事件与远程IP、时间等字段;对序列化与缓存写入失败记录 Error 日志。
- 模型/品牌处理器:对数据库查询失败与响应编码失败记录 Error 日志,并返回统一错误响应。
classDiagram
class DeviceHandler {
-redis : "redis.Client"
-log : "zap.Logger"
+ReportDevInfo(c)
}
class ModelHandler {
-repo : "ModelRepository"
-log : "zap.Logger"
+GetModel(c)
}
class BrandHandler {
-repo : "BrandRepository"
-log : "zap.Logger"
+GetBrand(c)
}
class ZapLogger {
+Info(msg, fields)
+Warn(msg, fields)
+Error(msg, fields)
+Fatal(msg, fields)
}
DeviceHandler --> ZapLogger : "记录Info/Error"
ModelHandler --> ZapLogger : "记录Error"
BrandHandler --> ZapLogger : "记录Error"
图表来源
- internal/handler/device.go:15-25
- internal/handler/model.go:13-23
- internal/handler/brand.go:13-23
- pkg/logger/logger.go:8-19
章节来源
依赖关系分析
- 组件耦合:
- 路由器依赖日志器、数据库、搜索引擎、缓存客户端;通过构造函数注入,降低耦合度。
- 中间件依赖日志器;请求ID中间件独立于日志器。
- 处理器依赖日志器与数据源;通过构造函数注入。
- 外部依赖:
- Gin:Web 框架,提供中间件与路由能力。
- Zap:结构化日志库,提供高性能日志记录。
- Redis、MySQL、Meilisearch:外部服务,通过连接客户端访问。
graph LR
MAIN["cmd/server/main.go"] --> ROUTER["internal/router/router.go"]
MAIN --> ZAP["pkg/logger/logger.go"]
ROUTER --> REQID["internal/middleware/request_id.go"]
ROUTER --> CACHE["internal/middleware/cache_control.go"]
ROUTER --> LOGMW["internal/middleware/logger.go"]
ROUTER --> DEV["internal/handler/device.go"]
ROUTER --> MODEL["internal/handler/model.go"]
ROUTER --> BRAND["internal/handler/brand.go"]
DEV --> ZAP
MODEL --> ZAP
BRAND --> ZAP
图表来源
- cmd/server/main.go:109
- internal/router/router.go:22-81
- internal/middleware/request_id.go:20-30
- internal/middleware/cache_control.go:11-17
- internal/middleware/logger.go:10-52
- internal/handler/device.go:15-25
- internal/handler/model.go:13-23
- internal/handler/brand.go:13-23
- pkg/logger/logger.go:8-19
章节来源
性能与轮转配置
- 当前实现:
- 日志器在启动时创建并使用默认输出(标准输出),未显式配置文件输出与轮转策略。
- 在退出时执行同步,确保缓冲区落盘。
- 新增优化:
- 健康检查路由跳过日志记录,减少系统监控产生的日志噪音。
- 缓存预热在启动时完成,避免首次访问的性能抖动。
- 不同路由使用不同的缓存策略,优化前端缓存效率。
- 建议扩展(概念性指导):
- 文件输出与轮转:通过自定义 Zap 编码器与输出目标,结合文件轮转策略(大小/时间/数量限制)提升可维护性。
- 异步写入:启用异步日志器,减少阻塞;结合队列长度与丢弃策略平衡性能与可靠性。
- 采样与速率限制:对高频日志进行采样,避免在峰值流量下产生过多 I/O。
- 结构化字段规范化:统一字段命名与类型,便于下游检索与聚合。
最佳实践与规范
- 字段命名规范
- 使用语义明确的键名,如状态码、方法、路径、延迟、IP、请求ID、错误等。
- 时间字段建议统一为 ISO8601 或 Unix 时间戳,便于排序与解析。
- 新增:缓存相关字段如
cache_hit、cache_key等,便于缓存命中率统计。
- 上下文传递
- 通过请求ID贯穿请求链路,便于跨模块聚合日志。
- 在处理器中记录关键业务事件与错误详情,包含上下文字段。
- 新增:缓存控制策略的上下文记录,便于性能分析。
- 日志级别使用
- Info:常规业务事件、连接成功、启动/关闭等。
- Warn:客户端错误(4xx)、潜在问题但不影响功能、缓存预热失败等。
- Error:服务端错误(5xx)、数据库/缓存/序列化失败等。
- Fatal:致命错误导致进程退出,通常用于不可恢复的初始化失败。
- 新增优化:
- 健康检查路由跳过日志记录,减少系统监控噪音。
- 缓存预热阶段记录详细的预热进度和结果。
- 不同路由使用不同的缓存策略,记录相应的缓存控制信息。
- 性能考虑
- 避免在热路径上进行昂贵的字符串拼接或格式化。
- 对高频日志进行采样或降级。
- 控制日志字段数量,仅记录必要信息。
- 新增:合理使用缓存控制中间件,减少不必要的请求。
- 实践示例
- 启动阶段记录连接信息与环境配置,包括缓存预热结果。
- 中间件按状态码选择级别,统一记录请求指标,跳过健康检查。
- 处理器在错误分支记录 Error 日志并返回统一错误响应。
- 新增:缓存控制中间件记录缓存策略的应用情况。
章节来源
- internal/middleware/logger.go:12-16
- internal/middleware/cache_control.go:5-8
- internal/handler/device.go:56-93
- internal/handler/model.go:42-60
- internal/handler/brand.go:39-58
- cmd/server/main.go:143-191
故障排查与调试
- 常见问题
- 数据库连接失败:启动阶段记录 Fatal 日志,检查配置与网络连通性。
- Redis 连接失败:记录 Error 日志,确认地址、端口与认证配置。
- 新增:缓存预热失败:检查数据库连接和缓存配置,查看预热日志。
- 新增:缓存控制中间件失效:检查路由注册顺序和缓存策略配置。
- 请求日志缺失:确认中间件已注册且顺序正确。
- 请求ID未透传:检查请求头是否被上游代理或网关修改。
- 新增调试技巧:
- 切换到开发环境以获得彩色输出与更详细的级别编码,便于本地调试。
- 在关键业务点增加 Info 日志,记录输入参数与关键中间结果。
- 使用统一错误响应包装,确保错误信息一致且可检索。
- 新增:利用缓存预热日志诊断缓存性能问题。
- 新增:检查缓存控制策略是否正确应用到相应路由。
- 建议的排查步骤
- 查看启动日志,确认各组件连接成功和缓存预热结果。
- 在中间件层观察请求日志,定位异常状态码与耗时,注意健康检查路由的特殊处理。
- 在处理器层查看 Error 日志,结合请求ID定位具体请求。
- 检查下游服务(数据库/缓存/搜索引擎)的可用性与配置。
- 新增:检查缓存控制中间件的缓存策略应用情况。
章节来源
- cmd/server/main.go:58-66
- cmd/server/main.go:143-191
- internal/middleware/logger.go:12-16
- internal/middleware/cache_control.go:11-17
结论
本项目采用简洁而高效的日志体系:通过工厂封装统一创建日志器,中间件集中记录请求指标,处理器在关键节点记录业务与错误日志。最新更新增强了系统的实用性:新增缓存控制中间件的日志集成,优化健康检查路由的日志记录,扩展启动阶段的详细日志记录,包括缓存预热和定时任务。结合请求ID与结构化字段,能够有效支撑日志聚合、监控告警与故障排查。建议在生产环境中进一步引入文件输出与轮转策略、异步写入与采样机制,以满足更高的可靠性与性能要求。这些增强功能使得日志系统更加完善,能够更好地支持现代 Web 应用的监控和运维需求。