Vla*_*nko 3 go deferred-execution
当尝试将日志设置代码移动到单独的函数时,我遇到无法从main函数中隐藏目标文件对象.在下面的INCORRECT简化示例中,尝试通过单个函数调用设置日志写入Stderr和文件:
package main
import (
"io"
"log"
"os"
)
func SetupLogging() {
logFile, err := os.OpenFile("test.log", os.O_APPEND|os.O_CREATE, 0666)
if err != nil {
log.Panicln(err)
}
defer logFile.Close()
log.SetOutput(io.MultiWriter(os.Stderr, logFile))
}
func main() {
SetupLogging()
log.Println("Test message")
}
Run Code Online (Sandbox Code Playgroud)
显然是不起作用因为defer在SetupLogging函数结束时关闭日志文件.
下面的一个工作示例添加了额外的代码,如果在较大的应用程序中重复作为模式,IMHO会失去一些清晰度:
package main
import (
"io"
"log"
"os"
)
func SetupLogging() *os.File {
logFile, err := os.OpenFile("test.log", os.O_APPEND|os.O_CREATE, 0666)
if err != nil {
log.Panicln(err)
}
log.SetOutput(io.MultiWriter(os.Stderr, logFile))
return logFile
}
func main() {
logf := SetupLogging()
defer logf.Close()
log.Println("Test message")
}
Run Code Online (Sandbox Code Playgroud)
有没有不同的方法将打开文件管理完全封装到一个函数中,但仍然很好地释放句柄?
我现在已经成功地在多个项目中使用了以下方法大约一年.我们的想法是从设置调用中返回一个函数.结果函数包含销毁逻辑.这是一个例子:
package main
import (
"fmt"
"io"
"log"
"os"
)
func LogSetupAndDestruct() func() {
logFile, err := os.OpenFile("test.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
if err != nil {
log.Panicln(err)
}
log.SetOutput(io.MultiWriter(os.Stderr, logFile))
return func() {
e := logFile.Close()
if e != nil {
fmt.Fprintf(os.Stderr, "Problem closing the log file: %s\n", e)
}
}
}
func main() {
defer LogSetupAndDestruct()()
log.Println("Test message")
}
Run Code Online (Sandbox Code Playgroud)
它正在使用一个关闭清理逻辑的闭包.
使用这种方法的一个更精细的公共示例是在Viper代码中:这是从测试初始化器返回的,这里它用于封装清理逻辑和对象