Go错误无内置级别,需自定义类型或用xerrors/pkg/errors包装,结合errors.Is/As分类;日志分级应由slog.Handler等根据错误类型判断,而非错误自身携带级别字段。
Go 里没有内置的错误级别(如 ERROR/WARN/INFO)
Go 的 error 接口本身只定义了一个 Error() 方法,不携带任何级别、时间、上下文等元信息。所谓“错误级别控制”,必须由开发者自行建模——要么扩展 error 实现,要么用结构体封装,再配合判断逻辑分发处理。
常见误操作是试图给 errors.New("xxx") 或 fmt.Errorf("xxx") “打标签”或“设级别”,这在类型层面完全无效:它们返回的是基础 error,无法区分严重性。
- 真正可用的方式是自定义错误类型,例如实现
type MyError struct { Level string; Msg string; Err error } - 更推荐使用已验证的库如
github.com/pkg/errors(虽已归档,但语义清晰)或golang.org/x/xerrors(官方轻量方案),它们支持带堆栈和简单分类,但依然不提供开箱即用的“级别字段” - 若需日志分级,应把错误实例传给日志器(如
log/slog),由日志器根据错误类型或包装特征决定输出级别,而非让错误自己“说它是 warn”
用 slog.With 与自定义 error 类型联动做分级处理
Go 1.21+ 的 slog 支持结构化日志,可将错误类型作为属性传入,再结合 slog.Handler 的自定义逻辑做路由。例如:
type LevelError struct {
Level string
Msg string
Err error
}
func (e *LevelError) Error() string { return e.Msg }
func (e *LevelError) Unwrap() error { return e.Err }
// 使用时:
slog.Error("db query failed", "err", &LevelError{Level: "ERROR", Msg: "timeout", Err: ctx.Err()})
关键点在于:slog 不会自动识别 LevelError.Level,你需要写一个自定义 slog.Handler,在 Handle() 方法中检查 record.Attrs() 里的 err 是否为 *LevelError,再根据其 Level 字段决定是否写入 stderr、是否上报 Sentry 等。