重要前提
安装AI Skills的关键前提是:必须科学上网,且开启TUN模式,这一点至关重要,直接决定安装能否顺利完成,在此郑重提醒三遍:科学上网,科学上网,科学上网。查看完整安装教程 →
npx skills add https://github.com/cxuu/golang-skills --skill go-logging日志是给运维人员看的,而不是开发者。每一行日志都应该有助于诊断生产环境问题。如果达不到这个目的,那就是噪音。
规范性:在新 Go 代码中使用
log/slog。
slog 是结构化、分级的,并且属于标准库(Go 1.21+)。它涵盖了绝大多数生产环境日志需求。
选择哪个日志库?
├─ 新的生产代码 → log/slog
├─ 简单的 CLI / 一次性脚本 → log (标准库)
└─ 存在可测量的性能瓶颈 → zerolog 或 zap (先进行基准测试)
除非性能分析表明 slog 在你的热点路径上成为瓶颈,否则不要引入第三方日志库。如果确实需要,请保持相同的结构化键值对风格。
在设置 slog 处理器、配置 JSON/文本输出或从 log.Printf 迁移到 slog 时,请阅读 references/LOGGING-PATTERNS.md。
规范性:始终使用键值对。切勿将值内插到消息字符串中。
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
消息是对所发生事件的静态描述。动态数据应放在键值属性中:
// 良好:静态消息,结构化字段
slog.Info("order placed", "order_id", orderID, "total", total)
// 不佳:动态数据硬编码到消息字符串中
slog.Info(fmt.Sprintf("order %d placed for $%.2f", orderID, total))
建议性:对日志属性键使用
snake_case。
键应为小写,用下划线分隔,并在整个代码库中保持一致:user_id、request_id、elapsed_ms。
对于性能关键路径,使用类型化构造函数以避免内存分配:
slog.LogAttrs(ctx, slog.LevelInfo, "request handled",
slog.String("method", r.Method),
slog.Int("status", code),
slog.Duration("elapsed", elapsed),
)
在优化日志性能或使用 Enabled() 进行预检查时,请阅读 references/LEVELS-AND-CONTEXT.md。
建议性:始终遵循这些级别语义。
| 级别 | 何时使用 | 生产环境默认值 |
|---|---|---|
| Debug | 仅供开发者使用的诊断信息,跟踪内部状态 | 禁用 |
| Info | 显著的生命周期事件:启动、关闭、配置加载 | 启用 |
| Warn | 意外但可恢复的情况:使用了已弃用的功能、重试成功 | 启用 |
| Error | 操作失败,需要运维人员关注 | 启用 |
经验法则:
如果没有人需要对其采取行动,那就不是 Error —— 使用 Warn 或 Info
如果只有在附加调试器时才有用,那就是 Debug
slog.Error 应始终包含一个 "err" 属性
slog.Error("payment failed", "err", err, "order_id", id) slog.Warn("retry succeeded", "attempt", n, "endpoint", url) slog.Info("server started", "addr", addr) slog.Debug("cache lookup", "key", key, "hit", hit)
在 Warn 和 Error 之间做选择或定义自定义详细级别时,请阅读 references/LEVELS-AND-CONTEXT.md。
建议性:从上下文中派生日志记录器,以携带请求作用域的字段。
使用中间件来丰富日志记录器,添加请求 ID、用户 ID 或跟踪 ID,然后通过上下文或作为显式参数将丰富的日志记录器传递给下游:
func middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
logger := slog.With("request_id", requestID(r))
ctx := context.WithValue(r.Context(), loggerKey, logger)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
该请求中所有后续的日志调用都会自动携带 request_id。
在实现日志记录中间件或通过上下文传递日志记录器时,请阅读 references/LOGGING-PATTERNS.md。
规范性:每个错误只处理一次 —— 要么记录它,要么返回它。
记录一个错误然后返回它,会导致重复的噪音,因为调用栈上层的调用者也会处理这个错误。
// 不佳:在这里记录,并且调用栈上层的每个调用者也会记录
if err != nil {
slog.Error("query failed", "err", err)
return fmt.Errorf("query: %w", err)
}
// 良好:包装并返回 —— 让调用者决定
if err != nil {
return fmt.Errorf("query: %w", err)
}
例外:HTTP 处理器和其他调用栈顶层的边界可以在服务器端记录详细的错误,同时向客户端返回一个经过清理的消息:
if err != nil {
slog.Error("checkout failed", "err", err, "user_id", uid)
http.Error(w, "internal error", http.StatusInternalServerError)
return
}
有关完整的一次性处理模式和错误包装指南,请参阅 go-error-handling。
规范性:切勿记录机密信息、凭据、个人身份信息或高基数无界数据。
在决定哪些数据可以安全地包含在日志属性中时,请阅读 references/LEVELS-AND-CONTEXT.md。
| 应做 | 不应做 |
|---|---|
slog.Info("msg", "key", val) | log.Printf("msg %v", val) |
| 静态消息 + 结构化字段 | 在消息中使用 fmt.Sprintf |
snake_case 键 | camelCase 或不一致的键 |
| 记录错误 OR 返回错误 | 记录错误 AND 返回同一个错误 |
| 从上下文派生日志记录器 | 每次调用都创建新的日志记录器 |
使用带有 "err" 属性的 slog.Error | 对错误使用 slog.Info |
在热点路径上预检查 Enabled() | 总是分配日志参数 |
每周安装次数
66
代码仓库
GitHub 星标数
59
首次出现
12 天前
安全审计
安装于
github-copilot62
claude-code56
opencode51
codex50
kimi-cli49
gemini-cli49
Logs are for operators , not developers. Every log line should help someone diagnose a production issue. If it doesn't serve that purpose, it's noise.
Normative : Use
log/slogfor new Go code.
slog is structured, leveled, and in the standard library (Go 1.21+). It covers the vast majority of production logging needs.
Which logger?
├─ New production code → log/slog
├─ Trivial CLI / one-off → log (standard)
└─ Measured perf bottleneck → zerolog or zap (benchmark first)
Do not introduce a third-party logging library unless profiling shows slog is a bottleneck in your hot path. When you do, keep the same structured key-value style.
Read references/LOGGING-PATTERNS.md when setting up slog handlers, configuring JSON/text output, or migrating from log.Printf to slog.
Normative : Always use key-value pairs. Never interpolate values into the message string.
The message is a static description of what happened. Dynamic data goes in key-value attributes:
// Good: static message, structured fields
slog.Info("order placed", "order_id", orderID, "total", total)
// Bad: dynamic data baked into the message string
slog.Info(fmt.Sprintf("order %d placed for $%.2f", orderID, total))
Advisory : Use
snake_casefor log attribute keys.
Keys should be lowercase, underscore-separated, and consistent across the codebase: user_id, request_id, elapsed_ms.
For performance-critical paths, use typed constructors to avoid allocations:
slog.LogAttrs(ctx, slog.LevelInfo, "request handled",
slog.String("method", r.Method),
slog.Int("status", code),
slog.Duration("elapsed", elapsed),
)
Read references/LEVELS-AND-CONTEXT.md when optimizing log performance or pre-checking with Enabled().
Advisory : Follow these level semantics consistently.
| Level | When to use | Production default |
|---|---|---|
| Debug | Developer-only diagnostics, tracing internal state | Disabled |
| Info | Notable lifecycle events: startup, shutdown, config loaded | Enabled |
| Warn | Unexpected but recoverable: deprecated feature used, retry succeeded | Enabled |
| Error | Operation failed, requires operator attention | Enabled |
Rules of thumb :
If nobody should act on it, it's not Error — use Warn or Info
If it's only useful with a debugger attached, it's Debug
slog.Error should always include an "err" attribute
slog.Error("payment failed", "err", err, "order_id", id) slog.Warn("retry succeeded", "attempt", n, "endpoint", url) slog.Info("server started", "addr", addr) slog.Debug("cache lookup", "key", key, "hit", hit)
Read references/LEVELS-AND-CONTEXT.md when choosing between Warn and Error or defining custom verbosity levels.
Advisory : Derive loggers from context to carry request-scoped fields.
Use middleware to enrich a logger with request ID, user ID, or trace ID, then pass the enriched logger downstream via context or as an explicit parameter:
func middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
logger := slog.With("request_id", requestID(r))
ctx := context.WithValue(r.Context(), loggerKey, logger)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
All subsequent log calls in that request carry request_id automatically.
Read references/LOGGING-PATTERNS.md when implementing logging middleware or passing loggers through context.
Normative : Handle each error exactly once — either log it or return it.
Logging an error and then returning it causes duplicate noise as callers up the stack also handle the error.
// Bad: logged here AND by every caller up the stack
if err != nil {
slog.Error("query failed", "err", err)
return fmt.Errorf("query: %w", err)
}
// Good: wrap and return — let the caller decide
if err != nil {
return fmt.Errorf("query: %w", err)
}
Exception : HTTP handlers and other top-of-stack boundaries may log detailed errors server-side while returning a sanitized message to the client:
if err != nil {
slog.Error("checkout failed", "err", err, "user_id", uid)
http.Error(w, "internal error", http.StatusInternalServerError)
return
}
See go-error-handling for the full handle-once pattern and error wrapping guidance.
Normative : Never log secrets, credentials, PII, or high-cardinality unbounded data.
Read references/LEVELS-AND-CONTEXT.md when deciding what data is safe to include in log attributes.
| Do | Don't |
|---|---|
slog.Info("msg", "key", val) | log.Printf("msg %v", val) |
| Static message + structured fields | fmt.Sprintf in message |
snake_case keys | camelCase or inconsistent keys |
| Log OR return errors | Log AND return the same error |
| Derive logger from context | Create a new logger per call |
Use slog.Error with "err" attr |
Weekly Installs
66
Repository
GitHub Stars
59
First Seen
12 days ago
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
github-copilot62
claude-code56
opencode51
codex50
kimi-cli49
gemini-cli49
GSAP 框架集成指南:Vue、Svelte 等框架中 GSAP 动画最佳实践
3,400 周安装
viem 集成指南:为 TypeScript/JavaScript 应用连接 EVM 区块链
442 周安装
PDF OCR文字识别工具 - 支持影印PDF和图片提取文字,本地RapidOCR与云端AI双引擎
438 周安装
Rust物联网开发指南:IoT领域约束、设计模式与Rust实现
438 周安装
Vitest 测试框架:Vite驱动的下一代JavaScript/TypeScript单元测试工具
442 周安装
上下文压缩策略:优化AI智能体对话历史管理,降低任务令牌总成本
447 周安装
OpenAI变更集验证工具 - 自动化版本管理,确保代码变更合规
62 周安装
slog.Info for errors |
Pre-check Enabled() on hot paths | Always allocate log args |