为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
一只甜甜圈 2021-08-10 15:35:37
当尝试将日志设置代码移动到单独的函数中时,我无法从main函数中隐藏目标文件对象。在以下INCORRECT简化示例中,尝试通过单个函数调用将日志写入 Stderr 和文件:package mainimport (    "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 mainimport (    "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")}有没有一种不同的方法可以将打开的文件管理完全封装到一个函数中,但仍然可以很好地释放句柄?
查看完整描述

3 回答

?
波斯汪

TA贡献1811条经验 获得超4个赞

这样做的正确方法是将 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))

}


查看完整回答
反对 回复 2021-08-10
?
皈依舞

TA贡献1851条经验 获得超3个赞

我现在已经在多个项目中成功使用了以下方法大约一年。这个想法是从设置调用返回一个函数。结果函数包含销毁逻辑。下面是一个例子:


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

}

它在被延迟的清理逻辑周围使用了一个闭包。


查看完整回答
反对 回复 2021-08-10
  • 3 回答
  • 0 关注
  • 236 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信