// NewClientStream creates a new Stream for the client side. This is called // by generated code. func NewClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, opts ...CallOption) (ClientStream, error) { var ( t transport.ClientTransport err error ) t, err = cc.dopts.picker.Pick(ctx) if err != nil { return nil, toRPCErr(err) } // TODO(zhaoq): CallOption is omitted. Add support when it is needed. callHdr := &transport.CallHdr{ Host: cc.authority, Method: method, Flush: desc.ServerStreams && desc.ClientStreams, } if cc.dopts.cp != nil { callHdr.SendCompress = cc.dopts.cp.Type() } cs := &clientStream{ desc: desc, codec: cc.dopts.codec, cp: cc.dopts.cp, dc: cc.dopts.dc, tracing: EnableTracing, } if cc.dopts.cp != nil { callHdr.SendCompress = cc.dopts.cp.Type() cs.cbuf = new(bytes.Buffer) } if cs.tracing { cs.trInfo.tr = trace.New("grpc.Sent."+methodFamily(method), method) cs.trInfo.firstLine.client = true if deadline, ok := ctx.Deadline(); ok { cs.trInfo.firstLine.deadline = deadline.Sub(time.Now()) } cs.trInfo.tr.LazyLog(&cs.trInfo.firstLine, false) ctx = trace.NewContext(ctx, cs.trInfo.tr) } s, err := t.NewStream(ctx, callHdr) if err != nil { cs.finish(err) return nil, toRPCErr(err) } cs.t = t cs.s = s cs.p = &parser{r: s} // Listen on ctx.Done() to detect cancellation when there is no pending // I/O operations on this stream. go func() { select { case <-t.Error(): // Incur transport error, simply exit. case <-s.Context().Done(): err := s.Context().Err() cs.finish(err) cs.closeTransportStream(transport.ContextErr(err)) } }() return cs, nil }
// Open implements http.FileSystem. func (t *traceFS) Open(path string) (http.File, error) { tr := trace.New(t.family, path) ctx := trace.NewContext(context.Background(), tr) f, err := t.FileSystem.Open(ctx, path) // TODO: Decide where this should be in general (requests can be on-going). tr.Finish() return f, err }
func routeTracing(route Route, handler xhandler.HandlerC) xhandler.HandlerC { rs := route.String() return xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { tr := trace.New(rs, fmt.Sprintf("%s %s", r.Method, r.URL.Path)) ctx = trace.NewContext(ctx, tr) handler.ServeHTTPC(ctx, w, r) tr.Finish() }) }
func (t *TraceFS) newTrace(ctx context.Context, name, ft string, args ...interface{}) (trace.Trace, context.Context) { argsFmt := fmt.Sprintf(ft, args...) v := fmt.Sprintf("%s-%s %s", t.Id, t.MountConfig.FSName, argsFmt) if ctx == nil { ctx = context.TODO() } r := trace.New(name, v) ctx = trace.NewContext(ctx, r) return r, ctx }
// NewClientStream creates a new Stream for the client side. This is called // by generated code. func NewClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, opts ...CallOption) (ClientStream, error) { var ( conn *Conn t transport.ClientTransport err error ) for { conn, err = cc.dopts.picker.Pick() if err != nil { return nil, toRPCErr(err) } t, err = conn.Wait(ctx) if err != nil { if err == ErrTransientFailure { continue } return nil, toRPCErr(err) } break } // TODO(zhaoq): CallOption is omitted. Add support when it is needed. callHdr := &transport.CallHdr{ Host: conn.authority, Method: method, } cs := &clientStream{ desc: desc, codec: conn.dopts.codec, tracing: EnableTracing, } if cs.tracing { cs.traceInfo.tr = trace.New("grpc.Sent."+methodFamily(method), method) cs.traceInfo.firstLine.client = true if deadline, ok := ctx.Deadline(); ok { cs.traceInfo.firstLine.deadline = deadline.Sub(time.Now()) } cs.traceInfo.tr.LazyLog(&cs.traceInfo.firstLine, false) ctx = trace.NewContext(ctx, cs.traceInfo.tr) } s, err := t.NewStream(ctx, callHdr) if err != nil { return nil, toRPCErr(err) } cs.t = t cs.s = s cs.p = &parser{s: s} return cs, nil }
// NewClientStream creates a new Stream for the client side. This is called // by generated code. func NewClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, opts ...CallOption) (ClientStream, error) { var ( t transport.ClientTransport err error ) t, err = cc.dopts.picker.Pick(ctx) if err != nil { return nil, toRPCErr(err) } // TODO(zhaoq): CallOption is omitted. Add support when it is needed. callHdr := &transport.CallHdr{ Host: cc.authority, Method: method, } cs := &clientStream{ desc: desc, codec: cc.dopts.codec, tracing: EnableTracing, } if cs.tracing { cs.trInfo.tr = trace.New("grpc.Sent."+methodFamily(method), method) cs.trInfo.firstLine.client = true if deadline, ok := ctx.Deadline(); ok { cs.trInfo.firstLine.deadline = deadline.Sub(time.Now()) } cs.trInfo.tr.LazyLog(&cs.trInfo.firstLine, false) ctx = trace.NewContext(ctx, cs.trInfo.tr) } s, err := t.NewStream(ctx, callHdr) if err != nil { return nil, toRPCErr(err) } cs.t = t cs.s = s cs.p = &parser{s: s} // Listen on ctx.Done() to detect cancellation when there is no pending // I/O operations on this stream. go func() { <-s.Context().Done() cs.closeTransportStream(transport.ContextErr(s.Context().Err())) }() return cs, nil }
func (s *Server) serveStreams(st transport.ServerTransport) { defer s.removeConn(st) defer st.Close() var wg sync.WaitGroup st.HandleStreams(func(stream *transport.Stream) { wg.Add(1) go func() { defer wg.Done() s.handleStream(st, stream, s.traceInfo(st, stream)) }() }, func(ctx context.Context, method string) context.Context { if !EnableTracing { return ctx } tr := trace.New("grpc.Recv."+methodFamily(method), method) return trace.NewContext(ctx, tr) }) wg.Wait() }
// TraceContext recreates the context of s with a trace.Trace. func (s *Stream) TraceContext(tr trace.Trace) { s.ctx = trace.NewContext(s.ctx, tr) }
// Open implements store.FileSystem func (r *rootTraceFS) Open(ctx context.Context, path string) (http.File, error) { tr := trace.New("request", path) defer tr.Finish() return r.FileSystem.Open(trace.NewContext(ctx, tr), path) }
func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, opts ...CallOption) (_ ClientStream, err error) { var ( t transport.ClientTransport s *transport.Stream put func() ) c := defaultCallInfo for _, o := range opts { if err := o.before(&c); err != nil { return nil, toRPCErr(err) } } callHdr := &transport.CallHdr{ Host: cc.authority, Method: method, Flush: desc.ServerStreams && desc.ClientStreams, } if cc.dopts.cp != nil { callHdr.SendCompress = cc.dopts.cp.Type() } var trInfo traceInfo if EnableTracing { trInfo.tr = trace.New("grpc.Sent."+methodFamily(method), method) trInfo.firstLine.client = true if deadline, ok := ctx.Deadline(); ok { trInfo.firstLine.deadline = deadline.Sub(time.Now()) } trInfo.tr.LazyLog(&trInfo.firstLine, false) ctx = trace.NewContext(ctx, trInfo.tr) defer func() { if err != nil { // Need to call tr.finish() if error is returned. // Because tr will not be returned to caller. trInfo.tr.LazyPrintf("RPC: [%v]", err) trInfo.tr.SetError() trInfo.tr.Finish() } }() } if stats.On() { ctx = stats.TagRPC(ctx, &stats.RPCTagInfo{FullMethodName: method}) begin := &stats.Begin{ Client: true, BeginTime: time.Now(), FailFast: c.failFast, } stats.HandleRPC(ctx, begin) } defer func() { if err != nil && stats.On() { // Only handle end stats if err != nil. end := &stats.End{ Client: true, Error: err, } stats.HandleRPC(ctx, end) } }() gopts := BalancerGetOptions{ BlockingWait: !c.failFast, } for { t, put, err = cc.getTransport(ctx, gopts) if err != nil { // TODO(zhaoq): Probably revisit the error handling. if _, ok := err.(*rpcError); ok { return nil, err } if err == errConnClosing || err == errConnUnavailable { if c.failFast { return nil, Errorf(codes.Unavailable, "%v", err) } continue } // All the other errors are treated as Internal errors. return nil, Errorf(codes.Internal, "%v", err) } s, err = t.NewStream(ctx, callHdr) if err != nil { if put != nil { put() put = nil } if _, ok := err.(transport.ConnectionError); ok || err == transport.ErrStreamDrain { if c.failFast { return nil, toRPCErr(err) } continue } return nil, toRPCErr(err) } break } cs := &clientStream{ opts: opts, c: c, desc: desc, codec: cc.dopts.codec, cp: cc.dopts.cp, dc: cc.dopts.dc, put: put, t: t, s: s, p: &parser{r: s}, tracing: EnableTracing, trInfo: trInfo, statsCtx: ctx, } if cc.dopts.cp != nil { cs.cbuf = new(bytes.Buffer) } // Listen on ctx.Done() to detect cancellation and s.Done() to detect normal termination // when there is no pending I/O operations on this stream. go func() { select { case <-t.Error(): // Incur transport error, simply exit. case <-s.Done(): // TODO: The trace of the RPC is terminated here when there is no pending // I/O, which is probably not the optimal solution. if s.StatusCode() == codes.OK { cs.finish(nil) } else { cs.finish(Errorf(s.StatusCode(), "%s", s.StatusDesc())) } cs.closeTransportStream(nil) case <-s.GoAway(): cs.finish(errConnDrain) cs.closeTransportStream(errConnDrain) case <-s.Context().Done(): err := s.Context().Err() cs.finish(err) cs.closeTransportStream(transport.ContextErr(err)) } }() return cs, nil }
func (s apiServer) requestHandler(w http.ResponseWriter, r *http.Request) { // tracing tr := trace.New(s.serverName, "URL PATH!") defer tr.Finish() // metadata md := metadata.Pairs("traceID", "TRACEID", "fromName", s.serverName) // context ctx := context.Background() ctx = trace.NewContext(ctx, tr) ctx = metadata.NewContext(ctx, md) // grab auth token from request token, err := authtoken.FromRequest(r) if err != nil { http.Error(w, err.Error(), http.StatusForbidden) return } // verify token w/ auth service _, err = s.VerifyToken(ctx, &auth.Request{token}) if err != nil { http.Error(w, "Unauthorized", http.StatusForbidden) return } // read and validate in/out arguments inDate := r.URL.Query().Get("inDate") outDate := r.URL.Query().Get("outDate") if inDate == "" || outDate == "" { http.Error(w, "Please specify inDate / outDate", http.StatusBadRequest) return } // get hotels within geo box geoRes, err := s.BoundedBox(ctx, &geo.Request{ Lo: &geo.Point{Latitude: 400000000, Longitude: -750000000}, Hi: &geo.Point{Latitude: 420000000, Longitude: -730000000}, }) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // make reqeusts for profiles and rates profileCh := s.getProfiles(ctx, geoRes.HotelIds) rateCh := s.getRatePlans(ctx, geoRes.HotelIds, inDate, outDate) // wait on profiles reply profileReply := <-profileCh if err := profileReply.err; err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // wait on rates reply rateReply := <-rateCh if err := rateReply.err; err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // build the final inventory response inventory := inventory{ Hotels: profileReply.hotels, RatePlans: rateReply.ratePlans, } // encode JSON for rendering encoder := json.NewEncoder(w) if err = encoder.Encode(inventory); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } }
// This method is used to execute the query and return the response to the // client as a protocol buffer message. func (s *grpcServer) Query(ctx context.Context, req *graph.Request) (*graph.Response, error) { var allocIds map[string]uint64 if rand.Float64() < *tracing { tr := trace.New("Dgraph", "GrpcQuery") defer tr.Finish() ctx = trace.NewContext(ctx, tr) } resp := new(graph.Response) if len(req.Query) == 0 && req.Mutation == nil { x.TraceError(ctx, x.Errorf("Empty query and mutation.")) return resp, fmt.Errorf("Empty query and mutation.") } var l query.Latency l.Start = time.Now() x.Trace(ctx, "Query received: %v", req.Query) gq, mu, err := gql.Parse(req.Query) if err != nil { x.TraceError(ctx, x.Wrapf(err, "Error while parsing query")) return resp, err } // If mutations are part of the query, we run them through the mutation handler // same as the http client. if mu != nil && (len(mu.Set) > 0 || len(mu.Del) > 0) { if allocIds, err = mutationHandler(ctx, mu); err != nil { x.TraceError(ctx, x.Wrapf(err, "Error while handling mutations")) return resp, err } } // If mutations are sent as part of the mutation object in the request we run // them here. if req.Mutation != nil && (len(req.Mutation.Set) > 0 || len(req.Mutation.Del) > 0) { if allocIds, err = runMutations(ctx, req.Mutation); err != nil { x.TraceError(ctx, x.Wrapf(err, "Error while handling mutations")) return resp, err } } resp.AssignedUids = allocIds if gq == nil || (gq.UID == 0 && len(gq.XID) == 0) { return resp, err } sg, err := query.ToSubGraph(ctx, gq) if err != nil { x.TraceError(ctx, x.Wrapf(err, "Error while conversion to internal format")) return resp, err } l.Parsing = time.Since(l.Start) x.Trace(ctx, "Query parsed") rch := make(chan error) go query.ProcessGraph(ctx, sg, nil, rch) err = <-rch if err != nil { x.TraceError(ctx, x.Wrapf(err, "Error while executing query")) return resp, err } l.Processing = time.Since(l.Start) - l.Parsing x.Trace(ctx, "Graph processed") node, err := sg.ToProtocolBuffer(&l) if err != nil { x.TraceError(ctx, x.Wrapf(err, "Error while converting to ProtocolBuffer")) return resp, err } resp.N = node gl := new(graph.Latency) gl.Parsing, gl.Processing, gl.Pb = l.Parsing.String(), l.Processing.String(), l.ProtocolBuffer.String() resp.L = gl return resp, err }
func queryHandler(w http.ResponseWriter, r *http.Request) { // Add a limit on how many pending queries can be run in the system. pendingQueries <- struct{}{} defer func() { <-pendingQueries }() addCorsHeaders(w) if r.Method == "OPTIONS" { return } if r.Method != "POST" { x.SetStatus(w, x.ErrorInvalidMethod, "Invalid method") return } ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() if rand.Float64() < *tracing { tr := trace.New("Dgraph", "Query") defer tr.Finish() ctx = trace.NewContext(ctx, tr) } var l query.Latency l.Start = time.Now() defer r.Body.Close() req, err := ioutil.ReadAll(r.Body) q := string(req) if err != nil || len(q) == 0 { x.TraceError(ctx, x.Wrapf(err, "Error while reading query")) x.SetStatus(w, x.ErrorInvalidRequest, "Invalid request encountered.") return } x.Trace(ctx, "Query received: %v", q) gq, mu, err := gql.Parse(q) if err != nil { x.TraceError(ctx, x.Wrapf(err, "Error while parsing query")) x.SetStatus(w, x.ErrorInvalidRequest, err.Error()) return } var allocIds map[string]uint64 var allocIdsStr map[string]string // If we have mutations, run them first. if mu != nil && (len(mu.Set) > 0 || len(mu.Del) > 0) { if allocIds, err = mutationHandler(ctx, mu); err != nil { x.TraceError(ctx, x.Wrapf(err, "Error while handling mutations")) x.SetStatus(w, x.Error, err.Error()) return } // convert the new UIDs to hex string. allocIdsStr = make(map[string]string) for k, v := range allocIds { allocIdsStr[k] = fmt.Sprintf("%#x", v) } } if gq == nil || (gq.UID == 0 && gq.Func == nil && len(gq.XID) == 0) { mp := map[string]interface{}{ "code": x.ErrorOk, "message": "Done", "uids": allocIdsStr, } if js, err := json.Marshal(mp); err == nil { w.Write(js) } else { x.SetStatus(w, "Error", "Unable to marshal map") } return } sg, err := query.ToSubGraph(ctx, gq) if err != nil { x.TraceError(ctx, x.Wrapf(err, "Error while conversion o internal format")) x.SetStatus(w, x.ErrorInvalidRequest, err.Error()) return } l.Parsing = time.Since(l.Start) x.Trace(ctx, "Query parsed") rch := make(chan error) go query.ProcessGraph(ctx, sg, nil, rch) err = <-rch if err != nil { x.TraceError(ctx, x.Wrapf(err, "Error while executing query")) x.SetStatus(w, x.Error, err.Error()) return } l.Processing = time.Since(l.Start) - l.Parsing x.Trace(ctx, "Graph processed") if len(*dumpSubgraph) > 0 { x.Checkf(os.MkdirAll(*dumpSubgraph, 0700), *dumpSubgraph) s := time.Now().Format("20060102.150405.000000.gob") filename := path.Join(*dumpSubgraph, s) f, err := os.Create(filename) x.Checkf(err, filename) enc := gob.NewEncoder(f) x.Check(enc.Encode(sg)) x.Checkf(f.Close(), filename) } js, err := sg.ToJSON(&l) if err != nil { x.TraceError(ctx, x.Wrapf(err, "Error while converting to Json")) x.SetStatus(w, x.Error, err.Error()) return } x.Trace(ctx, "Latencies: Total: %v Parsing: %v Process: %v Json: %v", time.Since(l.Start), l.Parsing, l.Processing, l.Json) w.Header().Set("Content-Type", "application/json") w.Write(js) }
// NewClientStream creates a new Stream for the client side. This is called // by generated code. func NewClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, opts ...CallOption) (ClientStream, error) { var ( t transport.ClientTransport s *transport.Stream err error put func() ) c := defaultCallInfo for _, o := range opts { if err := o.before(&c); err != nil { return nil, toRPCErr(err) } } callHdr := &transport.CallHdr{ Host: cc.authority, Method: method, Flush: desc.ServerStreams && desc.ClientStreams, } if cc.dopts.cp != nil { callHdr.SendCompress = cc.dopts.cp.Type() } cs := &clientStream{ opts: opts, c: c, desc: desc, codec: cc.dopts.codec, cp: cc.dopts.cp, dc: cc.dopts.dc, tracing: EnableTracing, } if cc.dopts.cp != nil { callHdr.SendCompress = cc.dopts.cp.Type() cs.cbuf = new(bytes.Buffer) } if cs.tracing { cs.trInfo.tr = trace.New("grpc.Sent."+methodFamily(method), method) cs.trInfo.firstLine.client = true if deadline, ok := ctx.Deadline(); ok { cs.trInfo.firstLine.deadline = deadline.Sub(time.Now()) } cs.trInfo.tr.LazyLog(&cs.trInfo.firstLine, false) ctx = trace.NewContext(ctx, cs.trInfo.tr) } gopts := BalancerGetOptions{ BlockingWait: !c.failFast, } for { t, put, err = cc.getTransport(ctx, gopts) if err != nil { // TODO(zhaoq): Probably revisit the error handling. if _, ok := err.(*rpcError); ok { return nil, err } if err == errConnClosing { if c.failFast { return nil, Errorf(codes.Unavailable, "%v", errConnClosing) } continue } // All the other errors are treated as Internal errors. return nil, Errorf(codes.Internal, "%v", err) } s, err = t.NewStream(ctx, callHdr) if err != nil { if put != nil { put() put = nil } if _, ok := err.(transport.ConnectionError); ok { if c.failFast { cs.finish(err) return nil, toRPCErr(err) } continue } return nil, toRPCErr(err) } break } cs.put = put cs.t = t cs.s = s cs.p = &parser{r: s} // Listen on ctx.Done() to detect cancellation and s.Done() to detect normal termination // when there is no pending I/O operations on this stream. go func() { select { case <-t.Error(): // Incur transport error, simply exit. case <-s.Done(): // TODO: The trace of the RPC is terminated here when there is no pending // I/O, which is probably not the optimal solution. if s.StatusCode() == codes.OK { cs.finish(nil) } else { cs.finish(Errorf(s.StatusCode(), "%s", s.StatusDesc())) } cs.closeTransportStream(nil) case <-s.Context().Done(): err := s.Context().Err() cs.finish(err) cs.closeTransportStream(transport.ContextErr(err)) } }() return cs, nil }
func (s *Hotel) Rates(ctx context.Context, req *hotel.Request, rsp *hotel.Response) error { // tracing tr := trace.New("api.v1", "Hotel.Rates") defer tr.Finish() // context ctx = trace.NewContext(ctx, tr) md, ok := metadata.FromContext(ctx) if !ok { md = metadata.Metadata{} } // add a unique request id to context if traceID, err := uuid.NewV4(); err == nil { // make copy tmd := metadata.Metadata{} for k, v := range md { tmd[k] = v } tmd["traceID"] = traceID.String() tmd["fromName"] = "api.v1" ctx = metadata.NewContext(ctx, tmd) } // token from request headers token, err := getToken(md) if err != nil { return merr.Forbidden("api.hotel.rates", err.Error()) } // verify token w/ auth service authClient := auth.NewAuthClient("go.micro.srv.auth", s.Client) if _, err = authClient.VerifyToken(ctx, &auth.Request{AuthToken: token}); err != nil { return merr.Unauthorized("api.hotel.rates", "Unauthorized") } // checkin and checkout date query params inDate, outDate := req.InDate, req.OutDate if inDate == "" || outDate == "" { return merr.BadRequest("api.hotel.rates", "Please specify inDate/outDate params") } // finds nearby hotels // TODO(hw): use lat/lon from request params geoClient := geo.NewGeoClient("go.micro.srv.geo", s.Client) nearby, err := geoClient.Nearby(ctx, &geo.Request{ Lat: 51.502973, Lon: -0.114723, }) if err != nil { return merr.InternalServerError("api.hotel.rates", err.Error()) } // make reqeusts for profiles and rates profileCh := getHotelProfiles(s.Client, ctx, nearby.HotelIds) rateCh := getRatePlans(s.Client, ctx, nearby.HotelIds, inDate, outDate) // wait on profiles reply profileReply := <-profileCh if err := profileReply.err; err != nil { return merr.InternalServerError("api.hotel.rates", err.Error()) } // wait on rates reply rateReply := <-rateCh if err := rateReply.err; err != nil { return merr.InternalServerError("api.hotel.rates", err.Error()) } rsp.Hotels = profileReply.hotels rsp.RatePlans = rateReply.ratePlans return nil }
// operateHeader takes action on the decoded headers. It returns the current // stream if there are remaining headers on the wire (in the following // Continuation frame). func (t *http2Server) operateHeaders(hDec *hpackDecoder, s *Stream, frame headerFrame, endStream bool, handle func(*Stream), wg *sync.WaitGroup) (pendingStream *Stream) { defer func() { if pendingStream == nil { hDec.state = decodeState{} } }() endHeaders, err := hDec.decodeServerHTTP2Headers(frame) if s == nil { // s has been closed. return nil } if err != nil { grpclog.Printf("transport: http2Server.operateHeader found %v", err) if se, ok := err.(StreamError); ok { t.controlBuf.put(&resetStream{s.id, statusCodeConvTab[se.Code]}) } return nil } if endStream { // s is just created by the caller. No lock needed. s.state = streamReadDone } if !endHeaders { return s } t.mu.Lock() if t.state != reachable { t.mu.Unlock() return nil } if uint32(len(t.activeStreams)) >= t.maxStreams { t.mu.Unlock() t.controlBuf.put(&resetStream{s.id, http2.ErrCodeRefusedStream}) return nil } s.sendQuotaPool = newQuotaPool(int(t.streamSendQuota)) t.activeStreams[s.id] = s t.mu.Unlock() s.windowHandler = func(n int) { t.updateWindow(s, uint32(n)) } if hDec.state.timeoutSet { s.ctx, s.cancel = context.WithTimeout(context.TODO(), hDec.state.timeout) } else { s.ctx, s.cancel = context.WithCancel(context.TODO()) } // Attach Auth info if there is any. if t.authInfo != nil { s.ctx = credentials.NewContext(s.ctx, t.authInfo) } // Cache the current stream to the context so that the server application // can find out. Required when the server wants to send some metadata // back to the client (unary call only). s.ctx = newContextWithStream(s.ctx, s) // Attach the received metadata to the context. if len(hDec.state.mdata) > 0 { s.ctx = metadata.NewContext(s.ctx, hDec.state.mdata) } s.dec = &recvBufferReader{ ctx: s.ctx, recv: s.buf, } s.method = hDec.state.method if t.tracing { s.tr = trace.New("grpc.Recv."+MethodFamily(s.method), s.method) s.ctx = trace.NewContext(s.ctx, s.tr) } wg.Add(1) go func() { handle(s) wg.Done() }() return nil }