Skip to content

Commit

Permalink
feat(otel): add otel package. add otel interceptors to grpc. bump deps
Browse files Browse the repository at this point in the history
  • Loading branch information
bradub committed Jun 13, 2024
1 parent 1e34378 commit 2660270
Show file tree
Hide file tree
Showing 14 changed files with 251 additions and 54 deletions.
68 changes: 36 additions & 32 deletions grpc/go.mod
Original file line number Diff line number Diff line change
@@ -1,56 +1,60 @@
module github.com/purposeinplay/go-commons/grpc

go 1.20
go 1.21

toolchain go1.22.3

require (
contrib.go.opencensus.io/exporter/stackdriver v0.13.14
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
github.com/go-chi/chi/v5 v5.0.11
github.com/go-chi/chi/v5 v5.0.12
github.com/google/uuid v1.6.0
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0
github.com/matryer/is v1.4.0
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0
github.com/matryer/is v1.4.1
github.com/oklog/run v1.1.0
github.com/rs/cors v1.10.1
github.com/rs/cors v1.11.0
go.opencensus.io v0.24.0
go.uber.org/zap v1.26.0
google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe
google.golang.org/grpc v1.61.0
google.golang.org/protobuf v1.32.0
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0
go.uber.org/zap v1.27.0
google.golang.org/genproto/googleapis/api v0.0.0-20240610135401-a8a62080eff3
google.golang.org/grpc v1.64.0
google.golang.org/protobuf v1.34.2
)

require (
cloud.google.com/go/compute v1.23.3 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/monitoring v1.17.0 // indirect
cloud.google.com/go/trace v1.10.4 // indirect
github.com/aws/aws-sdk-go v1.50.4 // indirect
cloud.google.com/go/auth v0.5.1 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect
cloud.google.com/go/compute v1.27.0 // indirect
cloud.google.com/go/compute/metadata v0.3.0 // indirect
cloud.google.com/go/monitoring v1.19.0 // indirect
cloud.google.com/go/trace v1.10.7 // indirect
github.com/aws/aws-sdk-go v1.54.0 // indirect
github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
github.com/googleapis/gax-go/v2 v2.12.4 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/prometheus/prometheus v0.49.1 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 // indirect
go.opentelemetry.io/otel v1.22.0 // indirect
go.opentelemetry.io/otel/metric v1.22.0 // indirect
go.opentelemetry.io/otel/trace v1.22.0 // indirect
github.com/prometheus/prometheus v0.52.1 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0 // indirect
go.opentelemetry.io/otel v1.27.0 // indirect
go.opentelemetry.io/otel/metric v1.27.0 // indirect
go.opentelemetry.io/otel/trace v1.27.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.18.0 // indirect
golang.org/x/net v0.20.0 // indirect
golang.org/x/oauth2 v0.16.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.16.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/crypto v0.24.0 // indirect
golang.org/x/net v0.26.0 // indirect
golang.org/x/oauth2 v0.21.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.21.0 // indirect
golang.org/x/text v0.16.0 // indirect
golang.org/x/time v0.5.0 // indirect
google.golang.org/api v0.158.0 // indirect
google.golang.org/api v0.184.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe // indirect
google.golang.org/genproto v0.0.0-20240610135401-a8a62080eff3 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240610135401-a8a62080eff3 // indirect
)
67 changes: 67 additions & 0 deletions grpc/go.sum

Large diffs are not rendered by default.

18 changes: 17 additions & 1 deletion grpc/grpcclient/grpc_client_conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"net"

"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)
Expand All @@ -23,7 +24,12 @@ func NewConn(
o.apply(opts)
}

conn, err := grpc.Dial(addr, opts.computeDialOptions()...)
// nolint: revive
if addr == "bufnet" {
addr = "passthrough://bufnet"
}

conn, err := grpc.NewClient(addr, opts.computeDialOptions()...)
if err != nil {
return nil, fmt.Errorf("grpc dial: %w", err)
}
Expand Down Expand Up @@ -98,3 +104,13 @@ func WithClientUnaryInterceptor(interceptor grpc.UnaryClientInterceptor) OptionC
)
})
}

// WithOTEL adds OpenTelemetry instrumentation to the client.
func WithOTEL() OptionConn {
return newFuncConnOption(func(o *connOptions) {
o.dialOptions = append(
o.dialOptions,
grpc.WithStatsHandler(otelgrpc.NewClientHandler()),
)
})
}
15 changes: 14 additions & 1 deletion grpc/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
grpcctxtags "github.com/grpc-ecosystem/go-grpc-middleware/tags"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/rs/cors"
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
"go.uber.org/zap"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
Expand Down Expand Up @@ -72,6 +73,7 @@ type serverOptions struct {
registerGateway registerGatewayFunc
grpcListener net.Listener
unaryServerInterceptors []grpc.UnaryServerInterceptor
dialOptions []grpc.DialOption
errorHandler ErrorHandler
panicHandler PanicHandler
monitorOperationer MonitorOperationer
Expand Down Expand Up @@ -306,6 +308,16 @@ func WithHTTPRoute(method, path string, handler http.HandlerFunc) ServerOption {
})
}

// WithOTEL adds the OpenTelemetry instrumentation to the GRPC server.
func WithOTEL() ServerOption {
return newFuncServerOption(func(o *serverOptions) {
o.dialOptions = append(
o.dialOptions,
grpc.WithStatsHandler(otelgrpc.NewServerHandler()),
)
})
}

func defaultServerOptions() serverOptions {
return serverOptions{
tracing: false,
Expand All @@ -331,12 +343,13 @@ func defaultServerOptions() serverOptions {
},
),
},
httpRoutes: nil,
httpMiddlewares: nil,
httpRoutes: nil,
registerServer: nil,
registerGateway: nil,
grpcListener: nil,
unaryServerInterceptors: nil,
dialOptions: nil,
errorHandler: nil,
panicHandler: nil,
monitorOperationer: nil,
Expand Down
4 changes: 2 additions & 2 deletions grpc/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,13 +113,13 @@ func (s *Server) ListenAndServe() error {

var runGroup run.Group

runGroup.Add(s.runGRPCServer, func(err error) {
runGroup.Add(s.runGRPCServer, func(error) {
_ = s.grpcServer.close()
})

// start gateway server.
if s.gatewayServer != nil {
runGroup.Add(s.runGatewayServer, func(err error) {
runGroup.Add(s.runGatewayServer, func(error) {
_ = s.gatewayServer.close()
})
}
Expand Down
37 changes: 19 additions & 18 deletions grpc/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ func TestGateway(t *testing.T) {
grpcServer, err := commonsgrpc.NewServer(
commonsgrpc.WithMuxOptions([]runtime.ServeMuxOption{
runtime.WithErrorHandler(func(
ctx context.Context,
mux *runtime.ServeMux,
marshaler runtime.Marshaler,
_ context.Context,
_ *runtime.ServeMux,
_ runtime.Marshaler,
respWriter http.ResponseWriter,
req *http.Request,
_ *http.Request,
err error,
) {
t.Logf("err: %s", err)
Expand Down Expand Up @@ -87,7 +87,7 @@ func TestGateway(t *testing.T) {
commonsgrpc.WithHTTPRoute(
http.MethodGet,
"/test",
func(w http.ResponseWriter, r *http.Request) {
func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusUnprocessableEntity)
},
),
Expand Down Expand Up @@ -144,7 +144,7 @@ func TestGateway(t *testing.T) {
)
i.NoErr(err)

req.Header.Set("Grpc-Metadata-custom", header)
req.Header.Set("Grpc-Metadata-Custom", header)
req.Header.Set("X-Custom", header)

resp, err = http.DefaultClient.Do(req)
Expand All @@ -169,11 +169,11 @@ func TestGateway(t *testing.T) {
grpcServer, err := commonsgrpc.NewServer(
commonsgrpc.WithMuxOptions([]runtime.ServeMuxOption{
runtime.WithErrorHandler(func(
ctx context.Context,
mux *runtime.ServeMux,
marshaler runtime.Marshaler,
_ context.Context,
_ *runtime.ServeMux,
_ runtime.Marshaler,
w http.ResponseWriter,
r *http.Request,
_ *http.Request,
err error,
) {
i.Equal(grpcErr.Error(), status.Convert(err).Message())
Expand Down Expand Up @@ -326,7 +326,7 @@ func TestBufnet(t *testing.T) {
wg.Wait()
})

_, err = grpc.Dial(
_, err = grpc.NewClient(
"bufnet",
grpc.WithContextDialer(bufDialer),
grpc.WithTransportCredentials(insecure.NewCredentials()),
Expand All @@ -351,7 +351,7 @@ func TestErrorHandling(t *testing.T) {

errorHandler := &mock.ErrorHandlerMock{
ErrorToGRPCStatusFunc: func(
err error,
error,
) (*status.Status, error) {
return status.New(codes.Internal, appErr.Error()), nil
},
Expand Down Expand Up @@ -382,7 +382,7 @@ func TestErrorHandling(t *testing.T) {
nil,
)

greetClient := newGreeterClient(t, bufDialer)
greetClient := newGreeterClient(t, "bufnet", bufDialer)

resp, err := greetClient.Greet(ctx, &greetpb.GreetRequest{
Greeting: &greetpb.Greeting{
Expand Down Expand Up @@ -432,7 +432,7 @@ func TestErrorHandling(t *testing.T) {
nil,
)

greetClient := newGreeterClient(t, bufDialer)
greetClient := newGreeterClient(t, "bufnet", bufDialer)

resp, err := greetClient.Greet(ctx, &greetpb.GreetRequest{
Greeting: &greetpb.Greeting{
Expand All @@ -454,7 +454,7 @@ func TestErrorHandling(t *testing.T) {
i := is.New(t)

errorHandler := &mock.ErrorHandlerMock{
IsApplicationErrorFunc: func(err error) bool {
IsApplicationErrorFunc: func(error) bool {
panic(panicString)
},
LogErrorFunc: func(err error) {
Expand Down Expand Up @@ -487,7 +487,7 @@ func TestErrorHandling(t *testing.T) {
nil,
)

greetClient := newGreeterClient(t, bufDialer)
greetClient := newGreeterClient(t, "bufnet", bufDialer)

resp, err := greetClient.Greet(ctx, &greetpb.GreetRequest{
Greeting: &greetpb.Greeting{
Expand Down Expand Up @@ -535,7 +535,7 @@ func TestMonitorOperation(t *testing.T) {
monitorOperationer,
)

greetClient := newGreeterClient(t, bufDialer)
greetClient := newGreeterClient(t, "bufnet", bufDialer)

resp, err := greetClient.Greet(ctx, &greetpb.GreetRequest{
Greeting: &greetpb.Greeting{
Expand Down Expand Up @@ -675,14 +675,15 @@ func newBufnetServer(

func newGreeterClient(
t *testing.T,
addr string,
dialer func(context.Context, string) (net.Conn, error),
) greetpb.GreetServiceClient {
t.Helper()

i := is.New(t)

clientConn, err := grpcclient.NewConn(
"",
addr,
grpcclient.WithContextDialer(dialer),
grpcclient.WithNoTLS(),
)
Expand Down
21 changes: 21 additions & 0 deletions otel/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2022 Purpose in Play

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
4 changes: 4 additions & 0 deletions otel/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
test:
go test -race ./...
lint:
golangci-lint run --fix -c=../.golangci.yml
Loading

0 comments on commit 2660270

Please sign in to comment.