Skip to content

Commit

Permalink
Add gRPC interceptor to request tracker (#224)
Browse files Browse the repository at this point in the history
This makes those metrics reusable between HTTP and gRPC servers
  • Loading branch information
benkeith-splunk authored Oct 4, 2021
1 parent 35116ef commit 602c94b
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 2 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@ require (
github.com/smartystreets/goconvey v1.6.4
github.com/stretchr/testify v1.7.0
github.com/vaughan0/go-ini v0.0.0-20130923145212-a98ad7ee00ec
google.golang.org/grpc v1.40.0
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 // indirect
)
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1267,6 +1267,7 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
golang.org/x/net v0.0.0-20210427231257-85d9c07bbe3a/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
Expand Down Expand Up @@ -1396,6 +1397,7 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
Expand Down Expand Up @@ -1595,6 +1597,7 @@ google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20210312152112-fc591d9ea70f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0=
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
Expand Down Expand Up @@ -1623,6 +1626,7 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q=
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
Expand Down
29 changes: 27 additions & 2 deletions web/reqcounter.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package web

import (
"context"
"net/http"
"sync/atomic"
"time"

"github.com/signalfx/golib/v3/datapoint"
"github.com/signalfx/golib/v3/sfxclient"
"google.golang.org/grpc"
)

// RequestCounter is a negroni handler that tracks connection stats
Expand All @@ -29,16 +31,39 @@ func (m *RequestCounter) Wrap(next http.Handler) http.Handler {
return http.HandlerFunc(f)
}

func (m *RequestCounter) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.Handler) {
// wrapRequest will wrap the request handler func in a generic way that times the request and
// maintains counts for org metrics.
func (m *RequestCounter) wrapRequest(handler func()) {
atomic.AddInt64(&m.TotalConnections, 1)
atomic.AddInt64(&m.ActiveConnections, 1)
defer atomic.AddInt64(&m.ActiveConnections, -1)
start := time.Now()
next.ServeHTTP(rw, r)

handler()

reqDuration := time.Since(start)
atomic.AddInt64(&m.TotalProcessingTimeNs, reqDuration.Nanoseconds())
}

// ServeHTTP makes an HTTP handler that tracks the requests.
func (m *RequestCounter) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.Handler) {
m.wrapRequest(func() { next.ServeHTTP(rw, r) })
}

// GRPCInterceptor makes a unary GRPC interceptor to track requests.
func (m *RequestCounter) GRPCInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
var resp interface{}
var err error

m.wrapRequest(func() {
// This is safe because WrapRequest should always call this func synchronously and never in
// a separate goroutine.
resp, err = handler(ctx, req)
})

return resp, err
}

// Datapoints returns stats on total connections, active connections, and total processing time
func (m *RequestCounter) Datapoints() []*datapoint.Datapoint {
return []*datapoint.Datapoint{
Expand Down
11 changes: 11 additions & 0 deletions web/reqcounter_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package web

import (
"context"
"net/http"
"testing"
"time"
Expand All @@ -26,4 +27,14 @@ func TestRequestCounter(t *testing.T) {
m.ServeHTTP(nil, nil, f)

assert.Equal(t, 3, len(m.Datapoints()))

resp, err := m.GRPCInterceptor(context.Background(), nil, nil, func(ctx context.Context, req interface{}) (interface{}, error) {
assert.EqualValues(t, 1, m.ActiveConnections)
assert.EqualValues(t, 3, m.TotalConnections)
assert.NotEqual(t, 0, m.TotalProcessingTimeNs)

return 5, nil
})
assert.NoError(t, err)
assert.Equal(t, 5, resp)
}

0 comments on commit 602c94b

Please sign in to comment.