apmgokit

package module
v1.15.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 8, 2021 License: Apache-2.0 Imports: 0 Imported by: 0

README

apmgokit

Package apmgokit provides examples and integration tests for tracing services implemented with Go kit.

We do not provide any Go kit specific code, as the other generic modules (module/apmhttp and module/apmgrpc) are sufficient.

Go kit-based HTTP servers can be traced by instrumenting the kit/transport/http.Server with apmhttp.Wrap, and HTTP clients can be traced by providing a net/http.Client instrumented with apmhttp.WrapClient.

Go kit-based gRPC servers and clients can both be wrapped using the interceptors provided in module/apmgrpc.

Documentation

Overview

Package apmgokit provides examples and integration tests for tracing services implemented with Go kit.

We do not provide any Go kit specific code, as the other generic modules (apmhttp and apmgrpc) are sufficient.

Go kit-based HTTP servers can be traced by instrumenting the kit/transport/http.Server with apmhttp.Wrap, and HTTP clients can be traced by providing a net/http.Client instrumented with apmhttp.WrapClient.

Go kit-based gRPC servers and clients can both be wrapped using the interceptors provided in module/apmgrpc.

Example (GrpcClient)
package main

import (
	"context"

	kitgrpc "github.com/go-kit/kit/transport/grpc"
	"google.golang.org/grpc"

	pb "google.golang.org/grpc/examples/helloworld/helloworld"

	"go.elastic.co/apm"
	"go.elastic.co/apm/module/apmgrpc"
)

func main() {
	// When dialling the gRPC client connection, use the apmgrpc.NewUnaryClientInterceptor
	// function (from module/apmgrpc). This will trace all outgoing requests, as long as
	// the context supplied to methods include an apm.Transaction.
	conn, err := grpc.Dial("localhost:1234", grpc.WithUnaryInterceptor(apmgrpc.NewUnaryClientInterceptor()))
	if err != nil {
		panic(err)
	}
	defer conn.Close()

	// Create your go-kit/kit/transport/grpc.Client as usual, without any tracing middleware.
	client := kitgrpc.NewClient(
		conn, "helloworld.Greeter", "SayHello",
		func(ctx context.Context, req interface{}) (interface{}, error) {
			return &pb.HelloRequest{Name: req.(string)}, nil
		},
		func(ctx context.Context, resp interface{}) (interface{}, error) {
			return resp, nil
		},
		&pb.HelloReply{},
	)

	tx := apm.DefaultTracer.StartTransaction("name", "type")
	ctx := apm.ContextWithTransaction(context.Background(), tx)
	defer tx.End()

	_, err = client.Endpoint()(ctx, "world")
	if err != nil {
		panic(err)
	}
}
Output:

Example (GrpcServer)
package main

import (
	"context"
	"net"

	kitgrpc "github.com/go-kit/kit/transport/grpc"

	netcontext "golang.org/x/net/context"
	"google.golang.org/grpc"

	pb "google.golang.org/grpc/examples/helloworld/helloworld"

	"go.elastic.co/apm"
	"go.elastic.co/apm/module/apmgrpc"
)

func main() {
	// Create your go-kit/kit/transport/grpc.Server as usual, without any tracing middleware.
	endpoint := func(ctx context.Context, req interface{}) (interface{}, error) {
		// The middleware added to the underlying gRPC server will be propagate
		// a transaction to the context passed to your endpoint. You can then
		// report endpoint-specific spans using apm.StartSpan.
		span, ctx := apm.StartSpan(ctx, "name", "endpoint")
		defer span.End()
		return nil, nil
	}
	var encodeRequest func(ctx context.Context, req interface{}) (interface{}, error)
	var decodeResponse func(ctx context.Context, req interface{}) (interface{}, error)
	service := &helloWorldService{kitgrpc.NewServer(
		endpoint,
		encodeRequest,
		decodeResponse,
	)}

	// When creating the underlying gRPC server, use the apmgrpc.NewUnaryServerInterceptor
	// function (from module/apmgrpc). This will trace all incoming requests.
	s := grpc.NewServer(grpc.UnaryInterceptor(apmgrpc.NewUnaryServerInterceptor()))
	defer s.GracefulStop()
	lis, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		panic(err)
	}
	go s.Serve(lis)
	pb.RegisterGreeterServer(s, service)
}

type helloWorldService struct {
	sayHello *kitgrpc.Server
}

func (s *helloWorldService) SayHello(ctx netcontext.Context, req *pb.HelloRequest) (*pb.HelloReply, error) {
	_, rep, err := s.sayHello.ServeGRPC(ctx, req)
	if err != nil {
		return nil, err
	}
	return rep.(*pb.HelloReply), nil
}
Output:

Example (HttpClient)
package main

import (
	"context"
	"net/http"
	"net/url"

	kithttp "github.com/go-kit/kit/transport/http"

	"go.elastic.co/apm"
	"go.elastic.co/apm/module/apmhttp"
)

func main() {
	// When constructing the kit/transport/http.Client, pass in an http.Client
	// instrumented using apmhttp.WrapClient (from module/apmhttp). This will
	// trace all outgoing requests, as long as the context supplied to methods
	// include an apm.Transaction.
	client := kithttp.NewClient(
		"GET", &url.URL{ /*...*/ },
		kithttp.EncodeJSONRequest,
		func(_ context.Context, r *http.Response) (interface{}, error) { return nil, nil },
		kithttp.SetClient(apmhttp.WrapClient(http.DefaultClient)),
	)

	tx := apm.DefaultTracer.StartTransaction("name", "type")
	ctx := apm.ContextWithTransaction(context.Background(), tx)
	defer tx.End()

	_, err := client.Endpoint()(ctx, struct{}{})
	if err != nil {
		panic(err)
	}
}
Output:

Example (HttpServer)
package main

import (
	"context"
	"net/http"

	kithttp "github.com/go-kit/kit/transport/http"

	"go.elastic.co/apm"
	"go.elastic.co/apm/module/apmhttp"
)

func main() {
	// Create your go-kit/kit/transport/http.Server as usual, without any tracing middleware.
	endpoint := func(ctx context.Context, req interface{}) (interface{}, error) {
		// The middleware added to the underlying gRPC server will be propagate
		// a transaction to the context passed to your endpoint. You can then
		// report endpoint-specific spans using apm.StartSpan.
		span, ctx := apm.StartSpan(ctx, "name", "endpoint")
		defer span.End()
		return nil, nil
	}
	server := kithttp.NewServer(
		endpoint,
		kithttp.NopRequestDecoder,
		func(_ context.Context, w http.ResponseWriter, _ interface{}) error { return nil },
	)

	// Use apmhttp.Wrap (from module/apmhttp) to instrument the
	// kit/transport/http.Server. This will trace all incoming requests.
	http.ListenAndServe("localhost:1234", apmhttp.Wrap(server))
}
Output:

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL