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

标签 go deferred-execution

当试图将日志设置代码移动到一个单独的函数中时,我遇到了无法从 main 函数中隐藏目标文件对象的问题。在下面的不正确简化示例中,尝试通过单个函数调用将日志写入 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")
}

是否有不同的方法可以将打开的文件管理完全封装到一个函数中,同时又能很好地释放句柄?

最佳答案

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

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

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

在 Viper 代码中有一个使用这种方法的更详细的公开示例:here is the return from a test initializer , 和 here it is used to encapsulate the cleanup logic and objects

关于go - 在 golang 中封装日志设置的正确模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25342806/

相关文章:

postgresql - 如何设置 pgx 以从数据库中获取 UTC 值?

c# - Linq - 找出延迟执行的最快方法是什么?

javascript - 在库加载后将 JS 排队运行的最简单方法是什么? (jQ 在页末)

go - 是否可以使用标准库在 Go 中嵌套模板?

Golang stdin 读错了德语变音符号

mongodb - 使用 Go 插入和查询 MongoDB 数据

javascript - 纯javascript中的延迟分配

jquery-deferred - jQuery - 延迟等待一组 ajax 请求以完成甚至失败

c# - Dapper 的 IEnumerable<T> 是延迟执行还是立即执行?

go - 在 go 中使用 Telnet 客户端读取数据