// New returns an AddService backed by a gRPC client connection. It is the // responsibility of the caller to dial, and later close, the connection. func New(conn *grpc.ClientConn, tracer stdopentracing.Tracer, logger log.Logger) addsvc.Service { // We construct a single ratelimiter middleware, to limit the total outgoing // QPS from this client to all methods on the remote instance. We also // construct per-endpoint circuitbreaker middlewares to demonstrate how // that's done, although they could easily be combined into a single breaker // for the entire remote instance, too. limiter := ratelimit.NewTokenBucketLimiter(jujuratelimit.NewBucketWithRate(100, 100)) var sumEndpoint endpoint.Endpoint { sumEndpoint = grpctransport.NewClient( conn, "Add", "Sum", addsvc.EncodeGRPCSumRequest, addsvc.DecodeGRPCSumResponse, pb.SumReply{}, grpctransport.ClientBefore(opentracing.FromGRPCRequest(tracer, "Sum", logger)), ).Endpoint() sumEndpoint = opentracing.TraceClient(tracer, "Sum")(sumEndpoint) sumEndpoint = limiter(sumEndpoint) sumEndpoint = circuitbreaker.Gobreaker(gobreaker.NewCircuitBreaker(gobreaker.Settings{ Name: "Sum", Timeout: 30 * time.Second, }))(sumEndpoint) } var concatEndpoint endpoint.Endpoint { concatEndpoint = grpctransport.NewClient( conn, "Add", "Concat", addsvc.EncodeGRPCConcatRequest, addsvc.DecodeGRPCConcatResponse, pb.ConcatReply{}, grpctransport.ClientBefore(opentracing.FromGRPCRequest(tracer, "Concat", logger)), ).Endpoint() concatEndpoint = opentracing.TraceClient(tracer, "Concat")(concatEndpoint) concatEndpoint = limiter(concatEndpoint) concatEndpoint = circuitbreaker.Gobreaker(gobreaker.NewCircuitBreaker(gobreaker.Settings{ Name: "Concat", Timeout: 30 * time.Second, }))(concatEndpoint) } return addsvc.Endpoints{ SumEndpoint: sumEndpoint, ConcatEndpoint: concatEndpoint, } }
func newGRPCBinding(ctx context.Context, tracer opentracing.Tracer, svc server.AddService, tracingLogger log.Logger) grpcBinding { return grpcBinding{ sum: grpc.NewServer( ctx, kitot.TraceServer(tracer, "sum")(makeSumEndpoint(svc)), servergrpc.DecodeSumRequest, servergrpc.EncodeSumResponse, grpc.ServerBefore(kitot.FromGRPCRequest(tracer, "", tracingLogger)), ), concat: grpc.NewServer( ctx, kitot.TraceServer(tracer, "concat")(makeConcatEndpoint(svc)), servergrpc.DecodeConcatRequest, servergrpc.EncodeConcatResponse, grpc.ServerBefore(kitot.FromGRPCRequest(tracer, "", tracingLogger)), ), } }
// MakeGRPCServer makes a set of endpoints available as a gRPC AddServer. func MakeGRPCServer(ctx context.Context, endpoints Endpoints, tracer stdopentracing.Tracer, logger log.Logger) pb.AddServer { options := []grpctransport.ServerOption{ grpctransport.ServerErrorLogger(logger), } return &grpcServer{ sum: grpctransport.NewServer( ctx, endpoints.SumEndpoint, DecodeGRPCSumRequest, EncodeGRPCSumResponse, append(options, grpctransport.ServerBefore(opentracing.FromGRPCRequest(tracer, "Sum", logger)))..., ), concat: grpctransport.NewServer( ctx, endpoints.ConcatEndpoint, DecodeGRPCConcatRequest, EncodeGRPCConcatResponse, append(options, grpctransport.ServerBefore(opentracing.FromGRPCRequest(tracer, "Concat", logger)))..., ), } }
func TestTraceGRPCRequestRoundtrip(t *testing.T) { logger := log.NewNopLogger() tracer := mocktracer.New() // Initialize the ctx with a Span to inject. beforeSpan := tracer.StartSpan("to_inject").(*mocktracer.MockSpan) defer beforeSpan.Finish() beforeSpan.Context().SetBaggageItem("baggage", "check") beforeCtx := opentracing.ContextWithSpan(context.Background(), beforeSpan) toGRPCFunc := kitot.ToGRPCRequest(tracer, logger) md := metadata.Pairs() // Call the RequestFunc. afterCtx := toGRPCFunc(beforeCtx, &md) // The Span should not have changed. afterSpan := opentracing.SpanFromContext(afterCtx) if beforeSpan != afterSpan { t.Errorf("Should not swap in a new span") } // No spans should have finished yet. finishedSpans := tracer.GetFinishedSpans() if want, have := 0, len(finishedSpans); want != have { t.Errorf("Want %v span(s), found %v", want, have) } // Use FromGRPCRequest to verify that we can join with the trace given MD. fromGRPCFunc := kitot.FromGRPCRequest(tracer, "joined", logger) joinCtx := fromGRPCFunc(afterCtx, &md) joinedSpan := opentracing.SpanFromContext(joinCtx).(*mocktracer.MockSpan) joinedContext := joinedSpan.Context().(*mocktracer.MockSpanContext) beforeContext := beforeSpan.Context().(*mocktracer.MockSpanContext) if joinedContext.SpanID == beforeContext.SpanID { t.Error("SpanID should have changed", joinedContext.SpanID, beforeContext.SpanID) } // Check that the parent/child relationship is as expected for the joined span. if want, have := beforeContext.SpanID, joinedSpan.ParentID; want != have { t.Errorf("Want ParentID %q, have %q", want, have) } if want, have := "joined", joinedSpan.OperationName; want != have { t.Errorf("Want %q, have %q", want, have) } if want, have := "check", joinedSpan.Context().BaggageItem("baggage"); want != have { t.Errorf("Want %q, have %q", want, have) } }