-
Notifications
You must be signed in to change notification settings - Fork 705
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 go-kit logging middleware #223
Add go-kit logging middleware #223
Conversation
Thanks for your pull request. It looks like this may be your first contribution to a Google open source project (if not, look below for help). Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). 📝 Please visit https://cla.developers.google.com/ to sign. Once you've signed (or fixed any issues), please reply here with What to do if you already signed the CLAIndividual signers
Corporate signers
ℹ️ Googlers: Go here for more info. |
a3837e8
to
737f2b4
Compare
@googlebot I signed it! |
CLAs look good, thanks! ℹ️ Googlers: Go here for more info. |
Codecov Report
@@ Coverage Diff @@
## master #223 +/- ##
==========================================
+ Coverage 72.12% 73.01% +0.89%
==========================================
Files 37 42 +5
Lines 1349 1564 +215
==========================================
+ Hits 973 1142 +169
- Misses 329 369 +40
- Partials 47 53 +6
Continue to review full report at Codecov.
|
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.
Overall just nits... it follow the same pattern as the other interceptors and tests seem to cover the majority of cases. Can you also add a doc.go to describe the new module?
Great to see that it has been tested already against thanos 👍
@adrien-f mind adding the addition of the new logger to the |
@adrien-f could you rebase and push changes ... looking to get this in before we cut a release again |
Sorry I missed your message, will get on it today 😄 |
737f2b4
to
a35a11d
Compare
There you go 😄 ! |
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.
Looks good overall just a few minor tweaks to tidy it up abit, mainly:
- using the newer "context" package
- adding docs/examples
- cleaning up comments if they reference zap
- running goimports over the code
Thanks again and sorry for the slow turn around on my side.
@adrien-f you been able to have a look at this? |
a35a11d
to
51ffeb9
Compare
It would be nice to have this, let's get back to this (: @adrien-f ? |
29a715a
to
6e27dcf
Compare
Hi there ! I did go over your latest reviews 2 weeks ago but failed to notice that the CI was red 🙏 ! How does it look ? |
logging/kit/client_interceptors.go
Outdated
code := o.codeFunc(err) | ||
logger = o.levelFunc(code, logger) | ||
args := []interface{}{"msg", msg, "error", err, "grpc.code", code.String()} | ||
args = append(args, o.durationFunc(time.Now().Sub(startTime))...) |
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.
Could use time.Since
here instead.
if strings.HasPrefix(runtime.Version(), "go1.7") { | ||
t.Skipf("Skipping due to json.RawMessage incompatibility with go1.7") | ||
return | ||
} |
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.
Surely we don't need this check. We should only be supporting Go 1.12 and 1.13 at this point.
} | ||
|
||
func durationToMilliseconds(duration time.Duration) float32 { | ||
return float32(duration.Nanoseconds()/1000) / 1000 |
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.
Why not duration.Milliseconds
? https://golang.org/pkg/time/#Duration.Milliseconds
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 project is still built with Go 1.12, should we upgrade ?
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.
Awesome! Thanks for all tests and go-kit support.
It generally looks amazing, but I would focus on reusing more. Otherwise we are inconsistent. Can we create maybe logging/common
or logging
package so we can put common stuff for all implementations? I think we can reuse much more. Especially given we have 3 implementation now it's time to aggregate common stuff together (:
|
||
type ctxMarker struct{} | ||
|
||
type ctxLogger 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.
Do we need to replicate this for every logger? Can we reuse?
logging/kit/ctxkit/context.go
Outdated
fields := TagsToFields(ctx) | ||
// Add fields added until now. | ||
fields = append(fields, l.fields...) | ||
return log.With(l.logger, fields...) |
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.
just log.With(l.logger, append(fields, l.fields...)...)
var DefaultDurationToField = DurationToTimeMillisField | ||
|
||
// DurationToTimeMillisField converts the duration to milliseconds and uses the key `grpc.time_ms`. | ||
func DurationToTimeMillisField(duration time.Duration) []interface{} { |
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 use []string
? I don't think go kit logger supports non string field.
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 With
call that those fields are used afterwards require []interface{}
:
func With(logger Logger, keyvals ...interface{}) Logger
https://godoc.org/github.com/go-kit/kit/log#With
} | ||
|
||
// DefaultCodeToLevel is the default implementation of gRPC return codes and interceptor log level for server side. | ||
func DefaultCodeToLevel(code codes.Code, logger log.Logger) log.Logger { |
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.
I would vote for reusing more... We need to reimplement Option
stuff and code to level 3 times and it's quite a problem as we have inconsistencies. e.g https://github.com/grpc-ecosystem/go-grpc-middleware/blob/master/logging/logrus/options.go#L87 for codes to level. Can we optimize for it?
logger.Log(args...) | ||
} | ||
|
||
func newClientLoggerFields(ctx context.Context, fullMethodString string) []interface{} { |
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 create maybe logging/common
or logging
package so we can put common stuff for all implementation. I think we can reuse much more. Especially given we have 3 implementation now it's time to aggregate common stuff together (:
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.
I think we can actually do this in second PR, we can iterate over it (:
) | ||
|
||
// UnaryClientInterceptor returns a new unary client interceptor that optionally logs the execution of external gRPC calls. | ||
func UnaryClientInterceptor(logger log.Logger, opts ...Option) grpc.UnaryClientInterceptor { |
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.
I just tried to use it and I cannot see the option that would allow me to inject custom fields here like request-id
to the logged message ): I think it would be nice to add! It is exactly the same for logrus and zap but would nice to add I guess (: at some point in another PR!
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.
func newClientLoggerFields(ctx context.Context, fullMethodString string) []interface{} { | ||
service := path.Dir(fullMethodString)[1:] | ||
method := path.Base(fullMethodString) | ||
return []interface{}{ |
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 are missing something like callLog = callLog.WithFields(ctx_logrus.Extract(ctx).Data)
(this is what logrus do)
Either he or on caller side, but we need to have to use context logger (:
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.
I would agree but I don't see it on the other loggers as well. I do see it in server_interceptors
though
Hey it's me again! I do agree that some pieces of the logging component is getting repetitive and should probably be merged and aggregated. Should this be a separated MR or you'd like me to work on it in this one 😄 ? |
@adrien-f do you still intend to push forward with this PR? |
logging/kit/ctxkit/context.go
Outdated
// Add fields added until now. | ||
fields = append(fields, l.fields...) | ||
return log.With(l.logger, fields...) | ||
return log.With(l.logger, append(fields, l.fields...)) |
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.
This seems to break the tests. append(fields, l.fields...)...
should be the correct change.
I think we're happy to have this in two separate PRs so that we can get this merged. |
Would be super nice to push it through, and definitely let's add this without major refactoring of others first (: |
c1e56ba
to
09011da
Compare
09011da
to
d2efd62
Compare
Terribly sorry for the long wait 🙏 I've just pushed the latest changes, rebased master and tested with Thanos:
Trace IDs are injected and all tests are green. I've also started working on a common package/interface, maybe something like type MiddlewareLogger interface {
Inject(ctx context.Context, method string, operation OperationKind, startTime time.Time) context.Context
InjectPayload(ctx context.Context, method string, operation OperationKind) context.Context
AddFields(ctx context.Context, fields Fields)
Log(ctx context.Context, message string, level Level)
LogRequest(ctx context.Context, message string, code codes.Code, level Level, duration DurationEntry, err error)
LogPayload(ctx context.Context, message string, payload interface{}, payloadName string)
} but that might be out of scope of this MR. |
Awesome, thanks @adrien-f, let's save the refactor for the next PR! |
Greetings 👋
I come from the Thanos project where we mostly use the go-kit logging library and we wanted some sweet gRPC logging for our users.
I'm not a Go expert, so I mostly copy/pasted the tests from the Zap implementation and wrote the go-kit logging system.
The tests suite is green and it works pretty swell with Thanos: