Introduction

零位记录字段

我在我的Golang项目中用了github.com/rs/zerolog.

我知道我可以使用如下代码将字段添加到输出中:

package main

import (
    "os"

    "github.com/rs/zerolog"
)

func main() {
    logger := zerolog.New(os.Stderr).With().Timestamp().Logger()
    logger.Int("myIntField", 42)
    logger.Info("a regular log output") // this log entry will also contain the integer field `myIntField`
}

但我想要的是,在第logger.Info("a regular log output")行的运行时,可以计算出字段myIntField的值.

设置

我有一个带有GO- routine 的生产者/消费者设置(例如,参见https://goplay.tools/snippet/hkoMAwqKcwj),我有两个整数,它们自动倒计时仍在运行的消费者和生产者GO- routine 的数量.在拆卸消费者和生产者之后,我希望在运行时显示这些数字.

以下是使用LOG而不是ZERLOG时的代码:

package main

import (
    "fmt"
    "log"
    "os"
    "sync"
    "sync/atomic"
)

func main() {
    numProducers := int32(3)
    numConsumers := int32(3)

    producersRunning := numProducers
    consumersRunning := numConsumers

    var wg sync.WaitGroup

    l := log.New(os.Stderr, "", 0)

    // producers
    for i := int32(0); i < numProducers; i++ {
        idx := i
        wg.Add(1)
        go (func() {
            // producer tear down
            defer func() {
                atomic.AddInt32(&producersRunning, -1)
                l.Printf("producer-%3d . producersRunning: %3d\n", idx, producersRunning)
                wg.Done()
            }()

            // this is where the actual producer works is happening
        })()
    }

    // consumers
    for i := int32(0); i < numConsumers; i++ {
        idx := i
        wg.Add(1)
        go (func() {
            // consumer tear down
            defer func() {
                atomic.AddInt32(&consumersRunning, -1)
                l.Printf("consumer-%3d . consumersRunning: %3d\n", idx, consumersRunning)
                wg.Done()
            }()

            // this is where the actual consumer works is happening
        })()
    }

    fmt.Println("waiting")
    wg.Wait()
}

它输出的内容如下所示:

waiting
producer-  1 . producersRunning:   2
producer-  0 . producersRunning:   1
consumer-  1 . consumersRunning:   2
producer-  2 . producersRunning:   0
consumer-  2 . consumersRunning:   1
consumer-  0 . consumersRunning:   0

消费者/生产者的记录器

使用ZERLOG,您可以创建记录器并将其传递给每个Go-routle:

logger := zerolog.New(os.Stderr)

go myConsumer(logger.With().Str("is", "consumer").Logger())
go myProducer(logger.With().Str("is", "producer").Logger())

然后,只需查看每个日志(log)行中的is字段,就可以很容易地在日志(log)中找出消息是来自消费者还是生产者.

但是,如果我希望始终在每个日志(log)行中打印当前活动的消费者/生产者的数量,该怎么办?您可能会忍不住想做这样的事情:

go myConsumer(logger.With().Str("is", "consumer").Int("consumersRunning", consumersRunning).Logger())
go myProducer(logger.With().Str("is", "producer").Int("producersRunning", producersRunning).Logger())

但当然,这只会在创建Go程序时打印consumersRunningproducersRunning的瞬时值.相反,我希望日志(log)输出反映日志(log)输出时的值.

摘要

我希望我的问题是清楚的.我不确定它是否违背了零度的概念,但像这样的函数

func (e *Event) DeferredInt(key string, i func()int) *Event

如果它存在的话,可能会奏效.

有没有其他方法可以达到同样的效果?

潜在的解决方法

我的意思是,一种方法是将logger变量替换为如下所示的函数调用:

logFunc := func() zerolog.Logger {
  return logger.With().Int("runningConcumers", runningConsumers).Logger()
}

然后可以用logFunc().Msg("hello")创建一个日志(log)条目.这推迟了runningConsumers的计算,但也 for each 日志(log)条目创建了一个记录器,这感觉有点过头了.

到目前为止,我希望我没有把你搞糊涂.

推荐答案

你可以加hook.将 for each 日志(log)记录事件判断挂钩

https://go.dev/play/p/Q7doafJGaeE

package main

import (
    "os"

    "github.com/rs/zerolog"
)

type IntHook struct {
    Count int
}

func (h *IntHook) Run(e *zerolog.Event, l zerolog.Level, msg string) {
    e.Int("count", h.Count)
    h.Count++
}

func main() {
    var intHook IntHook
    log := zerolog.New(os.Stdout).Hook(&intHook)

    log.Info().Msg("hello world")
    log.Info().Msg("hello world one more time")
}

输出为

{"level":"info","count":0,"message":"hello world"}
{"level":"info","count":1,"message":"hello world one more time"}

需要指针才能将调用之间的Count保存为Hook.Run

对你来说,HookFunc美元可能更好.它是 for each 事件调用的无状态函数.下面是为每条消息调用PRNG的函数钩子的示例:https://go.dev/play/p/xu6aXpUmE0v

package main

import (
    "math/rand"
    "os"

    "github.com/rs/zerolog"
)

func RandomHook(e *zerolog.Event, l zerolog.Level, msg string) {
    e.Int("random", rand.Intn(100))
}

func main() {
    var randomHook zerolog.HookFunc = RandomHook
    log := zerolog.New(os.Stdout).Hook(randomHook)

    log.Info().Msg("hello world")
    log.Info().Msg("hello world one more time")
}

输出

{"level":"info","random":81,"message":"hello world"}
{"level":"info","random":87,"message":"hello world one more time"}

Go相关问答推荐

无法在Macos上使用Azure Speech golang SDK

向API网关终结点发出POST请求时出现AWS Lambda With Go:";Rune me.InvalidEntrypoint";错误

一种基于时间的Golang函数节制器

链自定义GRPC客户端拦截器/DialOptions

如何描述OpenAPI规范中围棋的数据类型.JSON?

在不耗尽资源的情况下处理S3文件下载

为什么 `go mod` 占用了另一个磁盘上的空间而不是我的 GOPATH?

使用 goroutine 比较 Golang 中的两棵树是等价的

Go - 永远停止带有上下文的循环

使用goqu无法获取响应

如何忽略打印达到最大深度限制 go colly

如何解决我的 Go 聊天应用程序中 cookie 未在本地主机端口之间传输的问题?

此 Golang 程序中的同步问题

使用模拟在 golang 中测试我的界面.专门测试调用同级函数的 1 个函数

致命错误 - 所有 Goroutines 都睡着了!僵局

具有嵌套重复的正则表达式

当有多个同名包时如何在vscode中显示golang包完整路径?

Go AST:获取所有 struct

如何优雅地映射到 Go 中返回可变长度数组的方法?

如何使用带有Electron 表格 ID、Electron 表格名称、表格 ID 和值的 golang 在 googlesheet 中插入数据