-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Stringers field constructor for array of objects implementing fmt.Stringer method #1155
Conversation
This looks good to me, I wonder if we should add some sort of benchmark to show the benefit of this, since I believe the only way before was to use |
Codecov Report
@@ Coverage Diff @@
## master #1155 +/- ##
=======================================
Coverage 98.33% 98.33%
=======================================
Files 49 49
Lines 2160 2163 +3
=======================================
+ Hits 2124 2127 +3
Misses 28 28
Partials 8 8
📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more |
126f793
to
2101cab
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
give Field | ||
want []any | ||
}{ | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we also add a test for a []fmt.Stringer
? That should also work.
// Stringers constructs a field with the given key, holding a list of the | ||
// output provided by the value's String method | ||
// | ||
// Given an object that implements String on the value receiver, you |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same caveat as Objects applies here. We should add a comment about it:
// Note that these objects must implement fmt.Stringer directly.
// That is, if you're trying to marshal a []Request, the String method
// must be declared on the Request type, not its pointer (*Request).
In a future change, we can add an ObjectValues equivalent if necessary that will let the String method be on *Request
for a []Request
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Thanks for the contribution. Changes LGTM modulo @abhinav's comments and a lint failure
array_go118_test.go
Outdated
@@ -179,3 +179,48 @@ func TestObjectsAndObjectValues_marshalError(t *testing.T) { | |||
}) | |||
} | |||
} | |||
|
|||
type stringerObject struct{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: lint
type stringerObject struct{ | |
type stringerObject struct { |
2101cab
to
e3f7e7a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
Hi! I'm wondering if there was a specific reason as to why generics were used in this. Wouldn't this accomplish the same result? func Stringers(key string, values []fmt.Stringer) zap.Field {
return zap.Array(key, stringers(values))
}
type stringers []fmt.Stringer
func (os stringers) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for _, o := range os {
arr.AppendString(o.String())
}
return nil
} Thanks! |
You can't implicitly convert between foos := []Foo{ /* ... */ } We then have to handle it as follows (without generics): func Stringers(key string, values []fmt.Stringer) zap.Field {
// ...
}
// Stringers(foos) <- does not compile
converted := make([]fmt.Stringer, len(foos))
for i, f := range foos {
converted[i] = f // converts type `Foo` to `fmt.Stringer`
}
Stringers(converted) // compiles Whereas with generics, we can handle both func Stringers[T fmt.Stringer](key string, values []T) zap.Field {
// ...
}
var (
a = []fmt.Stringer{ /* ... */ }
b = []Foo{ /* ... */ }
)
Stringers(a) // compiles
Stringers(b) // compiles Thus the generic version gives callers more flexibility by (1) letting them use wider types than |
That makes perfect sense. Thanks for the explanation! |
Add a new Zap field constructor that encodes an array of zero or more
objects which implement fmt.Stringer interface into a Zap array.
Usage:
// type Request struct{ ... }
// func (a Request) String() string
//
// var requests []Request = ...
// logger.Info("sending requests", zap.Stringers("requests", requests))
Credits: @zmanji, @abhinav for the suggestions