如何使用Golang实现错误日志记录_Golanglog记录错误信息方法

16次阅读

go 标准库 log 包需手动配置前缀、标志、文件输出及 panic 捕获才能满足生产需求,结构化日志应选用 zap 或 zerolog。

如何使用Golang实现错误日志记录_Golanglog记录错误信息方法

Go 标准库log 包本身不区分错误级别,直接用 log.printlog.printf 记录错误信息是可行的,但缺乏上下文、和结构化输出——这意味着你得自己补全这些能力,否则线上出问题时很难快速定位。

log.SetPrefixlog.SetFlags 标记错误来源

标准 log 包虽无 Errorf 方法,但可通过前缀和标志增强可读性。常见错误是只调用 log.Println,结果日志里看不出是错误、时间戳缺失、也没有文件行号。

  • log.SetPrefix("ERROR: ") 统一标记错误日志,避免靠内容关键词 grep
  • log.SetFlags(log.LstdFlags | log.Lshortfile) 启用时间戳 + 文件名+行号,定位快得多
  • 不要在每条日志里手动拼 "[ERROR] " + err.Error(),前缀已承担该职责
log.SetPrefix("ERROR: ") log.SetFlags(log.LstdFlags | log.Lshortfile) log.Printf("failed to open config: %v", err)

捕获并记录 panic 堆recover + debug.PrintStack

http handler 或 goroutine 中未处理的 panic 会静默消失,仅靠 log.Printf 记录错误值根本不够。必须显式 recover 并打印完整堆栈,否则永远不知道 panic 发生在哪一行。

  • fmt.Sprintf("%+v", err) 对普通 error 没用,对 panic 无效;要用 debug.PrintStack()
  • 恢复后仍需重新 panic 或返回错误,不能吞掉异常
  • 建议封装中间件或 defer 函数,避免每个 handler 重复写
defer func() {     if r := recover(); r != nil {         log.Printf("PANIC: %v", r)         debug.PrintStack()     } }()

写入文件而非终端时注意 os.OpenFileos.O_appENDos.O_CREATE

直接用 log.SetOutput(os.Stdout) 在开发时没问题,但生产环境必须写文件。常见错误是用 os.Create 每次覆盖日志,或者忘记设置权限导致进程无法写入。

立即学习go语言免费学习笔记(深入)”;

  • 必须同时指定 os.O_APPEND | os.O_CREATE | os.O_WRONLY,缺一不可
  • 文件权限建议设为 0644(非 0600),否则运维查日志要切用户
  • 记得检查 os.OpenFile 返回的 error,空指针 panic 比日志丢失更难排查
f, err := os.OpenFile("app.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if err != nil {     log.Fatalf("failed to open log file: %v", err) } log.SetOutput(f)

需要结构化日志?别硬改标准库,换 zapzerolog

当你要加 trace_id、字段过滤、jsON 输出、日志采样或对接 Loki/Splunk 时,标准 log 包的字符串拼接方式会迅速失控。强行给 log.Printf 包一层 mapjson,性能差、易出错、且无法复用上下文。

  • zap.Logger.With(zap.String("path", r.URL.Path)) 可复用,log.Printf 每次都要重传
  • zerolog.New(os.Stderr).With().timestamp().Logger() 默认带时间,无需手动设 flags
  • 注意 zapSugar 模式适合快速迁移,但结构化字段要用 Info()String() 等方法
logger := zerolog.New(os.Stderr).With().Timestamp().Logger() logger.Error().Err(err).Str("action", "save_user").Int64("user_id", id).Msg("failed")

真正难的不是“怎么记下错误”,而是确保错误发生时,那条日志里有足够线索让一个人在凌晨三点不用翻十页代码就能判断是网络超时、数据库约束冲突,还是上游返回了非法 JSON。前缀、堆栈、文件行号、结构化字段——每个都是省下五分钟的关键,而不是锦上添花的配置项。

text=ZqhQzanResources