Golang包中正确的日志记录实现

时间:2020-07-09 04:16:09

标签: go logging packaging software-design

我有一个小的Golang package,可以完成一些工作。这项工作假设会产生大量错误,这是可以的。当前,所有错误都将被忽略。是的,它看起来可能很奇怪,但是请访问链接并检查包装的主要用途。 我想扩展程序包的功能,并提供查看运行时发生的错误的功能。但是由于缺乏软件设计技能,我有一些问题没有答案。

起初,我想使用现有的日志记录(zerolog,zap或其他方法)在程序包内部实现日志记录。但是,对于打包用户来说可以吗?因为他们可能想要使用其他日志记录包,并希望修改输出格式。 也许可以为用户提供一种注入自己的日志记录的方法?

我希望能够提供一种易于配置的日志记录方式,可以根据用户需求打开或关闭它。

2 个答案:

答案 0 :(得分:2)

有些go lib这样使用日志记录

在您的速度中确定记录器界面

type Yourlogging interface{
      Errorf(...)
      Warningf(...)
      Infof(...)
      Debugf(...)
}

并为此接口定义一个变量

  var mylogger Yourlogging
  func SetLogger(l yourlogging)error{
       mylogger = l
  }

在您的函数中,您可以调用它们进行记录

  mylogger.Infof(..)

  mylogger.Errorf(...)

您不需要实现该接口,但是可以使用他们来实现此接口

 for example:
     SetLogger(os.Stdout)    //logging output to stdout
     SetLogger(logrus.New()) // logging output to logrus  (github.com/sirupsen/logrus)
  

答案 1 :(得分:1)

在 Go 中,您会看到一些库实现了日志接口,就像其他答案所建议的那样。但是,如果您以不同的方式构建应用程序,就可以完全避免需要记录包的情况,例如。

例如,在您链接的示例应用程序中,您的主应用程序运行时调用 idleexacts.Run(),它启动此函数。

// startLoop starts workload using passed settings and database connection.
func startLoop(ctx context.Context, log log.Logger, pool db.DB, tables []string, jobs uint16, minTime, maxTime time.Duration) error {
    rand.Seed(time.Now().UnixNano())

    // Increment maxTime up to 1 due to rand.Int63n() never return max value.
    maxTime++

    // While running, keep required number of workers using channel.
    // Run new workers only until there is any free slot.
    guard := make(chan struct{}, jobs)
    for {
        select {
        // Run workers only when it's possible to write into channel (channel is limited by number of jobs).
        case guard <- struct{}{}:
            go func() {
                table := selectRandomTable(tables)
                naptime := time.Duration(rand.Int63n(maxTime.Nanoseconds()-minTime.Nanoseconds()) + minTime.Nanoseconds())

                err := startSingleIdleXact(ctx, pool, table, naptime)
                if err != nil {
                    log.Warnf("start idle xact failed: %s", err)
                }

                // When worker finishes, read from the channel to allow starting another worker.
                <-guard
            }()
        case <-ctx.Done():

            return nil
        }
    }
}

这里的问题是您的逻辑的所有编排都发生在您的包内。相反,此循环应在您的主应用程序中运行,并且此程序包应为用户提供简单的操作,例如 selectRandomTable()createTempTable()

如果代码编排在您的主应用程序中,并且程序包仅提供简单的操作。将错误作为函数调用的一部分返回给用户会容易得多。

它还可以让其他人更轻松地重用您的包,因为它们具有简单的操作,并且允许用户以您不希望的其他方式使用它们。