我是Go的新手,我已经创建了一个按预期工作的应用程序。
我的应用程序结构如下:
myproj
Gopkg.toml
Gopkg.lock
src
server
main.go
utils
file1.go
logger.go
handler
handler1.go
handler2.go
Run Code Online (Sandbox Code Playgroud)
现在在main.go文件中,我创建了一个如下记录器:
文件 server-> main.go
import (
"handler"
"utils"
"github.com/sirupsen/logrus"
)
var logger *logrus.Logger
fun init(){
logger = utils.InitLogs()
}
func main(){
logger.info("my message")
…
handler.run()
}
Run Code Online (Sandbox Code Playgroud)
一切工作按预期!
现在我想在handler1&2文件中使用记录器(来自本地项目中的diff包)
为此,我执行了以下步骤。在处理程序内init,记录器(与我在主文件中所做的完全一样)正在运行
文件 handler-> handler1.go
import (
"utils"
"github.com/sirupsen/logrus"
)
var logger *logrus.Logger
fun init(){
//Init the logger again
logger = utils.InitLogs()
}
func run(){
//here Im not using logger otherwise maybe I can move it as parameter…
}
func build(){
//Here Im using the logger
logger.info("Hi")
}
Run Code Online (Sandbox Code Playgroud)
虽然这是工作,但我已经创建了2种记录仪的情况下,第一对main和第二对handler1其中林不知道是最好的
我的问题是:
logger在handler类/模块内部重用,是在Go中更好的方法吗?这是diff包(在我的本地项目中),我不确定如果Im 不重复使用该main方法中的相同logger对象,那么这是正确的方法...
如果要在整个项目中共享记录器实例,一种方法是按照Armin在其回答中的建议,将其作为utils包中的全局变量导出:
package utils
...
var Logger *logrus.Logger
func init() {
Logger = InitLogs()
}
Run Code Online (Sandbox Code Playgroud)
我敢打赌,您可以将其InitLogs()更改为initLogs()
然后,在代码的其他位置,您可以导入utils并使用该记录器实例:
import "utils"
...
func something() {
utils.Logger.Info("Hi")
}
Run Code Online (Sandbox Code Playgroud)
另外,如果将所有配置都放在一个地方有意义,则可以将记录器指针声明为config结构的字段,并将其与其余程序配置一起初始化(如果有的话)。
例如,假设您的utils包裹中包含以下物品:
package utils
...
type MyAppConfig struct {
// whatever config parameters your app needs,
// like DB connections, etc.
Logger *logrus.Logger
}
// pass in whatever configuration parameters you need,
// like DB URL, etc.
func InitConfig() (*MyAppConfig, error) {
// set up other configuration
config := &MyAppConfig{
// other config
Logger: InitLogs(),
}
return config, nil
}
func (c *MyAppConfig) DoSomethingImportant() {
c.Logger.Info("Hello")
}
Run Code Online (Sandbox Code Playgroud)
同时,您可以在其他任何地方使用它,例如在CLI界面中:
package main
import "utils"
...
func main() {
// input, or CLI parameters...
// pass in other CLI parameters, if any
// (of course you'd have to change the function signature in
// the previous file above)
config, err := utils.NewConfig()
if err != nil {
// handle error
}
config.DoSomethingImportant()
// or since Logger is exported:
config.Logger.Info("hello")
}
Run Code Online (Sandbox Code Playgroud)
如果您发现需要进行很多全局配置(例如需要配置的Logger),则config结构是IMO更具扩展性的方法。另外,使用config类型可以使在单元测试中进行依赖注入比直接使用全局变量更容易。
另一方面,如果您只需要担心一个全局Logger,则config结构可能会过大,尤其是在设计测试时不需要使用该结构时。这是一个主观决定,具体取决于您的情况。
要回答第二个问题...
项目布局
如果/server有带有命令的主程序包,请将其移至下cmd/server。
另外,按照您目前的方式,其他人依赖您的项目会有些混乱。由于您的存储库似乎始于src/,因此以下是其他人尝试导入您的utils软件包时的样子:
文件结构:
<top of someone else's GOPATH>/
src/
myproject/src/utils/
...
Run Code Online (Sandbox Code Playgroud)
导入:
import "myproject/src/utils"
Run Code Online (Sandbox Code Playgroud)
...实际上,由于您import "utils"现在在代码中,因此我认为您的代码不会在其他人的程序中编译,GOPATH因为他们没有$GOPATH/src/utils。
解决方案:您的存储库不应包含src/。这个想法是,您设置了自己,$GOPATH然后在其中放入了不同的存储库/程序包。例如(假设您将代码托管在Github上):
<top of gopath>/
src/
github.com/you/myproject/ <---- your repo starts here
cmd/server/
main.go
utils
file1.go
logger.go
handler
handler1.go
handler2.go
Run Code Online (Sandbox Code Playgroud)
这样可以使您的软件包对您和其他人都可以导入,如下所示:
import "github.com/you/myproject/utils"
Run Code Online (Sandbox Code Playgroud)
同样,此项目结构允许其他人将您的项目包含在$ GOPATH内或vendor/可互换地包含在内。