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

Go 日志结构实例化实用方法的 Goroutine 线程安全

Go 日志结构实例化实用方法的 Goroutine 线程安全

Go
哆啦的时光机 2022-01-04 09:49:10
我正在使用一个新的 go 服务,我有一个SetupLogger实用程序函数,可以创建一个 go-kit 日志记录结构的新实例log.Logger。从处理单独 go 例程中的请求的代码中调用此方法是否安全?package utilsimport (    "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 loggerfunc 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,    )}
查看完整描述

2 回答

?
人到中年有点甜

TA贡献1895条经验 获得超7个赞

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

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

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

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

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


查看完整回答
反对 回复 2022-01-04
?
眼眸繁星

TA贡献1873条经验 获得超9个赞

由于您对 Logger 的设置只涉及库实例化,如果它不存在则创建一个日志文件,打开日志文件并且不涉及写入,因此从不同的 go-routines 调用它不会有问题,因为共享数据没有得到篡改。

旁注: 设计明智(假设 Logger 正在写入同一个文件)传递 Logger 的唯一实例化实例进行日志记录,这将防止两个 go-routines 同时调用您的 setup 函数。


查看完整回答
反对 回复 2022-01-04
  • 2 回答
  • 0 关注
  • 119 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号