Documentation

Overview

Package trace is a distributed tracing and Zipkin client library for Go.

Background

For background, Zipkin (http://twitter.github.io/zipkin/) is Twitter's implementation of the Google Dapper paper (http://research.google.com/pubs/pub36356.html) for collecting tracing information from a distributed system. Both Zipkin and Dapper instrument RPC layers for collecting tracing information from the system as messages pass between services. Please read more at the aforementioned websites.

This library is a Go client library to assist in integrating with Zipkin.

This library, for most common uses, relies heavily on Google's Context objects. See http://blog.golang.org/context for more information there, but essentially this library works best if you are already passing Context objects through most of your callstacks.

Full example

See https://github.com/jtolds/go-zipkin-sample for a set of toy example programs that use this library, or https://raw.githubusercontent.com/jtolds/go-zipkin-sample/master/screenshot.png for a screenshot of the Zipkin user interface after collecting a trace from the sample application.

Basic usage

At a basic level, all you need to do to use this library to interface with Zipkin are the two functions TraceHandler and TraceRequest.

Here's an example client:

func MyOperation(ctx context.Context) error {
  req, err := http.NewRequest("GET", "http://my.url.tld/resource", nil)
  if err != nil {
    return err
  }
  resp, err := trace.TraceRequest(ctx, http.DefaultClient, req)
  if err != nil {
    return err
  }
  defer resp.Body.Close()

  // do stuff
}

And an example server:

func MyServer(addr string) error {
  return http.ListenAndServe(addr, trace.ContextWrapper(
      trace.TraceHandler(trace.ContextHTTPHandlerFunc(
      func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
        MyOperation(ctx)
        fmt.Fprintf(w, "hello\n")
      }))))
}

It is important that the context objects are passed all the way through your application logic from server to client to get the full effect.

In-process tracing

You may want to get tracing information out of operations and services within a process, instead of only at RPC boundaries. In this scenario, there is one more function used for creating new Spans within the same process.

For each function you want dedicated tracing information for, you can call the Trace function like so:

func MyTask(ctx context.Context) (result int, err error) {
  defer trace.Trace(&ctx)(&err)

  result, err = OtherTask1(ctx)
  if err != nil {
    return 0, err
  }

  var wg sync.WaitGroup
  wg.Add(2)

  go func() {
    defer wg.Done()
    OtherTask2(ctx)
  }()

  go func() {
    defer wg.Done()
    OtherTask3(ctx)
  }()

  wg.Wait()

  return result, nil
}

Here, Trace modifies the current context to include a new Span named after the calling function (MyTask). Your tracing collector will then receive this Span and include annotations about when each sampled Span started, when it finished, if it had a non-nil error or had a panic, what the error type was (if github.com/spacemonkeygo/errors can identify it), and pass the Span along to subcalls, for if they have their own spans.

If you don't like the automatic Span naming, you can use TraceWithSpanNamed instead.

Process setup

Every process that sends Spans will need to be configured with Configure and RegisterTraceCollector, so make sure to call those functions appropriately early in your process lifetime.

Other

See https://github.com/itszero/docker-zipkin for easy Zipkin setup.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	DefaultManager = NewSpanManager()

	Configure              = DefaultManager.Configure
	NewSampledTrace        = DefaultManager.NewSampledTrace
	NewSpanFromRequest     = DefaultManager.NewSpanFromRequest
	NewTrace               = DefaultManager.NewTrace
	RegisterTraceCollector = DefaultManager.RegisterTraceCollector
	TraceHandler           = DefaultManager.TraceHandler
	TraceRequest           = DefaultManager.TraceRequest
	TraceWithSpanNamed     = DefaultManager.TraceWithSpanNamed
)
View Source
var Rng = rand.New(&locker{s: rand.NewSource(seed())})

Rng is not a source of safe cryptographic randomness. This is only for instances where cryptographic randomness isn't needed. If in doubt, assume you need cryptographic randomness :)

Functions

func AddIgnoredCallerPrefix

func AddIgnoredCallerPrefix(prefix string)

AddIgnoredCallerPrefix adds a prefix that will get trimmed off from automatic name generation through CallerName (and therefore Trace)

func CallerName

func CallerName() string

CallerName returns the name of the caller two frames up the stack.

func ContextWithSpan

func ContextWithSpan(ctx context.Context, s *Span) context.Context

ContextWithSpan creates a new Context with the provided Span set as the current Span.

func ContextWrapper

func ContextWrapper(h ContextHTTPHandler) http.Handler

ContextWrapper will turn a ContextHTTPHandler into an http.Handler by passing a new Context into every request.

func PackageName

func PackageName() string

PackageName returns the name of the package of the caller two frames up the stack.

func RedirectPackets

func RedirectPackets(listen_addr string, collector *ScribeCollector) error

RedirectPackets is a method that handles incoming packets from the UDPCollector class. RedirectPackets, when running, will listen for UDP packets containing serialized zipkin.Span objects on listen_addr, then will resend those packets to the given ScribeCollector. On any error, RedirectPackets currently aborts.

func Trace

func Trace(ctx *context.Context) func(*error)

Trace calls Trace on the DefaultManager

Types

type Client

type Client interface {
	Do(req *http.Request) (*http.Response, error)
}

Client is an interface that matches an http.Client

type ContextHTTPHandler

type ContextHTTPHandler interface {
	ServeHTTP(ctx context.Context, w http.ResponseWriter, r *http.Request)
}

ContextHTTPHandler is like http.Handler, but expects a Context object as the first parameter.

type ContextHTTPHandlerFunc

type ContextHTTPHandlerFunc func(
	ctx context.Context, w http.ResponseWriter, r *http.Request)

ContextHTTPHandlerFunc is like http.HandlerFunc but for ContextHTTPHandlers

func (ContextHTTPHandlerFunc) ServeHTTP

type HeaderGetter

type HeaderGetter interface {
	Get(string) string
}

HeaderGetter is an interface that http.Header matches for RequestFromHeader

type HeaderSetter

type HeaderSetter interface {
	Set(string, string)
}

HeaderSetter is an interface that http.Header matches for Request.SetHeader

type Request

type Request struct {
	TraceId  *int64
	SpanId   *int64
	ParentId *int64
	Sampled  *bool
	Flags    *int64
}

Request is a structure representing an incoming RPC request. Every field is optional.

func RequestFromHeader

func RequestFromHeader(header HeaderGetter) (rv Request)

RequestFromHeader will create a Request object given an http.Header or anything that matches the HeaderGetter interface.

func (Request) SetHeader

func (r Request) SetHeader(header HeaderSetter)

SetHeader will take a Request and fill out an http.Header, or anything that matches the HeaderSetter interface.

type ScribeCollector

type ScribeCollector struct {

	// contains filtered or unexported fields

}

ScribeCollector matches the TraceCollector interface, but writes directly to a connected Scribe socket.

func NewScribeCollector

func NewScribeCollector(scribe_addr string) (*ScribeCollector, error)

NewScribeCollector creates a ScribeCollector. scribe_addr is the address of the Scribe endpoint, typically "127.0.0.1:9410"

func (*ScribeCollector) Close

func (s *ScribeCollector) Close() error

Close closes an existing ScribeCollector

func (*ScribeCollector) Collect

func (c *ScribeCollector) Collect(s *zipkin.Span)

Collect will serialize and send a zipkin.Span to the configured Scribe endpoint

func (*ScribeCollector) CollectSerialized

func (c *ScribeCollector) CollectSerialized(serialized []byte) error

CollectSerialized buffers a serialized zipkin.Span to be sent to the Scribe endpoint. It returns an error and loses the log entry if the buffer is full.

type Span

type Span struct {

	// contains filtered or unexported fields

}

Span represents a given task or request within a full trace.

func NewDisabledTrace

func NewDisabledTrace() *Span

NewDisabledTrace creates a new Span that is disabled.

func SpanFromContext

func SpanFromContext(ctx context.Context) (s *Span, ok bool)

SpanFromContext loads the current span from the current Context if one exists

func (*Span) Annotate

func (s *Span) Annotate(key string, val interface{}, host *zipkin.Endpoint)

Annotate annotates a given span with an arbitrary value. host is optional. Annotate is a no-op unless val is of type time.Time, []byte, or string.

func (*Span) AnnotateTimestamp

func (s *Span) AnnotateTimestamp(key string, now time.Time,
	duration *time.Duration, host *zipkin.Endpoint)

AnnotateTimestamp annotates a given span with a timestamp. duration and host are optional.

func (*Span) Debug

func (s *Span) Debug() bool

Debug is whether or not the trace collector is allowed to sample this trace on its own.

func (*Span) Export

func (s *Span) Export() *zipkin.Span

Export will take a Span and return a serializable thrift object.

func (*Span) Name

func (s *Span) Name() string

Name is the name of the given span, if not disabled.

func (*Span) NewSpan

func (parent *Span) NewSpan(name string) *Span

NewSpan creates a new Span off of the given parent Span.

func (*Span) Observe

func (s *Span) Observe() func(errptr *error)

Observe is meant to watch a Span over a given Span duration.

Example

Code:

package main

import (
	"gopkg.in/spacemonkeygo/monitor.v1/trace"
)

func main() {
	myfunc := func() (err error) {
		span := trace.NewTrace("my span")
		defer span.Observe()(&err)

		// do things

		return nil
	}

	myfunc()
}

func (*Span) ObserveService

func (s *Span) ObserveService(service *zipkin.Endpoint) func(errptr *error)

ObserveService is like Observe, but uses a provided host instead of the SpanManager's default local host for annotations.

func (*Span) ParentId

func (s *Span) ParentId() *int64

ParentId is the id of the parent span in the given trace, if not disabled.

func (*Span) Request

func (s *Span) Request() Request

Request will return a Request for RPC purposes based off of the existing Span

func (*Span) SpanId

func (s *Span) SpanId() int64

SpanId is the id of the given span, if not disabled.

func (*Span) TraceDisabled

func (s *Span) TraceDisabled() bool

Trace disabled returns whether the trace is even active. A disabled trace causes many operations to be a no-op.

func (*Span) TraceId

func (s *Span) TraceId() int64

TraceId is the id of the given trace, if not disabled.

type SpanManager

type SpanManager struct {

	// contains filtered or unexported fields

}

SpanManager creates and configures settings about Spans. Create one with NewSpanManager

func NewSpanManager

func NewSpanManager() *SpanManager

NewSpanManager creates a new SpanManager. No traces will be collected by default until Configure is called.

func (*SpanManager) Configure

func (m *SpanManager) Configure(trace_fraction float64, trace_debug bool,
	default_local_host *zipkin.Endpoint)

Configure configures a SpanManager. trace_fraction is the fraction of new traces that will be collected (between 0 and 1, inclusive). trace_debug is whether or not traces will have the debug flag set, which controls whether or not the trace collector will be allowed to sample them on its own. default_local_host is the annotation host endpoint to set when one isn't otherwise provided.

func (*SpanManager) NewSampledTrace

func (m *SpanManager) NewSampledTrace(span_name string, debug bool) *Span

NewSampledTrace creates a new span that begins a trace that is being sampled without consulting the configured trace_fraction. span_name names the first span of the trace, and debug controls whether or not the span collector is allowed to sample the trace on its own.

func (*SpanManager) NewSpanFromRequest

func (m *SpanManager) NewSpanFromRequest(name string, req Request) *Span

NewSpanFromRequest creates a new span, and possibly a new trace, given whatever was supplied in the incoming request.

func (*SpanManager) NewTrace

func (m *SpanManager) NewTrace(span_name string) *Span

NewTrace creates a new span that begins a trace, after consulting the SpanManager's configured trace_fraction and trace_debug settings. The trace may or may not actually be sampled. span_name is the name of the beginning Span.

func (*SpanManager) RegisterTraceCollector

func (m *SpanManager) RegisterTraceCollector(collector TraceCollector)

RegisterTraceCollector takes a TraceCollector and calls Collect on it whenever a Span from this SpanManager is complete.

func (*SpanManager) Trace

func (m *SpanManager) Trace(ctx *context.Context) func(*error)

Trace is a utility that allows you to automatically create a Span (or a brand new trace, if needed) that observes the current function scope, given a function call context. The name of the Span is pulled from the current function name. See the example for usage.

Example

Code:

package main

import (
	"golang.org/x/net/context"
	"gopkg.in/spacemonkeygo/monitor.v1/trace"
)

func main() {
	myfunc := func(ctx context.Context) (err error) {
		defer trace.Trace(&ctx)(&err)

		// do things

		return nil
	}

	myfunc(context.Background())
}

func (*SpanManager) TraceHandler

TraceHandler wraps a ContextHTTPHandler with a Span pulled from incoming requests, possibly starting new Traces if necessary.

func (*SpanManager) TraceRequest

func (m *SpanManager) TraceRequest(ctx context.Context, cl Client,
	req *http.Request) (
	resp *http.Response, err error)

TraceRequest will perform an HTTP request, creating a new Span for the HTTP request and sending the Span in the HTTP request headers. Compare to http.Client.Do.

func (*SpanManager) TraceWithSpanNamed

func (m *SpanManager) TraceWithSpanNamed(
	ctx *context.Context, name string) func(*error)

TraceWithSpanNamed is like Trace, except you get to pick the Span name.

type TraceCollector

type TraceCollector interface {
	// Collect gets called with a Span whenever a Span is completed on a
	// SpanManager.
	Collect(span *zipkin.Span)
}

TraceCollector is an interface dealing with completed Spans on a SpanManager. See RegisterTraceCollector.

type TraceCollectorFunc

type TraceCollectorFunc func(span *zipkin.Span)

TraceCollectorFunc is for closures that match the TraceCollector interface.

func (TraceCollectorFunc) Collect

func (f TraceCollectorFunc) Collect(span *zipkin.Span)

type UDPCollector

type UDPCollector struct {

	// contains filtered or unexported fields

}

UDPCollector matches the TraceCollector interface, but sends serialized zipkin.Span objects over UDP, instead of the Scribe protocol. See RedirectPackets for the UDP server-side code.

func NewUDPCollector

func NewUDPCollector(collector_addr string, buffer_size int) (
	*UDPCollector, error)

NewUDPCollector creates a UDPCollector that sends packets to collector_addr. buffer_size is how many outstanding unsent zipkin.Span objects can exist before Spans start getting dropped.

func (*UDPCollector) Collect

func (c *UDPCollector) Collect(span *zipkin.Span)

Collect takes a zipkin.Span object, serializes it, and sends it to the configured collector_addr.

Directories

Path Synopsis
gen-go/scribe
gen-go/zipkin