Go logging struct 实例化实用方法的 Goroutine 线程安全

标签 go

我正在使用一个新的 go 服务,我有一个 SetupLogger 实用函数,它创建一个新的 go-kit 日志结构实例 log.Logger

从在单独的 go-routines 中处理请求的代码调用此方法是否安全?

package utils

import (
    "fmt"
    "github.com/go-kit/kit/log"
    "io"
    "os"
    "path/filepath"
)

// If the environment-specified directory for writing log files exists, open the existing log file
// if it already exists or create a log file if no log file exists.
// If the environment-specified directory for writing log files does not exist, configure the logger
// to log to process stdout.
// Returns an instance of go-kit logger
func SetupLogger() log.Logger {
    var logWriter io.Writer
    var err error

    LOG_FILE_DIR := os.Getenv("CRAFT_API_LOG_FILE_DIR")
    LOG_FILE_NAME := os.Getenv("CRAFT_API_LOG_FILE_NAME")

    fullLogFilePath := filepath.Join(
        LOG_FILE_DIR,
        LOG_FILE_NAME,
    )

    if dirExists, _ := Exists(&ExistsOsCheckerStruct{}, LOG_FILE_DIR); dirExists {
        if logFileExists, _ := Exists(&ExistsOsCheckerStruct{}, fullLogFilePath); !logFileExists {
            os.Create(fullLogFilePath)
        }
        logWriter, err = os.OpenFile(fullLogFilePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
        if err != nil {
            fmt.Println("Could not open log file. ", err)
        }
    } else {
        logWriter = os.Stdout
    }

    return log.NewContext(log.NewJSONLogger(logWriter)).With(
        "timestamp", log.DefaultTimestampUTC,
        "caller", log.DefaultCaller,
    )
}

最佳答案

第一个建议:使用-race 标志go buildgo test。如果您有竞争条件,它几乎总能告诉您。尽管在这种情况下可能不会,因为您最终可能会同时调用 os.Create()os.OpenFile()

因此,第二个建议是尽可能避免“如果它存在/匹配/具有权限然后打开/删除/随便”模式。

该模式会导致 TOCTTOU(检查时间到使用时间)错误,这通常是一个安全错误,至少会导致数据丢失。

为了避免它,要么将检查和使用包装到同一个互斥锁中,要么使用原子操作,例如创建文件的 OpenFile 调用,或者如果文件已经存在则返回错误(尽管是技术性的,它被锁定在操作系统中内核。就像原子 CPU 操作如何锁定在硬件总线中一样。)。

在你这里的情况下,我不太确定为什么你有两个 Open 调用,因为它看起来只需要一个就可以完成这项工作。

关于Go logging struct 实例化实用方法的 Goroutine 线程安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36458566/

相关文章:

golang 去获取无法识别的导入路径

进行基准测试不要只测量循环?

reactjs - 我需要解决 golang 服务器上的 websockets 问题

将int转换为byte

XML Marshal 在此 Go 示例中不起作用

go - 解析 msgpack 编码单个 slice 的 msgpack 编码 slice 时为空 slice

git - 为什么 'go get' 即使配置了 ssh 也要使用 https?

algorithm - 从N个元素的 slice 生成K个元素的算法

rest - 使用类型嵌入访问特定字段?

去 float 零除法编译器错误