在Golang包中正确地实现日志记录

3
我有一个小的Golang ,它做了一些工作。这项工作可能会产生大量错误,这是可以接受的。目前所有的错误都被忽略了。是的,这看起来很奇怪,但请访问链接并检查包的主要目的。
我想扩展包的功能并提供在运行时查看发生的错误的能力。但由于缺乏软件设计技能,我有一些没有答案的问题。
首先,我考虑使用现有的日志记录器(zerolog、zap或其他)。但是,这对于包的用户来说是否可以接受?因为他们可能希望使用其他日志记录包并希望修改输出格式。也许可以提供一种方法让用户注入自己的日志记录?
我希望能够提供易于配置的日志记录方式,可以根据用户的要求进行开启或关闭。
2个回答

3

有些Go语言库使用以下方式进行日志记录

在您的包中定义一个logger接口

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
在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()
如果代码编排在主应用程序中,包只提供简单动作,那么在函数调用过程中向用户返回错误将变得更加容易。
此外,这样做也会使你的包对其他人更容易重复使用,因为它们只提供了简单动作并打开了用户以其它方式使用它们的可能性,而非你所期望的方式。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接