从本地包中共享对象

时间:2017-12-10 08:46:35

标签: go

我是Go的新手,我已经创建了一个按预期工作的应用程序。

我的申请结构如下:

myproj
   Gopkg.toml
   Gopkg.lock
   src
      server
         main.go
      utils
          file1.go
          logger.go
      handler
          handler1.go
          handler2.go

现在在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()

} 

一切都正常工作

现在我想在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") 
}

虽然这有效,但我已经创建了两个记录器实例,首先 main第二 handler1 1}}我不确定是最好的

  

我的问题是:

  1. 我想在logger类/模块中重用handler,在Go中更好的方法吗?
  2. 这是差异包(在我的本地项目中)并且我不确定如果我不能重复使用相同的记录器对象 main方法,这是正确的方法......

    1. (更低的prio问题)我的项目结构是否适合Go?我使用this作为参考,类似于...... also this,这有点不同

2 个答案:

答案 0 :(得分:4)

如果你想在你的项目中共享你的记录器实例,一种方法是将它作为一个全局变量从你的utils包中导出,正如Armin在他的回答中所建议的那样:

package utils

...

var Logger *logrus.Logger

func init() {
    Logger = InitLogs()
}

我敢打赌,您可以通过将其更改为InitLogs()而无需导出initLogs()

然后,在代码的其他地方,您可以导入utils并使用该记录器实例:

import "utils"

...
func something() {
    utils.Logger.Info("Hi")
}

或者,如果将所有配置保存在一个位置是有意义的,则可以将记录器指针声明为config结构的字段,并将其与其余程序配置一起初始化(如果有的话)。 / p>

例如,假设您的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")
}

与此同时,您可以在其他任何地方使用它,例如在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")
}

如果您发现最终需要配置许多全局内容,例如需要配置的Logger,则配置结构是IMO的可扩展方法。作为一个额外的好处,使用配置类型使得在单元测试中进行依赖注入比直接使用全局变量更容易。

另一方面,如果你只需要担心一个全局Logger,那么config结构可能有点过分,特别是如果在设计测试时你不需要检测它。根据您的具体情况,这是一个主观的呼吁。

回答你的第二个问题......

项目布局

如果/server的主程序包包含命令,请将其移至cmd/server下。

此外,您目前拥有它的方式,其他人依赖您的项目会有点混乱。由于您的存储库似乎从src/开始,以下是其他人尝试导入您的utils包时的情况:

文件结构:

 <top of someone else's GOPATH>/
   src/
     myproject/src/utils/
       ...

要导入:

 import "myproject/src/utils"

...实际上,既然您现在在代码中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

这会使您的软件包可以导入给您和其他人,例如:

import "github.com/you/myproject/utils"

此外,此项目结构允许其他人将您的项目包含在他们的$ GOPATH或vendor/内。

答案 1 :(得分:1)

您似乎想要使用xxx中的确切记录器。您应该只导出它并在其他包中使用它:

main.go

server/main.go

var Logger *logrus.Logger // Notice capital L func main() { Logger = utils.InitLogs() // Init logger once ... }

handler/handler1.go

您的项目结构不标准。请参阅this