这是我第一次使用日志记录器,经过几次搜索,我最终选择了zerolog,我创建了一个简单的web服务器,它调用了一个虚拟的API端点来说明我的担忧。
GitHub Repo示例:https://github.com/BigBoulard/logger
var (
router *gin.Engine
)
func main() {
// load the env variables
conf.LoadEnv()
// GinMode is set to "debug" in the /.env file
gin.SetMode(conf.Env.GinMode)
router = gin.Default()
// creates a controller that uses an httpclient to call https://jsonplaceholder.typicode.com/todos
controller := controller.NewController(
httpclient.NewClient(),
)
router.GET("/todos", controller.GetTodos)
// run the router on host and port specified in the /.env file
err := router.Run(fmt.Sprintf("%s:%s", conf.Env.Host, conf.Env.Port))
if err != nil {
log.Fatal("application/main", err)
}
}
正如你已经注意到的,如果我在本地工作,或者如果服务器在生产环境中,这个服务器使用的环境变量需要以不同的方式加载,对吗?所以为了管理这个,我创建了一个conf包,看起来像这样。
package conf
import (
"log"
"os"
"github.com/joho/godotenv"
)
var Env = &env{}
type env struct {
AppMode string
GinMode string
Host string
Port string
}
var IsLoaded = false
func LoadEnv() {
// the httpclient and the Gin server both need the env vars
// but we don't want to load them twice
if IsLoaded {
return
}
// if not "prod"
if Env.AppMode != "prod" {
curDir, err := os.Getwd()
if err != nil {
log.Fatal(err, "conf", "LoadEnv", "error loading os.Getwd()")
}
// load the /.env file
loadErr := godotenv.Load(curDir + "/.env")
if loadErr != nil {
log.Fatal(loadErr, "conf", "LoadEnv", "can't load env file from current directory: "+curDir)
}
Env.GinMode = "debug"
} else {
Env.GinMode = "release"
}
// load the env vars
Env.AppMode = os.Getenv("APP_MODE")
Env.Host = os.Getenv("HOST")
Env.Port = os.Getenv("PORT")
IsLoaded = true
}
长话短说,我已经创建了一个日志包,我会包含在每个微服务中。这个日志包在启动时使用环境变量来确定日志级别并决定是否激活某些功能。日志包看起来像这样:
package log
var l *logger = NewLogger()
const API = "test api"
type logger struct {
logger zerolog.Logger // see https://github.com/rs/zerolog#leveled-logging
}
func NewLogger() *logger {
loadEnvFile()
var zlog zerolog.Logger
if os.Getenv("APP_ENV") == "dev" {
// setup for dev ...
} else {
// setup for prod ...
}
return &logger{
logger: zlog,
}
func Error(path string, err error) {
l.logger.
Error().
Stack().
Str("path", path).
Msg(err.Error())
}
func Fatal(path string, err error) {
l.logger.
Fatal().
Stack().
Str("path", path).
Msg(err.Error())
}
// PROBLEM: I need to duplicate loadEnvFile() from conf.load_env.go
// because conf uses log ... but conversely, log need conf cause it needs the env var
func loadEnvFile() {
curDir, err := os.Getwd()
if err != nil {
log.Fatal(err, "test api", "App", "gw - conf - LoadEnv - os.Getwd()")
}
loadErr := godotenv.Load(curDir + "/.env")
if loadErr != nil {
log.Fatal(err, "test api", "conf - LoadEnv", "godotenv.Load("+curDir+"/.env\")")
}
}
正如你所看到的,我不能使用conf包中的loadEnvFile()
,因为它会导致循环依赖,所以我想可能有一个更好的方法来实现它。
附带问题:我可以创建一个日志记录器Web服务,它将从所有其他服务接收日志消息,并将其打印到文件中,但我不确定这是否是一个好的做法。我希望能够将日志文件推到像Kibana这样的东西中,以更好地了解所有这些是如何执行的,但也许它最好每个服务都打印到标准输入中,将日志集中到一个我不知道的专用服务中。
非常感谢。
1条答案
按热度按时间n6lpvg4x1#
我只是在
main
函数中委托了日志记录器示例化,就像我们对控制器和http客户端所做的那样。你可以用最后一次提交来检查repo:https://github.com/BigBoulard/logger