You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

自定义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

火山引擎 最新活动