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