-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
feat: add support for custom ReflectType encoder #1039
Conversation
Codecov Report
@@ Coverage Diff @@
## master #1039 +/- ##
=======================================
Coverage 98.20% 98.21%
=======================================
Files 47 48 +1
Lines 2067 2071 +4
=======================================
+ Hits 2030 2034 +4
Misses 29 29
Partials 8 8
Continue to review full report at Codecov.
|
zapcore/encoder.go
Outdated
@@ -331,6 +332,9 @@ type EncoderConfig struct { | |||
// Unlike the other primitive type encoders, EncodeName is optional. The | |||
// zero value falls back to FullNameEncoder. | |||
EncodeName NameEncoder `json:"nameEncoder" yaml:"nameEncoder"` | |||
// Configure the encoder for interface{} type objects | |||
// If not provided, objects are encoded using json.Encoder | |||
NewReflectedEncoder func(io.Writer) ReflectedEncoder `json:"newReflectedEncoder" yaml:"newReflectedEncoder"` |
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.
Since this a function that is not JSON/YAML encodeable, we'll have to use -
here.
NewReflectedEncoder func(io.Writer) ReflectedEncoder `json:"newReflectedEncoder" yaml:"newReflectedEncoder"` | |
NewReflectedEncoder func(io.Writer) ReflectedEncoder `json:"-" yaml:"-"` |
zapcore/json_encoder.go
Outdated
var newReflectedEncoder func(io.Writer) ReflectedEncoder | ||
if enc.NewReflectedEncoder == nil { | ||
newReflectedEncoder = GetDefaultReflectedEncoder() | ||
} else { | ||
newReflectedEncoder = enc.NewReflectedEncoder | ||
} |
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.
We should do this in NewJSONEncoder
? We can set NewReflectedEncoder
in there once if it's nil, and then we don't have to check it on the hot path.
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.
@abhinav
This change was breaking TestJSONEncoderObjectFields
test cases in json_encoder_impl_test.go
so had to fix it by manually assigning default reflected encoder.
LMK if there are any concerns.
zapcore/json_encoder.go
Outdated
if enc.NewReflectedEncoder == nil { | ||
newReflectedEncoder = GetDefaultReflectedEncoder() | ||
} else { | ||
newReflectedEncoder = enc.NewReflectedEncoder |
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.
Would you please add a test for the custom reflection encoder case?
We don't want us to introduce a new dependency for that,
so a fake implementation of the function will suffice.
zapcore/reflected_encoder.go
Outdated
) | ||
|
||
// A ReflectedEncoder handles the serialization of Field which have FieldType = ReflectType and writes them to the underlying data stream | ||
// The underlying data stream is provided by zap during initialization. See EncoderConfig.NewReflectedEncoder |
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.
// The underlying data stream is provided by zap during initialization. See EncoderConfig.NewReflectedEncoder | |
// The underlying data stream is provided by Zap during initialization. See EncoderConfig.NewReflectedEncoder. |
zapcore/reflected_encoder.go
Outdated
// A ReflectedEncoder handles the serialization of Field which have FieldType = ReflectType and writes them to the underlying data stream | ||
// The underlying data stream is provided by zap during initialization. See EncoderConfig.NewReflectedEncoder | ||
type ReflectedEncoder interface { | ||
// Encode encodes and writes to the underlying data stream |
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.
// Encode encodes and writes to the underlying data stream | |
// Encode encodes and writes to the underlying data stream. |
zapcore/reflected_encoder.go
Outdated
Encode(interface{}) error | ||
} | ||
|
||
func GetDefaultReflectedEncoder() func(writer io.Writer) ReflectedEncoder { |
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.
We would prefer not to export this function. We also don't need the wrapper type because json.Encoder satisfies the ReflectedEncoder interface.
So something like the following should suffice:
func defaultReflectedEncoder(w io.Writer) ReflectedEncoder {
enc := json.NewEncoder(w)
enc.SetEscapeHTML(false)
return enc
}
The defaultReflectedEncoder function can satisfy the signature for `NewReflectedEncoder`, so we don't need to return a closure. And the returned `json.Encoder` matches the ReflectedEncoder interface so we don't need the wrapper type either.
assertOutput manually sets up a jsonEncoder. This means that any config initalization we do in the constructor has to be replicated in assertOutput. Instead, use the constructor and cast to `*jsonEncoder`.
zapcore/json_encoder_test.go
Outdated
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
buf, err := enc.EncodeEntry(zapcore.Entry{ |
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.
for _, tt := range tests { | |
t.Run(tt.name, func(t *testing.T) { | |
buf, err := enc.EncodeEntry(zapcore.Entry{ | |
for _, tt := range tests { | |
tt := tt | |
t.Run(tt.name, func(t *testing.T) { | |
t.Parallel() | |
buf, err := enc.EncodeEntry(zapcore.Entry{ |
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.
Oh, we can do that, although for that the encoder has to be instantiated per-test.
(Encoder isn't safe for concurrent use.)
I'll do it.
Co-authored-by: Sung Yoon Whang <sungyoonwhang@gmail.com>
Thanks! |
Hi Team!
This fixes #1034