跳转到主内容
趣航编程网 - 趣学编程,启航技术之路!

Golang如何把日志写到文件_Golang日志文件教程【秒懂】

Go log包默认只输出到stderr,需用os.OpenFile创建*os.File(实现io.Writer)传给log.SetOutput;并发写安全但格式易乱;需手动flush或用bufio.NewWriter;长期运行需日志轮转等高级功能。 Go 标准库的
log
包默认只输出到 stderr,不支持直接写文件——必须自己包装
os.File
作为
io.Writer
传进去。 log.SetOutput 需要传 io.Writer,不是文件路径 很多人卡在第一步:直接把字符串路径(比如
"app.log"
)塞给
log.SetOutput
,结果 panic:
cannot use "app.log" (type string) as type io.Writer
。这是因为
SetOutput
接收的是接口,不是路径。 先用
os.OpenFile
打开或创建文件,返回
*os.File
(它实现了
io.Writer
) 注意打开模式:追加日志用
os.O_APPEND | os.O_CREATE | os.O_WRONLY
,覆盖用
os.O_TRUNC
别忘了检查
err
,文件目录不存在时会失败,
os.MkdirAll
要自己兜底 示例:
file, err := os.OpenFile("logs/app.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if err != nil { log.Fatal(err) } log.SetOutput(file)
多 goroutine 写同一个文件是安全的,但格式容易乱
*os.File.Write
是线程安全的,Go 运行时内部加了锁,所以多个
log.Print
并发调用不会导致 panic 或数据损坏。但问题出在「换行」和「时间戳」上: 每条日志是原子写入,但
log.Printf("a"); log.Printf("b")
可能被调度成
a\nb\n
ab\n\n
(如果底层 buffer 没 flush) 标准
log
Flags
(如
log.Ltime | log.Lshortfile
)在并发下仍可靠,但自定义前缀(比如手动拼接时间)容易错位 如果需要结构化日志(JSON)、轮转、压缩,别硬刚标准库——直接上
zap
zerolog
,它们原生支持文件写入和并发安全格式控制 log.Println 写文件后看不到实时内容?检查是否 flush 日志“写进去了但文件里没更新”,大概率是缓冲区没刷出。标准
log
默认不自动 flush,尤其用
os.OpenFile
时: 立即学习 “ go语言免费学习笔记(深入) ”;
log
本身没有
Flush()
方法,它的输出目标(
*os.File
)才有 可以定期调用
file.Sync()
强制落盘(适合关键错误日志),但频繁调用影响性能 更稳妥的做法:用
bufio.NewWriter
包一层,自己控制
Flush()
时机;或者改用带缓冲策略的日志库(如
lumberjack
+
log
组合) 调试时临时加
file.Sync()
看效果,上线前评估 I/O 压力 真正麻烦的不是“怎么写进去”,而是“怎么不让日志把磁盘打满”“怎么查昨天的 error”“怎么避免 panic 时最后一行日志丢失”——这些得靠轮转、异步写入、panic hook 配合,不是
SetOutput
一行代码能解决的。

相关文章