-
Notifications
You must be signed in to change notification settings - Fork 683
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
v2: Refactor metrics interceptor and fix tests #413
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. |
Codecov Report
@@ Coverage Diff @@
## v2 #413 +/- ##
===========================================
- Coverage 83.58% 56.06% -27.53%
===========================================
Files 30 38 +8
Lines 932 1336 +404
===========================================
- Hits 779 749 -30
- Misses 114 515 +401
- Partials 39 72 +33
Continue to review full report at Codecov.
|
@googlebot I signed it! |
@@ -50,7 +50,7 @@ func (m *mockReportable) Equal(t *testing.T, expected []*mockReport) { | |||
require.NoError(t, err) | |||
continue | |||
} | |||
require.Equal(t, expected[i].postCalls[k].Error(), err.Error(), "%v %v", i, k) | |||
require.EqualError(t, err, expected[i].postCalls[k].Error(), "%v %v", i, k) |
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.
If there is a bug and err
is nil
, then this line panics. Now it does not and fails the test cleanly.
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 a lot
@@ -276,7 +276,7 @@ func (s *ClientInterceptorTestSuite) TestListReporting() { | |||
typ: ServerStream, | |||
svcName: testpb.TestServiceFullName, | |||
methodName: "PingList", | |||
postCalls: []error{io.EOF}, | |||
postCalls: []error{nil}, |
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.
Because of the change in interceptors/client.go
, it's called with nil
now.
@@ -329,7 +329,9 @@ func (s *ClientInterceptorTestSuite) TestBiStreamingReporting() { | |||
if err == io.EOF { | |||
break | |||
} | |||
require.NoError(s.T(), err, "reading pingStream shouldn't fail") |
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.
It is incorrect to use require
in a goroutine other than the main test goroutine.
@@ -340,12 +342,12 @@ func (s *ClientInterceptorTestSuite) TestBiStreamingReporting() { | |||
require.NoError(s.T(), ss.CloseSend()) | |||
wg.Wait() | |||
|
|||
require.EqualValues(s.T(), count, 100, "Number of received msg on the wire must match") | |||
require.EqualValues(s.T(), 100, count, "Number of received msg on the wire must match") |
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.
Put actual and expected values where they should be.
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.
Wow, thanks for those detailed comments (: Next time, no need for this it's very clear! 💪🏽
@@ -11,3 +11,5 @@ require ( | |||
google.golang.org/grpc v1.35.0 | |||
google.golang.org/protobuf v1.25.0 | |||
) | |||
|
|||
replace github.com/grpc-ecosystem/go-grpc-middleware/v2 => ../.. |
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'm not sure how to test it otherwise if changes are made to the outer module and to providers.
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 it'll have to be merged in two steps.
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.
If this PR is approved I can split it into two - one updating the base and another one updating the provider. I also have a few more things I'd like to cleanup in follow ups.
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.
Sounds good to me, will give @bwplotka a few days to have a look but I'm otherwise happy to merge this on our own.
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.
Yup, this is the problem with multi-modules.
One thing we could add is to add some tooling that e.g makes commit with this PR on your fork, then creates commit on top of it, so it's at least not broken on master, if you just pull openmetrics module. Local path approach can break users on main. It's fine for now (dev part of v2) but we might want to improve this process. LGTM for now
} | ||
|
||
func (rep *reportable) ServerReporter(ctx context.Context, _ interface{}, typ interceptors.GRPCType, service string, method string) (interceptors.Reporter, context.Context) { | ||
m := NewServerMetrics(rep.registry) |
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 is super weird. So we're creating a new metrics holder here, we do not register it anywhere and just use it as is. This is just broken - there is no way these metrics are going to be scraped.
@@ -1,35 +1,21 @@ | |||
package metrics |
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.
Server metrics and interceptor are refactored in the same way as client metrics and interceptor. All comments apply, not repeating them.
resp := httptest.NewRecorder() | ||
req, err := http.NewRequest("GET", "/", nil) | ||
require.NoError(t, err, "failed creating request for Prometheus handler") | ||
|
||
promhttp.Handler().ServeHTTP(resp, req) | ||
promhttp.HandlerFor(reg, promhttp.HandlerOpts{}).ServeHTTP(resp, req) |
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.
Use the explicitly passed registry here rather than a global one. Test should be self-contained and hermetic, it shouldn't depend on globals.
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 agree, thanks for this
@@ -292,6 +293,7 @@ func toFloat64HistCount(h prometheus.Observer) uint64 { | |||
} | |||
|
|||
func requireValue(t *testing.T, expect int, c prometheus.Collector) { | |||
t.Helper() |
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.
That way error traces when a test fails lead to the line where this function was invoked, not into this function. Convenience thing, helped me to navigate failing tests.
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 looks generally good to me, thanks for taking the time. I'll hold off on approving as this is @bwplotka's area of expertise.
requireValueHistCount(s.T(), 1, DefaultClientMetrics.clientHandledHistogram.WithLabelValues("unary", "mwitkow.testproto.TestService", "PingEmpty")) | ||
requireValue(s.T(), 1, s.clientMetrics.clientStartedCounter.WithLabelValues("unary", "providers.openmetrics.testproto.v1.TestService", "PingEmpty")) | ||
requireValue(s.T(), 1, s.clientMetrics.clientHandledCounter.WithLabelValues("unary", "providers.openmetrics.testproto.v1.TestService", "PingEmpty", "OK")) | ||
requireValueHistCount(s.T(), 1, s.clientMetrics.clientHandledHistogram.WithLabelValues("unary", "providers.openmetrics.testproto.v1.TestService", "PingEmpty")) |
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.
Nice find
@@ -11,3 +11,5 @@ require ( | |||
google.golang.org/grpc v1.35.0 | |||
google.golang.org/protobuf v1.25.0 | |||
) | |||
|
|||
replace github.com/grpc-ecosystem/go-grpc-middleware/v2 => ../.. |
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 it'll have to be merged in two steps.
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 this, LGTM
I agree that the openmetrics PR might have been prematurely merged.. Yet it was kind of stated to merge a bigger chunk of work for later to iterate... yet iteration never happened and the code on main was unusable. It's totally on me, sorry for not paying close attention during the review process. Cc @yashrsharma44 for learning too on this (:
Let's make sure to keep the quality bar much higher next time.
@@ -50,7 +50,7 @@ func (m *mockReportable) Equal(t *testing.T, expected []*mockReport) { | |||
require.NoError(t, err) | |||
continue | |||
} | |||
require.Equal(t, expected[i].postCalls[k].Error(), err.Error(), "%v %v", i, k) | |||
require.EqualError(t, err, expected[i].postCalls[k].Error(), "%v %v", i, k) |
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 a lot
// UnaryClientInterceptor is a gRPC client-side interceptor that provides Prometheus monitoring for Unary RPCs. | ||
func UnaryClientInterceptor(clientRegister openmetrics.Registerer) grpc.UnaryClientInterceptor { | ||
func UnaryClientInterceptor(clientMetrics *ClientMetrics) 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.
Agree, cc @yashrsharma44 for learning experience (:
@@ -340,12 +342,12 @@ func (s *ClientInterceptorTestSuite) TestBiStreamingReporting() { | |||
require.NoError(s.T(), ss.CloseSend()) | |||
wg.Wait() | |||
|
|||
require.EqualValues(s.T(), count, 100, "Number of received msg on the wire must match") | |||
require.EqualValues(s.T(), 100, count, "Number of received msg on the wire must match") |
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.
Wow, thanks for those detailed comments (: Next time, no need for this it's very clear! 💪🏽
@@ -11,3 +11,5 @@ require ( | |||
google.golang.org/grpc v1.35.0 | |||
google.golang.org/protobuf v1.25.0 | |||
) | |||
|
|||
replace github.com/grpc-ecosystem/go-grpc-middleware/v2 => ../.. |
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.
Yup, this is the problem with multi-modules.
One thing we could add is to add some tooling that e.g makes commit with this PR on your fork, then creates commit on top of it, so it's at least not broken on master, if you just pull openmetrics module. Local path approach can break users on main. It's fine for now (dev part of v2) but we might want to improve this process. LGTM for now
resp := httptest.NewRecorder() | ||
req, err := http.NewRequest("GET", "/", nil) | ||
require.NoError(t, err, "failed creating request for Prometheus handler") | ||
|
||
promhttp.Handler().ServeHTTP(resp, req) | ||
promhttp.HandlerFor(reg, promhttp.HandlerOpts{}).ServeHTTP(resp, req) |
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 agree, thanks for this
Thanks, @ash2k for such great work! I was the original author for introducing the changes for openmetrics and I agree that the changes were not suitable to be merged. Thanks for such a comprehensive review and this PR might be a good opportunity for me to write good Go code 😄 |
I decided to have a look at the v2 branch as I'm interested in better Prometheus metrics. I found that stuff was in a very weird state so I tried to fix, simplify and clean it all up. See inline comments for some details. I have also found that tests fail and are not executed on macOS (#411).
Closes #412.