zipkin

package
v0.0.0-...-3122b44 Latest Latest
Warning

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

Go to latest
Published: May 26, 2016 License: MIT Imports: 18 Imported by: 0

README

Zipkin

Development and Testing Set-up

Setting up Zipkin is not an easy thing to do. It will also demand quite some resources. To help you get started with development and testing we've made a docker-compose file available for running a full Zipkin stack. See the kit/tracing/zipkin/_docker subdirectory.

You will need docker-compose 1.6.0+ and docker-engine 1.10.0+.

If running on Linux HOSTNAME can be set to localhost. If running on Mac OS X or Windows you probably need to set the hostname environment variable to the hostname of the VM running the docker containers.

cd tracing/zipkin/_docker
HOSTNAME=localhost docker-compose -f docker-compose-zipkin.yml up

As mentioned the Zipkin stack is quite heavy and may take a few minutes to fully initialize.

The following services have been set-up to run:

  • Apache Cassandra (port: 9160 (thrift), 9042 (native))
  • Apache ZooKeeper (port: 2181)
  • Apache Kafka (port: 9092)
  • Zipkin Collector
  • Zipkin Query
  • Zipkin Web (port: 8080, 9990)

Middleware Usage

Wrap a server- or client-side endpoint so that it emits traces to a Zipkin collector. Make sure the host given to MakeNewSpanFunc resolves to an IP. If not your span will silently fail!

If needing to create child spans in methods or calling another service from your service method, it is highly recommended to request a context parameter so you can transfer the needed metadata for traces across service boundaries.

It is also wise to always return error parameters with your service method calls, even if your service method implementations will not throw errors themselves. The error return parameter can be wired to pass the potential transport errors when consuming your service API in a networked environment.

func main() {
	var (
		// myHost MUST resolve to an IP or your span will not show up in Zipkin.
		myHost        = "instance01.addsvc.internal.net:8000"
		myService     = "AddService"
		myMethod      = "Add"
		url           = myHost + "/add/"
		kafkaHost     = []string{"kafka.internal.net:9092"}
	)

	ctx := context.Background()

	// Set Up Zipkin Collector and Span factory
	spanFunc := zipkin.MakeNewSpanFunc(myHost, myService, myMethod)
	collector, _ := zipkin.NewKafkaCollector(kafkaHost)

	// Server-side Wiring
	var server endpoint.Endpoint
	server = makeEndpoint() // for your service
	// wrap endpoint with Zipkin tracing middleware
	server = zipkin.AnnotateServer(spanFunc, collector)(server)

	http.Handle(
		"/add/",
		httptransport.NewServer(
			ctx,
			server,
			decodeRequestFunc,
			encodeResponseFunc,
			httptransport.ServerBefore(
				zipkin.ToContext(spanFunc),
			),
		),
	)
	...

	// Client-side
	var client endpoint.Endpoint
	client = httptransport.NewClient(
		"GET",
		URL,
		encodeRequestFunc,
		decodeResponseFunc,
		httptransport.ClientBefore(zipkin.ToRequest(spanFunc)),
	).Endpoint()
	client = zipkin.AnnotateClient(spanFunc, collector)(client)

	ctx, cancel := context.WithTimeout(ctx, myTimeout)
	defer cancel()

	reply, err := client(ctx, param1, param2)
	// do something with the response/error
	...
}

Annotating Remote Resources

Next to the above shown examples of wiring server-side and client-side tracing middlewares, you can also span resources called from your service methods.

To do this, the service method needs to include a context parameter. From your endpoint wrapper you can inject the endpoint context which will hold the parent span already created by the server-side middleware. If the resource is a remote database you can use the zipkin.ServerAddr spanOption to identify the remote host:port and the display name of this resource.

type MyService struct {
	// add a Zipkin Collector to your service implementation's properties.
	Collector zipkin.Collector
}

// Example of the endpoint.Endpoint to service method wrapper, injecting the
// context provided by the transport server.
func makeComplexEndpoint() endpoint.Endpoint {
	return func(ctx context.Context, request interface{}) (interface{}, error) {
		req := request.(ComplexRequest)
		v, err := svc.Complex(ctx, req.A, req.B)
		return ComplexResponse{V: v, Err: err}, nil
	}
}

// Complex is an example method of our service, displaying the tracing of a
// remote database resource.
func (s *MyService) Complex(ctx context.Context, A someType, B otherType) (returnType, error) {
	// we've parsed the incoming parameters and now we need to query the database.
	// we wish to include this action into our trace.
	span, collect := zipkin.NewChildSpan(
		ctx,
		s.Collector,
		"complexQuery",
		zipkin.ServerAddr(
			"mysql01.internal.net:3306",
			"MySQL",
		),
	)
	// you probably want to binary annotate your query
	span.AnnotateBinary("query", "SELECT ... FROM ... WHERE ... ORDER BY ..."),
	// annotate the start of the query
	span.Annotate("complexQuery:start")
	// do the query and handle resultset
	...
	// annotate we are done with the query
	span.Annotate("complexQuery:end")
	// maybe binary annotate some items returned by the resultset
	...
	// when done with all annotations, collect the span
	collect()
	...
}

Documentation

Index

Constants

View Source
const (
	// SpanContextKey holds the key used to store Zipkin spans in the context.
	SpanContextKey = "Zipkin-Span"

	// ClientSend is the annotation value used to mark a client sending a
	// request to a server.
	ClientSend = "cs"

	// ServerReceive is the annotation value used to mark a server's receipt
	// of a request from a client.
	ServerReceive = "sr"

	// ServerSend is the annotation value used to mark a server's completion
	// of a request and response to a client.
	ServerSend = "ss"

	// ClientReceive is the annotation value used to mark a client's receipt
	// of a completed request from a server.
	ClientReceive = "cr"

	// ServerAddress allows to annotate the server endpoint in case the server
	// side trace is not instrumented as with resources like caches and
	// databases.
	ServerAddress = "sa"

	// ClientAddress allows to annotate the client origin in case the client was
	// forwarded by a proxy which does not instrument itself.
	ClientAddress = "ca"
)

Variables

This section is empty.

Functions

func AnnotateClient

func AnnotateClient(newSpan NewSpanFunc, c Collector) endpoint.Middleware

AnnotateClient returns a middleware that extracts a parent span from the context, produces a client (child) span from it, adds client-send and client-receive annotations at the boundaries, and submits the span to the collector. If no span is found in the context, a new span is generated and inserted.

func AnnotateServer

func AnnotateServer(newSpan NewSpanFunc, c Collector) endpoint.Middleware

AnnotateServer returns a server.Middleware that extracts a span from the context, adds server-receive and server-send annotations at the boundaries, and submits the span to the collector. If no span is found in the context, a new span is generated and inserted.

func NewChildSpan

func NewChildSpan(ctx context.Context, collector Collector, methodName string, options ...SpanOption) (*Span, CollectFunc)

NewChildSpan returns a new child Span of a parent Span extracted from the passed context. It can be used to annotate resources like databases, caches, etc. and treat them as if they are a regular service. For tracing client endpoints use AnnotateClient instead.

func ToContext

func ToContext(newSpan NewSpanFunc, logger log.Logger) func(ctx context.Context, r *http.Request) context.Context

ToContext returns a function that satisfies transport/http.BeforeFunc. It takes a Zipkin span from the incoming HTTP request, and saves it in the request context. It's designed to be wired into a server's HTTP transport Before stack. The logger is used to report errors.

func ToGRPCContext

func ToGRPCContext(newSpan NewSpanFunc, logger log.Logger) func(ctx context.Context, md *metadata.MD) context.Context

ToGRPCContext returns a function that satisfies transport/grpc.BeforeFunc. It takes a Zipkin span from the incoming GRPC request, and saves it in the request context. It's designed to be wired into a server's GRPC transport Before stack. The logger is used to report errors.

func ToGRPCRequest

func ToGRPCRequest(newSpan NewSpanFunc) func(ctx context.Context, md *metadata.MD) context.Context

ToGRPCRequest returns a function that satisfies transport/grpc.BeforeFunc. It takes a Zipkin span from the context, and injects it into the GRPC context. It's designed to be wired into a client's GRPC transport Before stack. It's expected that AnnotateClient has already ensured the span in the context is a child/client span.

func ToRequest

func ToRequest(newSpan NewSpanFunc) func(ctx context.Context, r *http.Request) context.Context

ToRequest returns a function that satisfies transport/http.BeforeFunc. It takes a Zipkin span from the context, and injects it into the HTTP request. It's designed to be wired into a client's HTTP transport Before stack. It's expected that AnnotateClient has already ensured the span in the context is a child/client span.

Types

type CollectFunc

type CollectFunc func()

CollectFunc will collect the span created with NewChildSpan.

type CollectionError

type CollectionError interface {
	Error() string
	GetErrors() []error
}

CollectionError represents an array of errors returned by one or more failed Collector methods.

type Collector

type Collector interface {
	Collect(*Span) error
	ShouldSample(*Span) bool
	Close() error
}

Collector represents a Zipkin trace collector, which is probably a set of remote endpoints.

func NewKafkaCollector

func NewKafkaCollector(addrs []string, options ...KafkaOption) (Collector, error)

NewKafkaCollector returns a new Kafka-backed Collector. addrs should be a slice of TCP endpoints of the form "host:port".

func NewScribeCollector

func NewScribeCollector(addr string, timeout time.Duration, options ...ScribeOption) (Collector, error)

NewScribeCollector returns a new Scribe-backed Collector. addr should be a TCP endpoint of the form "host:port". timeout is passed to the Thrift dial function NewTSocketFromAddrTimeout. batchSize and batchInterval control the maximum size and interval of a batch of spans; as soon as either limit is reached, the batch is sent. The logger is used to log errors, such as batch send failures; users should provide an appropriate context, if desired.

type KafkaCollector

type KafkaCollector struct {
	// contains filtered or unexported fields
}

KafkaCollector implements Collector by publishing spans to a Kafka broker.

func (*KafkaCollector) Close

func (c *KafkaCollector) Close() error

Close implements Collector.

func (*KafkaCollector) Collect

func (c *KafkaCollector) Collect(s *Span) error

Collect implements Collector.

func (*KafkaCollector) ShouldSample

func (c *KafkaCollector) ShouldSample(s *Span) bool

ShouldSample implements Collector.

type KafkaOption

type KafkaOption func(c *KafkaCollector)

KafkaOption sets a parameter for the KafkaCollector

func KafkaLogger

func KafkaLogger(logger log.Logger) KafkaOption

KafkaLogger sets the logger used to report errors in the collection process. By default, a no-op logger is used, i.e. no errors are logged anywhere. It's important to set this option.

func KafkaProducer

func KafkaProducer(p sarama.AsyncProducer) KafkaOption

KafkaProducer sets the producer used to produce to Kafka.

func KafkaSampleRate

func KafkaSampleRate(sr Sampler) KafkaOption

KafkaSampleRate sets the sample rate used to determine if a trace will be sent to the collector. By default, the sample rate is 1.0, i.e. all traces are sent.

func KafkaTopic

func KafkaTopic(t string) KafkaOption

KafkaTopic sets the kafka topic to attach the collector producer on.

type MultiCollector

type MultiCollector []Collector

MultiCollector implements Collector by sending spans to all collectors.

func (MultiCollector) Close

func (c MultiCollector) Close() error

Close implements Collector.

func (MultiCollector) Collect

func (c MultiCollector) Collect(s *Span) error

Collect implements Collector.

func (MultiCollector) ShouldSample

func (c MultiCollector) ShouldSample(s *Span) bool

ShouldSample implements Collector.

type NewSpanFunc

type NewSpanFunc func(traceID, spanID, parentSpanID int64) *Span

NewSpanFunc takes trace, span, & parent span IDs to produce a Span object.

func MakeNewSpanFunc

func MakeNewSpanFunc(hostport, serviceName, methodName string) NewSpanFunc

MakeNewSpanFunc returns a function that generates a new Zipkin span.

type NopCollector

type NopCollector struct{}

NopCollector implements Collector but performs no work.

func (NopCollector) Close

func (NopCollector) Close() error

Close implements Collector.

func (NopCollector) Collect

func (NopCollector) Collect(*Span) error

Collect implements Collector.

func (NopCollector) ShouldSample

func (n NopCollector) ShouldSample(span *Span) bool

ShouldSample implements Collector.

type Sampler

type Sampler func(id int64) bool

Sampler functions return if a Zipkin span should be sampled, based on its traceID.

func SampleRate

func SampleRate(rate float64, salt int64) Sampler

SampleRate returns a sampler function using a particular sample rate and a sample salt to identify if a Zipkin span based on its spanID should be collected.

type ScribeCollector

type ScribeCollector struct {
	// contains filtered or unexported fields
}

ScribeCollector implements Collector by forwarding spans to a Scribe service, in batches.

func (*ScribeCollector) Close

func (c *ScribeCollector) Close() error

Close implements Collector.

func (*ScribeCollector) Collect

func (c *ScribeCollector) Collect(s *Span) error

Collect implements Collector.

func (*ScribeCollector) ShouldSample

func (c *ScribeCollector) ShouldSample(s *Span) bool

ShouldSample implements Collector.

type ScribeOption

type ScribeOption func(s *ScribeCollector)

ScribeOption sets a parameter for the StdlibAdapter.

func ScribeBatchInterval

func ScribeBatchInterval(d time.Duration) ScribeOption

ScribeBatchInterval sets the maximum duration we will buffer traces before emitting them to the collector. The default batch interval is 1 second.

func ScribeBatchSize

func ScribeBatchSize(n int) ScribeOption

ScribeBatchSize sets the maximum batch size, after which a collect will be triggered. The default batch size is 100 traces.

func ScribeCategory

func ScribeCategory(category string) ScribeOption

ScribeCategory sets the Scribe category used to transmit the spans.

func ScribeLogger

func ScribeLogger(logger log.Logger) ScribeOption

ScribeLogger sets the logger used to report errors in the collection process. By default, a no-op logger is used, i.e. no errors are logged anywhere. It's important to set this option in a production service.

func ScribeSampleRate

func ScribeSampleRate(sr Sampler) ScribeOption

ScribeSampleRate sets the sample rate used to determine if a trace will be sent to the collector. By default, the sample rate is 1.0, i.e. all traces are sent.

type Span

type Span struct {
	// contains filtered or unexported fields
}

A Span is a named collection of annotations. It represents meaningful information about a single method call, i.e. a single request against a service. Clients should annotate the span, and submit it when the request that generated it is complete.

func FromContext

func FromContext(ctx context.Context) (*Span, bool)

FromContext extracts an existing Zipkin span if it is stored in the provided context. If you add context.Context as the first parameter in your service methods you can annotate spans from within business logic. Typical use case is to AnnotateDuration on interaction with resources like databases.

func NewSpan

func NewSpan(hostport, serviceName, methodName string, traceID, spanID, parentSpanID int64) *Span

NewSpan returns a new Span, which can be annotated and collected by a collector. Spans are passed through the request context to each middleware under the SpanContextKey.

func (*Span) Annotate

func (s *Span) Annotate(value string)

Annotate annotates the span with the given value.

func (*Span) AnnotateBinary

func (s *Span) AnnotateBinary(key string, value interface{})

AnnotateBinary annotates the span with a key and a value that will be []byte encoded.

func (*Span) AnnotateString

func (s *Span) AnnotateString(key, value string)

AnnotateString annotates the span with a key and a string value. Deprecated: use AnnotateBinary instead.

func (*Span) Encode

func (s *Span) Encode() *zipkincore.Span

Encode creates a Thrift Span from the gokit Span.

func (*Span) IsSampled

func (s *Span) IsSampled() bool

IsSampled returns if the span is set to be sampled.

func (*Span) ParentSpanID

func (s *Span) ParentSpanID() int64

ParentSpanID returns the ID of the span which invoked this span. It may be zero.

func (*Span) Sample

func (s *Span) Sample()

Sample forces sampling of this span.

func (*Span) SetDebug

func (s *Span) SetDebug()

SetDebug forces debug mode on this span.

func (*Span) SpanID

func (s *Span) SpanID() int64

SpanID returns the ID of this span.

func (*Span) TraceID

func (s *Span) TraceID() int64

TraceID returns the ID of the trace that this span is a member of.

type SpanOption

type SpanOption func(s *Span)

SpanOption sets an optional parameter for Spans.

func Debug

func Debug(debug bool) SpanOption

Debug will set the Span to debug mode forcing Samplers to pass the Span.

func Host

func Host(hostport, serviceName string) SpanOption

Host will update the default zipkin Endpoint of the Span it is used with.

func ServerAddr

func ServerAddr(hostport, serviceName string) SpanOption

ServerAddr will create a ServerAddr annotation with its own zipkin Endpoint when used with NewChildSpan. This is typically used when the NewChildSpan is used to annotate non Zipkin aware resources like databases and caches.

Jump to

Keyboard shortcuts

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