在 golang 中封装日志设置的正确模式

当尝试将日志设置代码移动到单独的函数中时,我无法从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")

}

显然是行不通的,因为defer在SetupLogging函数结束时关闭了日志文件。


下面的一个工作示例添加了额外的代码,恕我直言,如果在更大的应用程序中作为模式重复,则会失去一些清晰度:


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")

}

有没有一种不同的方法可以将打开的文件管理完全封装到一个函数中,但仍然可以很好地释放句柄?


一只甜甜圈
浏览 237回答 3
3回答

波斯汪

这样做的正确方法是将 main 中的句柄传递给SetupLogging:func SetupLogging(lf *os.File) {    log.SetOutput(io.MultiWriter(os.Stderr, logFile))    log.Println("Started")}func main() {    logFile, err := os.OpenFile("test.log", os.O_APPEND|os.O_CREATE, 0666)    if err != nil {        log.Panicln(err)    }    defer logFile.Close()    SetupLogging(logFile)    log.Println("Test message")}另一种选择是使用runtime.SetFinalizer,但并不总是保证在主退出之前运行。func SetupLogging() {    logFile, err := os.OpenFile("test.log", os.O_APPEND|os.O_CREATE, 0666)    if err != nil {        log.Panicln(err)    }    runtime.SetFinalizer(logFile, func(h *os.File) {        h.Close()    })    log.SetOutput(io.MultiWriter(os.Stderr, logFile))}

皈依舞

我现在已经在多个项目中成功使用了以下方法大约一年。这个想法是从设置调用返回一个函数。结果函数包含销毁逻辑。下面是一个例子:package mainimport (    "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")}它在被延迟的清理逻辑周围使用了一个闭包。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go