zap
zap copied to clipboard
add F* funcs that allows use `func() []Fields` as arguments
This PR add new public funcs with signature (msg string, fields ...FieldsFunc)
, where FieldsFunc
is type FieldsFunc func() []Field
- FDebug
- FInfo
- FWarn
- FError
- FDPanic
- FPanic
- FFatal
This approach allows you to perform the calculation of field values only when the message is actually displayed in the log.
An example:
func main() {
logger, _ := zap.NewProduction()
logger.FDebug("hello world", fields)
}
func fields() []zap.Field {
// Here we do any heavy operations
// and add fields for logging
// This function is not called if the level is not appropriate
return []zap.Field{
// ...
}
}
Just to verify my assumptions - have you considered doing the same with https://pkg.go.dev/go.uber.org/zap#Logger.Check?
I see how FInfo
is a nicer/shorter format, but then to realistically make it work you'd likely need to pass in a closure, which also is not very pretty?
so the example might look like this, which is not much easier than the Check API, right?
func main() {
logger, _ := zap.NewProduction()
a := someStruct....
// some work
logger.FDebug("hello world", fields(a))
}
func fields() func() []zap.Field {
return func(arg someStruct) []zap.Field {
// Here we do any heavy operations
// and add fields for logging
// This function is not called if the level is not appropriate
return []zap.Field{
// use arg
}
}
}
Note I have no impact/relation to zap maitenance, I'm asking out of my personal curiosity.
Yes, under the hood these functions use log.check. You can think of an API as syntactic sugar
Rather than increasing the API surface for each level, I think it would be nicer to support func Lazy(fieldFunc... func() []Field) Field
. The call sites would look like logger.Info("my message", zap.Lazy(field1Func, field2Func))