Example #1
1
func (l *labelWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
	md, _ := metadata.FromContext(ctx)

	labels := make(map[string]string)

	for k, v := range md {
		if strings.HasPrefix(k, LabelPrefix) {
			key := strings.TrimPrefix(k, LabelPrefix)
			key = strings.ToLower(key)
			labels[key] = strings.ToLower(v)
		}
	}

	filter := func(services []*registry.Service) []*registry.Service {
		var filtered []*registry.Service

	SERVICE:
		for _, service := range services {
			// check labels for the service
			for lk, lv := range labels {
				// if we match then append the service and return
				if v := service.Metadata[lk]; v == lv {
					filtered = append(filtered, service)
					continue SERVICE
				}
			}

			var nodes []*registry.Node

		NODE:
			for _, node := range service.Nodes {
				// check labels against the node
				for lk, lv := range labels {
					// if it matches then append node
					if v := node.Metadata[lk]; v == lv {
						nodes = append(nodes, node)
						continue NODE
					}
				}
			}

			if len(nodes) > 0 {
				service.Nodes = nodes
				filtered = append(filtered, service)
			}
		}

		return filtered
	}

	callOptions := append(opts, client.WithSelectOption(
		selector.Filter(filter),
	))

	return l.Client.Call(ctx, req, rsp, callOptions...)
}
Example #2
0
// getSegment creates a new segment based on whether we're part of an existing flow
func getSegment(name string, ctx context.Context) *awsxray.Segment {
	md, _ := metadata.FromContext(ctx)
	parentId := getParentId(md)
	traceId := getTraceId(md)

	// try get existing segment for parent Id
	if s, ok := awsxray.FromContext(ctx); ok {
		// only set existing segment as parent if its not a subsegment itself
		if len(parentId) == 0 && len(s.Type) == 0 {
			parentId = s.Id
		}
		if len(traceId) == 0 {
			traceId = s.TraceId
		}
	}

	// create segment
	s := &awsxray.Segment{
		Id:        fmt.Sprintf("%x", getRandom(8)),
		Name:      name,
		TraceId:   traceId,
		StartTime: float64(time.Now().Truncate(time.Millisecond).UnixNano()) / 1e9,
	}

	// we have a parent so subsegment
	if len(parentId) > 0 {
		s.ParentId = parentId
		s.Type = "subsegment"
	}

	return s
}
Example #3
0
File: main.go Project: micro/micro
// Nearby returns all hotels within a given distance.
func (s *Geo) Nearby(ctx context.Context, req *geo.Request, rsp *geo.Result) error {
	md, _ := metadata.FromContext(ctx)
	traceID := md["traceID"]

	if tr, ok := trace.FromContext(ctx); ok {
		tr.LazyPrintf("traceID %s", traceID)
	}

	// create center point for query
	center := &geoindex.GeoPoint{
		Pid:  "",
		Plat: float64(req.Lat),
		Plon: float64(req.Lon),
	}

	// find points around center point
	points := s.index.KNearest(center, maxSearchResults, geoindex.Km(maxSearchRadius), func(p geoindex.Point) bool {
		return true
	})

	for _, p := range points {
		rsp.HotelIds = append(rsp.HotelIds, p.Id())
	}
	return nil
}
Example #4
0
func (g *grpcClient) Publish(ctx context.Context, p client.Publication, opts ...client.PublishOption) error {
	md, ok := metadata.FromContext(ctx)
	if !ok {
		md = make(map[string]string)
	}
	md["Content-Type"] = p.ContentType()

	cf, err := g.newCodec(p.ContentType())
	if err != nil {
		return errors.InternalServerError("go.micro.client", err.Error())
	}

	b := &buffer{bytes.NewBuffer(nil)}
	if err := cf(b).Write(&codec.Message{Type: codec.Publication}, p.Message()); err != nil {
		return errors.InternalServerError("go.micro.client", err.Error())
	}

	g.once.Do(func() {
		g.opts.Broker.Connect()
	})

	return g.opts.Broker.Publish(p.Topic(), &broker.Message{
		Header: md,
		Body:   b.Bytes(),
	})
}
Example #5
0
func TestRequestToContext(t *testing.T) {
	testData := []struct {
		request *http.Request
		expect  metadata.Metadata
	}{
		{
			&http.Request{
				Header: http.Header{
					"foo1": []string{"bar"},
					"foo2": []string{"bar", "baz"},
				},
			},
			metadata.Metadata{
				"foo1": "bar",
				"foo2": "bar,baz",
			},
		},
	}

	for _, d := range testData {
		ctx := RequestToContext(d.request)
		md, ok := metadata.FromContext(ctx)
		if !ok {
			t.Fatalf("Expected metadata for request %+v", d.request)
		}
		for k, v := range d.expect {
			if val := md[k]; val != v {
				t.Fatal("Expected %s for key %s for expected md %+v, got md %+v", v, k, d.expect, md)
			}
		}
	}
}
Example #6
0
func (p *platform) Introspect(ctx context.Context) (*Token, error) {
	t, ok := p.FromContext(ctx)
	if !ok {
		md, kk := metadata.FromContext(ctx)
		if !kk {
			return nil, ErrInvalidToken
		}
		t, ok = p.FromHeader(md)
		if !ok {
			return nil, ErrInvalidToken
		}
	}

	rsp, err := p.c.Introspect(context.TODO(), &oauth2.IntrospectRequest{
		AccessToken: t.AccessToken,
	})
	if err != nil {
		return nil, err
	}

	// if its not active just err?
	if !rsp.Active {
		return nil, ErrInvalidToken
	}

	return &Token{
		AccessToken:  rsp.Token.AccessToken,
		RefreshToken: rsp.Token.RefreshToken,
		TokenType:    rsp.Token.TokenType,
		ExpiresAt:    time.Unix(rsp.Token.ExpiresAt, 0),
		Scopes:       rsp.Token.Scopes,
		Metadata:     rsp.Token.Metadata,
	}, nil
}
Example #7
0
func handlerWrapper(fn server.HandlerFunc, t Trace, s *registry.Service) server.HandlerFunc {
	return func(ctx context.Context, req server.Request, rsp interface{}) error {
		// embed trace instance
		newCtx := NewContext(ctx, t)

		var span *Span
		var err error

		// Expectation is that we're the initiator of tracing
		// So get trace info from metadata
		md, ok := metadata.FromContext(ctx)
		if !ok {
			// this is a new span
			span = t.NewSpan(nil)
			span.Debug = true
		} else {
			// can we gt the span from the header?
			span, ok = t.FromHeader(md)
			if !ok {
				// no, ok create one
				span = t.NewSpan(nil)
			}
			span.Timestamp = time.Time{}
			span.Debug = true
		}

		// mark client request
		span.Annotations = append(span.Annotations, &Annotation{
			Timestamp: time.Now(),
			Type:      AnnServerRequest,
			Service:   s,
		})

		// embed the span in the context
		newCtx = t.NewContext(newCtx, span)

		// defer the completion of the span
		defer func() {
			var debug map[string]string
			if err != nil {
				debug = map[string]string{"error": err.Error()}
			}
			// mark server response
			span.Annotations = append(span.Annotations, &Annotation{
				Timestamp: time.Now(),
				Type:      AnnServerResponse,
				Service:   s,
				Debug:     debug,
			})
			// flush the span to the collector on return
			t.Collect(span)
		}()
		err = fn(newCtx, req, rsp)
		return err
	}
}
Example #8
0
func (r *rpcClient) stream(ctx context.Context, address string, req Request, opts CallOptions) (Streamer, error) {
	msg := &transport.Message{
		Header: make(map[string]string),
	}

	md, ok := metadata.FromContext(ctx)
	if ok {
		for k, v := range md {
			msg.Header[k] = v
		}
	}

	// set timeout in nanoseconds
	msg.Header["Timeout"] = fmt.Sprintf("%d", opts.RequestTimeout)
	// set the content type for the request
	msg.Header["Content-Type"] = req.ContentType()

	cf, err := r.newCodec(req.ContentType())
	if err != nil {
		return nil, errors.InternalServerError("go.micro.client", err.Error())
	}

	c, err := r.opts.Transport.Dial(address, transport.WithStream(), transport.WithTimeout(opts.DialTimeout))
	if err != nil {
		return nil, errors.InternalServerError("go.micro.client", fmt.Sprintf("Error sending request: %v", err))
	}

	stream := &rpcStream{
		context: ctx,
		request: req,
		closed:  make(chan bool),
		codec:   newRpcPlusCodec(msg, c, cf),
	}

	ch := make(chan error, 1)

	go func() {
		ch <- stream.Send(req.Request())
	}()

	var grr error

	select {
	case err := <-ch:
		grr = err
	case <-ctx.Done():
		grr = errors.New("go.micro.client", fmt.Sprintf("%v", ctx.Err()), 408)
	}

	if grr != nil {
		stream.Close()
		return nil, grr
	}

	return stream, nil
}
Example #9
0
File: main.go Project: micro/micro
// GetProfiles returns hotel profiles for requested IDs
func (s *Profile) GetProfiles(ctx context.Context, req *profile.Request, rsp *profile.Result) error {
	md, _ := metadata.FromContext(ctx)
	traceID := md["traceID"]
	if tr, ok := trace.FromContext(ctx); ok {
		tr.LazyPrintf("traceID %s", traceID)
	}

	for _, i := range req.HotelIds {
		rsp.Hotels = append(rsp.Hotels, s.hotels[i])
	}
	return nil
}
Example #10
0
func (c *clientWrapper) setHeaders(ctx context.Context) context.Context {
	md, ok := metadata.FromContext(ctx)
	if !ok {
		md = metadata.Metadata{}
	}
	for k, v := range c.headers {
		if _, ok := md[k]; !ok {
			md[k] = v
		}
	}
	return metadata.NewContext(ctx, md)
}
Example #11
0
File: main.go Project: micro/micro
// VerifyToken returns a customer from authentication token.
func (s *Auth) VerifyToken(ctx context.Context, req *auth.Request, rsp *auth.Result) error {
	md, _ := metadata.FromContext(ctx)
	traceID := md["traceID"]

	if tr, ok := trace.FromContext(ctx); ok {
		tr.LazyPrintf("traceID %s", traceID)
	}

	customer := s.customers[req.AuthToken]
	if customer == nil {
		return errors.New("Invalid Token")
	}

	rsp.Customer = customer
	return nil
}
Example #12
0
func (g *grpcClient) stream(ctx context.Context, address string, req client.Request, opts client.CallOptions) (client.Streamer, error) {
	header := make(map[string]string)
	if md, ok := metadata.FromContext(ctx); ok {
		for k, v := range md {
			header[k] = v
		}
	}

	// set timeout in nanoseconds
	header["timeout"] = fmt.Sprintf("%d", opts.RequestTimeout)
	// set the content type for the request
	header["x-content-type"] = req.ContentType()

	md := gmetadata.New(header)
	ctx = gmetadata.NewContext(ctx, md)

	cf, err := g.newGRPCCodec(req.ContentType())
	if err != nil {
		return nil, errors.InternalServerError("go.micro.client", err.Error())
	}

	// TODO: do not use insecure
	cc, err := grpc.Dial(address, grpc.WithCodec(cf), grpc.WithTimeout(opts.DialTimeout), grpc.WithInsecure())
	if err != nil {
		return nil, errors.InternalServerError("go.micro.client", fmt.Sprintf("Error sending request: %v", err))
	}

	desc := &grpc.StreamDesc{
		StreamName:    req.Service() + req.Method(),
		ClientStreams: true,
		ServerStreams: true,
	}

	st, err := grpc.NewClientStream(ctx, desc, cc, req.Method())
	if err != nil {
		return nil, errors.InternalServerError("go.micro.client", fmt.Sprintf("Error creating stream: %v", err))
	}

	return &grpcStream{
		context: ctx,
		request: req,
		closed:  make(chan bool),
		stream:  st,
		conn:    cc,
	}, nil
}
Example #13
0
func (t *TestHandler) Exec(ctx context.Context, req *TestRequest, rsp *TestResponse) error {
	md, ok := metadata.FromContext(ctx)
	if !ok {
		return fmt.Errorf("Expected metadata got %t", ok)
	}

	for k, v := range t.expect {
		if val := md[k]; val != v {
			return fmt.Errorf("Expected %s for key %s got %s", v, k, val)
		}
	}

	t.t.Logf("Received request %+v", req)
	t.t.Logf("Received metadata %+v", md)

	return nil
}
Example #14
0
func (o *otWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
	md, _ := metadata.FromContext(ctx)
	name := fmt.Sprintf("%s.%s", req.Service(), req.Method())
	var sp opentracing.Span
	wireContext, err := o.ot.Extract(opentracing.TextMap, opentracing.TextMapCarrier(md))
	if err != nil {
		sp = o.ot.StartSpan(name)
	} else {
		sp = o.ot.StartSpan(name, opentracing.ChildOf(wireContext))
	}
	defer sp.Finish()
	if err := sp.Tracer().Inject(sp.Context(), opentracing.TextMap, opentracing.TextMapCarrier(md)); err != nil {
		return err
	}
	ctx = metadata.NewContext(ctx, md)
	return o.Client.Call(ctx, req, rsp, opts...)
}
Example #15
0
func TestWrapper(t *testing.T) {
	testData := []struct {
		existing  metadata.Metadata
		headers   metadata.Metadata
		overwrite bool
	}{
		{
			existing: metadata.Metadata{},
			headers: metadata.Metadata{
				"foo": "bar",
			},
			overwrite: true,
		},
		{
			existing: metadata.Metadata{
				"foo": "bar",
			},
			headers: metadata.Metadata{
				"foo": "baz",
			},
			overwrite: false,
		},
	}

	for _, d := range testData {
		c := &clientWrapper{
			headers: d.headers,
		}

		ctx := metadata.NewContext(context.Background(), d.existing)
		c.setHeaders(ctx)

		md, _ := metadata.FromContext(ctx)

		for k, v := range d.headers {
			if d.overwrite && md[k] != v {
				t.Fatalf("Expected %s=%s got %s=%s", k, v, k, md[k])
			}
			if !d.overwrite && md[k] != d.existing[k] {
				t.Fatalf("Expected %s=%s got %s=%s", k, d.existing[k], k, md[k])
			}
		}
	}

}
Example #16
0
func (g *grpcClient) call(ctx context.Context, address string, req client.Request, rsp interface{}, opts client.CallOptions) error {
	header := make(map[string]string)
	if md, ok := metadata.FromContext(ctx); ok {
		for k, v := range md {
			header[k] = v
		}
	}

	// set timeout in nanoseconds
	header["timeout"] = fmt.Sprintf("%d", opts.RequestTimeout)
	// set the content type for the request
	header["x-content-type"] = req.ContentType()

	md := gmetadata.New(header)
	ctx = gmetadata.NewContext(ctx, md)

	cf, err := g.newGRPCCodec(req.ContentType())
	if err != nil {
		return errors.InternalServerError("go.micro.client", err.Error())
	}

	var grr error
	// TODO: do not use insecure
	cc, err := grpc.Dial(address, grpc.WithCodec(cf), grpc.WithTimeout(opts.DialTimeout), grpc.WithInsecure())
	if err != nil {
		return errors.InternalServerError("go.micro.client", fmt.Sprintf("Error sending request: %v", err))
	}
	defer cc.Close()

	ch := make(chan error, 1)

	go func() {
		ch <- grpc.Invoke(ctx, req.Method(), req.Request(), rsp, cc)
	}()

	select {
	case err := <-ch:
		grr = err
	case <-ctx.Done():
		grr = ctx.Err()
	}

	return grr
}
Example #17
0
File: main.go Project: micro/micro
// GetRates gets rates for hotels for specific date range.
func (s *Rate) GetRates(ctx context.Context, req *rate.Request, rsp *rate.Result) error {
	md, _ := metadata.FromContext(ctx)
	traceID := md["traceID"]

	if tr, ok := trace.FromContext(ctx); ok {
		tr.LazyPrintf("traceID %s", traceID)
	}

	for _, hotelID := range req.HotelIds {
		stay := stay{
			HotelID: hotelID,
			InDate:  req.InDate,
			OutDate: req.OutDate,
		}
		if s.rateTable[stay] != nil {
			rsp.RatePlans = append(rsp.RatePlans, s.rateTable[stay])
		}
	}
	return nil
}
Example #18
0
func newContext(ctx context.Context, s *awsxray.Segment) context.Context {
	md, _ := metadata.FromContext(ctx)

	// make copy to avoid races
	newMd := metadata.Metadata{}
	for k, v := range md {
		newMd[k] = v
	}

	// set trace id in header
	newMd[awsxray.TraceHeader] = awsxray.SetTraceId(newMd[awsxray.TraceHeader], s.TraceId)
	// set parent id in header
	newMd[awsxray.TraceHeader] = awsxray.SetParentId(newMd[awsxray.TraceHeader], s.ParentId)
	// store segment in context
	ctx = awsxray.NewContext(ctx, s)
	// store metadata in context
	ctx = metadata.NewContext(ctx, newMd)

	return ctx
}
Example #19
0
// NewHandlerWrapper accepts an opentracing Tracer and returns a Handler Wrapper
func NewHandlerWrapper(ot opentracing.Tracer) server.HandlerWrapper {
	return func(h server.HandlerFunc) server.HandlerFunc {
		return func(ctx context.Context, req server.Request, rsp interface{}) error {
			md, _ := metadata.FromContext(ctx)
			name := fmt.Sprintf("%s.%s", req.Service(), req.Method())
			var sp opentracing.Span
			wireContext, err := ot.Extract(opentracing.TextMap, opentracing.TextMapCarrier(md))
			if err != nil {
				sp = ot.StartSpan(name)
			} else {
				sp = ot.StartSpan(name, opentracing.ChildOf(wireContext))
			}
			defer sp.Finish()
			if err := sp.Tracer().Inject(sp.Context(), opentracing.TextMap, opentracing.TextMapCarrier(md)); err != nil {
				return err
			}
			ctx = metadata.NewContext(ctx, md)
			return h(ctx, req, rsp)
		}
	}
}
Example #20
0
func (c *clientWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
	// retrieve token if one exists
	t, err := c.a.Introspect(ctx)
	if err != nil {
		// no? ok let's try make the call as ourself
		t, err = c.a.Token()
		if err != nil {
			return err
		}
	}

	// create new context with token
	newCtx := ContextWithToken(ctx, t)

	// get metadata
	md, ok := metadata.FromContext(newCtx)
	if !ok {
		md = metadata.Metadata{}
	}

	// set auth headers
	for k, v := range HeaderWithToken(map[string]string{}, t) {
		md[k] = v
	}

	// set metadata
	newCtx = metadata.NewContext(newCtx, md)

	// circuit break, check authorization here
	t, err = c.a.Authorized(newCtx, req)
	if err != nil {
		return ErrInvalidToken
	}

	// now just make a regular call down the stack
	err = c.Client.Call(newCtx, req, rsp, opts...)
	return err
}
Example #21
0
func (dc *dcWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
	md, _ := metadata.FromContext(ctx)

	filter := func(services []*registry.Service) []*registry.Service {
		for _, service := range services {
			var nodes []*registry.Node
			for _, node := range service.Nodes {
				if node.Metadata["datacenter"] == md["datacenter"] {
					nodes = append(nodes, node)
				}
			}
			service.Nodes = nodes
		}
		return services
	}

	callOptions := append(opts, client.WithSelectOption(
		selector.WithFilter(filter),
	))

	fmt.Printf("[DC Wrapper] filtering for datacenter %s\n", md["datacenter"])
	return dc.Client.Call(ctx, req, rsp, callOptions...)
}
Example #22
0
File: main.go Project: micro/micro
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
}
Example #23
0
func (c *clientWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
	var span *Span
	var ok, okk bool
	var err error
	md := metadata.Metadata{}

	// try pull span from context
	span, ok = c.t.FromContext(ctx)
	if !ok {
		// couldn't do that, try from the metadata

		// So get trace info from metadata
		var kk bool
		md, kk = metadata.FromContext(ctx)
		if !kk {
			// couldn't do that either

			// so this is a new span!
			md = metadata.Metadata{}
			span = c.t.NewSpan(nil)
		} else {
			// ok we got some md

			// can we get the span from the header?
			span, okk = c.t.FromHeader(md)
			if !okk {
				// no, ok create one!
				span = c.t.NewSpan(nil)
			}
		}
	}

	// got parent span from context or metadata
	if okk || ok {
		// setup the span with parent
		span = c.t.NewSpan(&Span{
			// same trace id
			TraceId: span.TraceId,
			// set parent id to parent span id
			ParentId: span.Id,
			// use previous debug
			Debug: span.Debug,
		})
	}

	// start the span
	span.Annotations = append(span.Annotations, &Annotation{
		Timestamp: time.Now(),
		Type:      AnnStart,
		Service:   c.s,
	})

	// and mark as debug? might want to do this based on a setting
	span.Debug = true
	// set uniq span name
	span.Name = req.Service() + "." + req.Method()
	// set source/dest
	span.Source = c.s
	span.Destination = &registry.Service{Name: req.Service()}

	// set context key
	newCtx := c.t.NewContext(ctx, span)
	// set metadata
	newCtx = metadata.NewContext(newCtx, c.t.NewHeader(md, span))

	// mark client request
	span.Annotations = append(span.Annotations, &Annotation{
		Timestamp: time.Now(),
		Type:      AnnClientRequest,
		Service:   c.s,
	})

	// defer the completion of the span
	defer func() {
		// mark client response
		span.Annotations = append(span.Annotations, &Annotation{
			Timestamp: time.Now(),
			Type:      AnnClientResponse,
			Service:   c.s,
		})

		// if we were the creator
		var debug map[string]string
		if err != nil {
			debug = map[string]string{"error": err.Error()}
		}
		// mark end of span
		span.Annotations = append(span.Annotations, &Annotation{
			Timestamp: time.Now(),
			Type:      AnnEnd,
			Service:   c.s,
			Debug:     debug,
		})

		span.Duration = time.Now().Sub(span.Timestamp)

		// flush the span to the collector on return
		c.t.Collect(span)
	}()

	// now just make a regular call down the stack
	err = c.Client.Call(newCtx, req, rsp, opts...)
	return err
}
Example #24
0
func handlerWrapper(fn server.HandlerFunc, t Trace, s *registry.Service) server.HandlerFunc {
	return func(ctx context.Context, req server.Request, rsp interface{}) error {
		// embed trace instance
		newCtx := NewContext(ctx, t)

		var span *Span
		var err error

		// get trace info from metadata
		md, ok := metadata.FromContext(ctx)
		if !ok {
			// this is a new span
			span = t.NewSpan(nil)
		} else {
			// can we gt the span from the header?
			span, ok = t.FromHeader(md)
			if !ok {
				// no, ok create one
				span = t.NewSpan(nil)
			}
		}

		// mark client request
		span.Annotations = append(span.Annotations, &Annotation{
			Timestamp: time.Now(),
			Type:      AnnServerRequest,
			Service:   s,
		})

		// and mark as debug? might want to do this based on a setting
		span.Debug = true
		// set unique span name
		span.Name = req.Service() + "." + req.Method()
		// set source/dest
		span.Source = s
		span.Destination = &registry.Service{Name: req.Service()}

		// embed the span in the context
		newCtx = t.NewContext(newCtx, span)

		// defer the completion of the span
		defer func() {
			var debug map[string]string
			if err != nil {
				debug = map[string]string{"error": err.Error()}
			}
			// mark server response
			span.Annotations = append(span.Annotations, &Annotation{
				Timestamp: time.Now(),
				Type:      AnnServerResponse,
				Service:   s,
				Debug:     debug,
			})

			span.Duration = time.Now().Sub(span.Timestamp)

			// flush the span to the collector on return
			t.Collect(span)
		}()
		err = fn(newCtx, req, rsp)
		return err
	}
}
Example #25
0
func (e *Example) Call(ctx context.Context, req *example.Request, rsp *example.Response) error {
	md, _ := metadata.FromContext(ctx)
	log.Printf("Received Example.Call request with metadata: %v", md)
	rsp.Msg = server.DefaultOptions().Id + ": Hello " + req.Name
	return nil
}
Example #26
0
func (l *logWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
	md, _ := metadata.FromContext(ctx)
	fmt.Printf("[Log Wrapper] ctx: %v service: %s method: %s\n", md, req.Service(), req.Method())
	return l.Client.Call(ctx, req, rsp)
}
Example #27
0
func (r *rpcClient) call(ctx context.Context, address string, req Request, resp interface{}, opts CallOptions) error {
	msg := &transport.Message{
		Header: make(map[string]string),
	}

	md, ok := metadata.FromContext(ctx)
	if ok {
		for k, v := range md {
			msg.Header[k] = v
		}
	}

	// set timeout in nanoseconds
	msg.Header["Timeout"] = fmt.Sprintf("%d", opts.RequestTimeout)
	// set the content type for the request
	msg.Header["Content-Type"] = req.ContentType()

	cf, err := r.newCodec(req.ContentType())
	if err != nil {
		return errors.InternalServerError("go.micro.client", err.Error())
	}

	var grr error
	c, err := r.pool.getConn(address, r.opts.Transport, transport.WithTimeout(opts.DialTimeout))
	if err != nil {
		return errors.InternalServerError("go.micro.client", fmt.Sprintf("Error sending request: %v", err))
	}
	defer func() {
		// defer execution of release
		r.pool.release(address, c, grr)
	}()

	stream := &rpcStream{
		context: ctx,
		request: req,
		closed:  make(chan bool),
		codec:   newRpcPlusCodec(msg, c, cf),
	}
	defer stream.Close()

	ch := make(chan error, 1)

	go func() {
		defer func() {
			if r := recover(); r != nil {
				ch <- errors.InternalServerError("go.micro.client", "request error")
			}
		}()

		// send request
		if err := stream.Send(req.Request()); err != nil {
			ch <- err
			return
		}

		// recv request
		if err := stream.Recv(resp); err != nil {
			ch <- err
			return
		}

		// success
		ch <- nil
	}()

	select {
	case err := <-ch:
		grr = err
		return err
	case <-ctx.Done():
		grr = ctx.Err()
		return errors.New("go.micro.client", fmt.Sprintf("%v", ctx.Err()), 408)
	}
}