正确做法是禁用gin.default()默认logger,自定义中间件收集结构化日志并调用sls sdk推送;需对齐sls索引字段名与类型,复用sls.client并发批量上传,panic日志应单独logstore隔离存储。

直接写入SLS需要绕过gin.Logger中间件
gin自带的Logger中间件只支持io.Writer类型输出,而阿里云日志服务(SLS)SDK要求构造PutLogsRequest并调用PutLogs方法,无法直接对接Output字段。硬塞os.Stdout再用logtail采集属于间接方案,延迟高、丢失风险大,生产环境不推荐。
正确做法是:禁用默认Logger,自己实现一个中间件,在c.Next()前后收集字段,组装成结构化日志后调用SLS SDK推送。
- 必须关闭
gin.Default()里的默认日志:r := gin.New(),而不是gin.Default() - 中间件里不要用
fmt.Printf或log.Println,避免污染标准输出 - 注意
c.Request.Body只能读一次,如需记录请求体,得提前用c.Request.Body = ioutil.NopCloser(bytes.NewReader(buf))重置
结构化日志字段要对齐SLS索引配置
SLS控制台建Logstore时,若开启了“自动提取”或配置了特定index规则,日志JSON字段名必须与之严格匹配,否则查不到数据。比如你设了status为int类型索引,但日志里传的是"status": "200"(字符串),查询就会失败。
推荐字段命名和类型参考:
-
method(string)→ HTTP方法 -
path(string)→c.Request.URL.Path -
status(int)→c.Writer.Status(),不是c.Writer.Status()返回的字符串 -
latency_ms(int64)→latency.Microseconds() / 1000 -
client_ip(string)→c.ClientIP(),注意X-Forwarded-For可能被伪造 -
user_agent(string)→c.GetHeader("User-Agent")
错误示例:"status_code": 200 → 若SLS索引定义为status,这条日志就无法被status: 200查到。
SDK并发推送需复用Client并控制goroutine数量
阿里云SLS Go SDK的sls.Client是线程安全的,但每个PutLogs调用都是一次HTTP请求。如果每条日志都单独发请求,QPS上不去还容易触发限流(默认50 QPS/Project)。
实操建议:
- 初始化一个全局
*sls.Client,复用连接池和认证信息 - 用channel + worker goroutine做简单缓冲:中间件把日志结构体发到
chan *sls.PutLogsRequest,后台固定3–5个worker消费并批量调用PutLogs - 单次
PutLogs最多带1000条日志,每条最大4MB;建议按时间窗口(如500ms)或数量阈值(如200条)触发flush - 失败时别panic,记本地error log并重试1次(SLS SDK本身有重试机制,但超时需自定义)
关键代码片段:
logChan := make(chan *sls.PutLogsRequest, 1000)
go func() {
for req := range logChan {
_, err := client.PutLogs(req)
if err != nil {
// 写本地error log,不阻塞主流程
localErrLog.Printf("sls put failed: %v", err)
}
}
}()
错误日志必须走Recovery中间件+独立SLS Project
panic类错误不能靠普通请求日志捕获,必须用Recovery中间件兜底。但别把panic日志和访问日志混进同一个Logstore——查询慢、权限难隔离、费用难分摊。
正确姿势:
- 单独建一个Logstore(如
myapp-panic),专门收panic堆栈 - 在
Recovery里构造含stacktrace、panic_msg、request_id的JSON,直接调SLS SDK推送 - 确保
debug.Stack()内容不超过4MB(SLS单条上限),超长需截断并标记"truncated": true - 不要在
Recovery里调用c.Abort()后还继续写响应体,Gin已终止写入,此时c.Writer状态不可靠
最容易被忽略的一点:SLS的topic字段最好设为"panic"或"access",后续用topic:过滤比正则快得多。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











