简介
zerolog字段
我在我的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
的值。
设置
我有一个生产者/消费者设置(例如,参见https://goplay.tools/snippet/hkoMAwqKcwj),其中包含go例程,我有两个整数,它们是对仍在运行的消费者和生产者go例程的数量进行原子计数。当消费者和生产者被拆除时,我想在运行时显示这些数字。
下面是使用log而不是zerolog时的代码:
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
每个消费者/生产者一个日志记录器
使用zerolog,您可以创建记录器并将其传递给每个go-rountine:
logger := zerolog.New(os.Stderr)
go myConsumer(logger.With().Str("is", "consumer").Logger())
go myProducer(logger.With().Str("is", "producer").Logger())
然后,您可以通过查看每个日志行中的is
字段,轻松地在日志中找出消息是来自消费者还是生产者。
但是,如果我想总是在每个日志行中打印当前活动的消费者/生产者的数量,该怎么办?你可能会被诱惑去做这样的事情:
go myConsumer(logger.With().Str("is", "consumer").Int("consumersRunning", consumersRunning).Logger())
go myProducer(logger.With().Str("is", "producer").Int("producersRunning", producersRunning).Logger())
当然,这只会在创建go例程时打印consumersRunning
和producersRunning
的瞬时值。相反,我希望日志输出反映日志输出时的值。
摘要
我希望我的问题很清楚。我不确定它是否与零的概念相违背,但像这样的函数
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")
创建日志条目。这推迟了runningConsumers
的评估,但也为每个日志条目创建了一个日志记录器,感觉有点过分。
到现在为止,我希望我没有混淆你。
2条答案
按热度按时间7lrncoxx1#
你可以添加一个钩子。为每个日志记录事件评估挂钩
https://go.dev/play/p/Q7doafJGaeE
输出
在调用
Hook.Run
之间需要指针来保存Count
也许你的
HookFunc
更好。它是一个无状态函数,每个事件都会调用它。下面是一个函数钩子的例子,它为每个消息调用PRNG:https://go.dev/play/p/xu6aXpUmE0v输出
jucafojl2#
您可以使用zerolog Hook来实现这一点。钩子是带有
Run
方法的接口,该方法在事件数据写入给定的io.Writer
(在您的示例中为os.Stderr
)之前被调用。下面是一些示例代码:
您将使用计数器的
inc
和dec
方法来修改正在运行的消费者/生产者的数量。