
log.Printf 为什么输出没有时间戳?
Go 标准 log 包默认不带时间戳,是因为它用的是最简配置——log.SetFlags(0) 的效果。你看到的纯文本输出,其实是 log.LstdFlags 没被启用。
- 要加时间戳,必须显式调用
log.SetFlags(log.LstdFlags)(含日期、时间、文件名和行号)或组合使用,比如log.Ldate | log.Ltime - 注意:这个设置是全局生效的,一旦在
init()或 main 开头设了,所有后续log.Print*都会受影响 - 常见错误:在某个函数里临时改 flags,但忘了恢复,导致其他包的日志格式错乱
- 如果你用的是
log.New()创建的自定义 logger,flags 要单独传给它,不会继承全局设置
如何让 log 输出到文件而不是终端?
标准 log 包本身不关心输出目标,只管写入 io.Writer。所以关键不是“怎么输出到文件”,而是“把文件句柄塞给 logger”。
- 用
os.OpenFile()打开文件时,记得加os.O_CREATE | os.O_APPEND | os.O_WRONLY,否则可能报permission denied或覆盖旧日志 - 别直接用
os.Stdout或os.Stderr做对比测试——它们是终端设备,行为和文件不同(比如缓冲策略) - 如果程序长期运行,要考虑日志轮转;标准
log不支持,得自己封装或换lumberjack这类第三方 writer - 示例:
f, _ := os.OpenFile("app.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644) log.SetOutput(f)
log.Fatal 和 panic 有什么实际区别?
表面看都终止程序,但底层行为完全不同:前者是“记录后调用 os.Exit(1)”,后者是“触发运行时 panic 机制并打印堆栈”。
-
log.Fatal("msg")等价于log.Println("msg"); os.Exit(1),不会打印 goroutine 堆栈,也不会触发defer(除非你在它前面手动写了) -
panic("msg")会打印完整调用栈,且会执行当前 goroutine 的defer,适合开发期快速暴露逻辑错误 - 线上服务慎用
log.Fatal:它会让整个进程退出,而很多服务期望的是单请求失败后继续服务 - 如果你只是想中止当前 HTTP handler,应该返回 error 或用
http.Error,而不是log.Fatal
为什么 log.Printf("%s", nil) 会 panic?
因为 log.Printf 底层调用的是 fmt.Sprintf,而 fmt 包对 nil 的 interface{} 或指针类型有严格校验——不是所有 %v 都能安全吞掉 nil。
立即学习“go语言免费学习笔记(深入)”;
- 具体错误是:
panic: runtime error: invalid memory address or nil pointer dereference,通常发生在你传了个未初始化的 struct 指针或 map - 解决办法不是加
if x != nil判断,而是统一用%v或%+v,它们对nil是安全的;%s只接受string类型,遇到nil就崩 - 更稳妥的做法是在日志前做类型断言或空值检查,尤其当变量来自外部输入(如 JSON 解析结果)时
- 示例:
log.Printf("user: %+v", user)比log.Printf("user: %s", user.Name)更健壮
nil 的盲目格式化,这几个点最容易在凌晨三点把你叫起来。










