自定义log.Logger写入日志文件失败原因排查
解决Go语言中main()以外函数无法写入日志文件的问题
你的代码问题出在init()函数里的defer fileHandle.Close()!
defer语句的执行时机是它所在的函数返回时,而init()会在程序启动阶段只执行一次,执行完毕就返回——这意味着你的日志文件句柄在程序刚启动就被关闭了!后面调用checkDomain()的时候,Info日志器操作的是已经关闭的文件句柄,自然写不进任何内容。而你在init()里调用Println能成功,是因为那时文件句柄还没被defer关闭。
修正方案
把关闭文件句柄的defer语句移到main()函数里,同时把fileHandle设为全局变量,这样就能保证文件在整个程序运行期间保持打开,直到main结束才关闭。
修正后的完整代码:
var ( Info *log.Logger Error *log.Logger fileHandle *os.File // 全局变量,让main能访问到文件句柄 ) func init() { var err error // 打开日志文件 fileHandle, err = os.OpenFile("/var/log/checkcert", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) if err != nil { log.Fatal(err) } // 这里不要放defer,否则init结束就关文件了 // 配置日志输出 log.SetOutput(fileHandle) Info = log.New(fileHandle, "Log: ", log.Ldate|log.Ltime|log.Lshortfile) Error = log.New(fileHandle, "Error: ", log.Ldate|log.Ltime|log.Lshortfile) } func checkDomain() { Info.Println("test inside checkDomain") } func main() { defer fileHandle.Close() // 程序结束时再关闭文件 checkDomain() // 你的其他业务逻辑... }
额外说明
如果你的程序是长期运行的服务类程序,其实也可以不用手动关闭文件句柄——进程退出时操作系统会自动回收所有打开的文件描述符。但显式关闭是更好的编程习惯,尤其是对于短运行的脚本。
内容的提问来源于stack exchange,提问作者Roger Creasy




