opentracing

package module
v0.0.0-...-6faad65 Latest Latest
Warning

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

Go to latest
Published: May 21, 2016 License: MIT Imports: 7 Imported by: 0

README

Gitter chat Build Status GoDoc

OpenTracing API for Go

This package is a Go platform API for OpenTracing.

Required Reading

In order to understand the Go platform API, one must first be familiar with the OpenTracing project and terminology more generally.

API overview for those adding instrumentation

Everyday consumers of this opentracing package really only need to worry about a couple of key abstractions: the StartSpan function, the Span interface, and binding a Tracer at main()-time. Here are code snippets demonstrating some important use cases.

Singleton initialization

The simplest starting point is ./default_tracer.go. As early as possible, call

    import "github.com/opentracing/opentracing-go"
    import ".../some_tracing_impl"

    func main() {
        tracerImpl := some_tracing_impl.New(...) // tracing impl specific
        opentracing.InitGlobalTracer(tracerImpl)
        ...
    }
Non-Singleton initialization

If you prefer direct control to singletons, manage ownership of the opentracing.Tracer implementation explicitly.

Creating a Span given an existing Golang context.Context

If you use context.Context in your application, OpenTracing's Go library will happily use it for Span propagation. To start a new (child) Span, you can use StartSpanFromContext.

    func xyz(ctx context.Context, ...) {
        ...
        span, ctx := opentracing.StartSpanFromContext(ctx, "operation_name")
        defer span.Finish()
        span.LogEvent("xyz_called")
        ...
    }
Starting an empty trace by creating a "root span"

It's always possible to create a "root" (parentless) Span.

    func xyz() {
        ...
        sp := opentracing.StartSpan("operation_name")
        defer sp.Finish()
        sp.LogEvent("xyz_called")
        ...
    }
Creating a (child) Span given an existing (parent) Span
    func xyz(parentSpan opentracing.Span, ...) {
        ...
        sp := opentracing.StartChildSpan(parentSpan, "operation_name")
        defer sp.Finish()
        sp.LogEvent("xyz_called")
        ...
    }
Serializing to the wire
    func makeSomeRequest(ctx context.Context) ... {
        if span := opentracing.SpanFromContext(ctx); span != nil {
            httpClient := &http.Client{}
            httpReq, _ := http.NewRequest("GET", "http://myservice/", nil)

            // Transmit the span's TraceContext as HTTP headers on our
            // outbound request.
            tracer.Inject(
                span,
                opentracing.TextMap,
                opentracing.HTTPHeaderTextMapCarrier(httpReq.Header))

            resp, err := httpClient.Do(httpReq)
            ...
        }
        ...
    }
Deserializing from the wire
    http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
        serverSpan, err := opentracing.GlobalTracer().Join(
            "serverSpan",
            opentracing.TextMap,
            opentracing.HTTPHeaderTextMapCarrier(req.Header))

        if err != nil {
            // Create a root span if necessary
            serverSpan = opentracing.StartTrace("serverSpan")
        }
        var goCtx context.Context = ...
        goCtx, _ = opentracing.ContextWithSpan(goCtx, serverSpan)
        defer serverSpan.Finish()
        ...
    }
Goroutine-safety

The entire public API is goroutine-safe and does not require external synchronization.

API pointers for those implementing a tracing system

Tracing system implementors may be able to reuse or copy-paste-modify the basictracer package, found here. In particular, see basictracer.New(...).

API compatibility

For the time being, "mild" backwards-incompatible changes may be made without changing the major version number. As OpenTracing and opentracing-go mature, backwards compatibility will become more of a priority.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrUnsupportedFormat occurs when the `format` passed to Tracer.Inject() or
	// Tracer.Join() is not recognized by the Tracer implementation.
	ErrUnsupportedFormat = errors.New("opentracing: Unknown or unsupported Inject/Join format")

	// ErrTraceNotFound occurs when the `carrier` passed to Tracer.Join() is
	// valid and uncorrupted but has insufficient information to join or resume
	// a trace.
	ErrTraceNotFound = errors.New("opentracing: Trace not found in Join carrier")

	// ErrInvalidSpan errors occur when Tracer.Inject() is asked to operate on
	// a Span which it is not prepared to handle (for example, since it was
	// created by a different tracer implementation).
	ErrInvalidSpan = errors.New("opentracing: Span type incompatible with tracer")

	// ErrInvalidCarrier errors occur when Tracer.Inject() or Tracer.Join()
	// implementations expect a different type of `carrier` than they are
	// given.
	ErrInvalidCarrier = errors.New("opentracing: Invalid Inject/Join carrier")

	// ErrTraceCorrupted occurs when the `carrier` passed to Tracer.Join() is
	// of the expected type but is corrupted.
	ErrTraceCorrupted = errors.New("opentracing: Trace data corrupted in Join carrier")
)

Functions

func BackgroundContextWithSpan

func BackgroundContextWithSpan(span Span) context.Context

BackgroundContextWithSpan is a convenience wrapper around `ContextWithSpan(context.BackgroundContext(), ...)`.

func CanonicalizeBaggageKey

func CanonicalizeBaggageKey(key string) (string, bool)

CanonicalizeBaggageKey returns the canonicalized version of baggage item key `key`, and true if and only if the key was valid.

It is more performant to use lowercase keys only.

func ContextWithSpan

func ContextWithSpan(ctx context.Context, span Span) context.Context

ContextWithSpan returns a new `context.Context` that holds a reference to the given `Span`.

func InitGlobalTracer

func InitGlobalTracer(tracer Tracer)

InitGlobalTracer sets the [singleton] opentracing.Tracer returned by GlobalTracer(). Those who use GlobalTracer (rather than directly manage an opentracing.Tracer instance) should call InitGlobalTracer as early as possible in main(), prior to calling the `StartSpan` (etc) global funcs below. Prior to calling `InitGlobalTracer`, any Spans started via the `StartSpan` (etc) globals are noops.

Types

type BuiltinFormat

type BuiltinFormat byte

BuiltinFormat is used to demarcate the values within package `opentracing` that are intended for use with the Tracer.Inject() and Tracer.Join() methods.

const (
	// Binary encodes the Span for propagation as opaque binary data.
	//
	// For Tracer.Inject(): the carrier must be an `io.Writer`.
	//
	// For Tracer.Join(): the carrier must be an `io.Reader`.
	Binary BuiltinFormat = iota

	// TextMap encodes the Span as key:value pairs.
	//
	// For Tracer.Inject(): the carrier must be a `TextMapWriter`.
	//
	// For Tracer.Join(): the carrier must be a `TextMapReader`.
	//
	// See HTTPHeaderTextMapCarrier for an implementation of both TextMapWriter
	// and TextMapReader that defers to an http.Header instance for storage.
	// For example, Inject():
	//
	//    carrier := HTTPHeaderTextMapCarrier(httpReq.Header)
	//    err := span.Tracer().Inject(span, TextMap, carrier)
	//
	// Or Join():
	//
	//    carrier := HTTPHeaderTextMapCarrier(httpReq.Header)
	//    span, err := tracer.Join("opName", TextMap, carrier)
	//
	TextMap
)

type FinishOptions

type FinishOptions struct {
	// FinishTime overrides the Span's finish time, or implicitly becomes
	// time.Now() if FinishTime.IsZero().
	//
	// FinishTime must resolve to a timestamp that's >= the Span's StartTime
	// (per StartSpanOptions).
	FinishTime time.Time

	// BulkLogData allows the caller to specify the contents of many Log()
	// calls with a single slice. May be nil.
	//
	// None of the LogData.Timestamp values may be .IsZero() (i.e., they must
	// be set explicitly). Also, they must be >= the Span's start timestamp and
	// <= the FinishTime (or time.Now() if FinishTime.IsZero()). Otherwise the
	// behavior of FinishWithOptions() is undefined.
	//
	// If specified, the caller hands off ownership of BulkLogData at
	// FinishWithOptions() invocation time.
	BulkLogData []LogData
}

FinishOptions allows Span.FinishWithOptions callers to override the finish timestamp and provide log data via a bulk interface.

type HTTPHeaderTextMapCarrier

type HTTPHeaderTextMapCarrier http.Header

HTTPHeaderTextMapCarrier satisfies both TextMapWriter and TextMapReader.

func (HTTPHeaderTextMapCarrier) ForeachKey

func (c HTTPHeaderTextMapCarrier) ForeachKey(handler func(key, val string) error) error

ForeachKey conforms to the TextMapReader interface.

func (HTTPHeaderTextMapCarrier) Set

func (c HTTPHeaderTextMapCarrier) Set(key, val string)

Set conforms to the TextMapWriter interface.

type LogData

type LogData struct {
	// The timestamp of the log record; if set to the default value (the unix
	// epoch), implementations should use time.Now() implicitly.
	Timestamp time.Time

	// Event (if non-empty) should be the stable name of some notable moment in
	// the lifetime of a Span. For instance, a Span representing a browser page
	// load might add an Event for each of the Performance.timing moments
	// here: https://developer.mozilla.org/en-US/docs/Web/API/PerformanceTiming
	//
	// While it is not a formal requirement, Event strings will be most useful
	// if they are *not* unique; rather, tracing systems should be able to use
	// them to understand how two similar Spans relate from an internal timing
	// perspective.
	Event string

	// Payload is a free-form potentially structured object which Tracer
	// implementations may retain and record all, none, or part of.
	//
	// If included, `Payload` should be restricted to data derived from the
	// instrumented application; in particular, it should not be used to pass
	// semantic flags to a Log() implementation.
	//
	// For example, an RPC system could log the wire contents in both
	// directions, or a SQL library could log the query (with or without
	// parameter bindings); tracing implementations may truncate or otherwise
	// record only a snippet of these payloads (or may strip out PII, etc,
	// etc).
	Payload interface{}
}

LogData is data associated to a Span. Every LogData instance should specify at least one of Event and/or Payload.

type NoopTracer

type NoopTracer struct{}

A NoopTracer is a trivial implementation of Tracer for which all operations are no-ops.

func (NoopTracer) Inject

func (n NoopTracer) Inject(sp Span, format interface{}, carrier interface{}) error

Inject belongs to the Tracer interface.

func (NoopTracer) Join

func (n NoopTracer) Join(operationName string, format interface{}, carrier interface{}) (Span, error)

Join belongs to the Tracer interface.

func (NoopTracer) StartSpan

func (n NoopTracer) StartSpan(operationName string) Span

StartSpan belongs to the Tracer interface.

func (NoopTracer) StartSpanWithOptions

func (n NoopTracer) StartSpanWithOptions(opts StartSpanOptions) Span

StartSpanWithOptions belongs to the Tracer interface.

type Span

type Span interface {
	// Sets or changes the operation name.
	SetOperationName(operationName string) Span

	// Adds a tag to the span.
	//
	// Tag values can be of arbitrary types, however the treatment of complex
	// types is dependent on the underlying tracing system implementation.
	// It is expected that most tracing systems will handle primitive types
	// like strings and numbers. If a tracing system cannot understand how
	// to handle a particular value type, it may ignore the tag, but shall
	// not panic.
	//
	// If there is a pre-existing tag set for `key`, it is overwritten.
	SetTag(key string, value interface{}) Span

	// Sets the end timestamp and calls the `Recorder`s RecordSpan()
	// internally.
	//
	// Finish() should be the last call made to any span instance, and to do
	// otherwise leads to undefined behavior.
	Finish()
	// FinishWithOptions is like Finish() but with explicit control over
	// timestamps and log data.
	FinishWithOptions(opts FinishOptions)

	// LogEvent() is equivalent to
	//
	//   Log(LogData{Event: event})
	//
	LogEvent(event string)

	// LogEventWithPayload() is equivalent to
	//
	//   Log(LogData{Event: event, Payload: payload0})
	//
	LogEventWithPayload(event string, payload interface{})

	// Log() records `data` to this Span.
	//
	// See LogData for semantic details.
	Log(data LogData)

	// SetBaggageItem sets a key:value pair on this Span that also
	// propagates to future Span children.
	//
	// SetBaggageItem() enables powerful functionality given a full-stack
	// opentracing integration (e.g., arbitrary application data from a mobile
	// app can make it, transparently, all the way into the depths of a storage
	// system), and with it some powerful costs: use this feature with care.
	//
	// IMPORTANT NOTE #1: SetBaggageItem() will only propagate trace
	// baggage items to *future* children of the Span.
	//
	// IMPORTANT NOTE #2: Use this thoughtfully and with care. Every key and
	// value is copied into every local *and remote* child of this Span, and
	// that can add up to a lot of network and cpu overhead.
	//
	// IMPORTANT NOTE #3: Baggage item keys have a restricted format:
	// implementations may wish to use them as HTTP header keys (or key
	// suffixes), and of course HTTP headers are case insensitive.
	//
	// As such, `restrictedKey` MUST match the regular expression
	// `(?i:[a-z0-9][-a-z0-9]*)` and is case-insensitive. That is, it must
	// start with a letter or number, and the remaining characters must be
	// letters, numbers, or hyphens. See CanonicalizeBaggageKey(). If
	// `restrictedKey` does not meet these criteria, SetBaggageItem()
	// results in undefined behavior.
	//
	// Returns a reference to this Span for chaining, etc.
	SetBaggageItem(restrictedKey, value string) Span

	// Gets the value for a baggage item given its key. Returns the empty string
	// if the value isn't found in this Span.
	//
	// See the `SetBaggageItem` notes about `restrictedKey`.
	BaggageItem(restrictedKey string) string

	// Provides access to the Tracer that created this Span.
	Tracer() Tracer
}

Span represents an active, un-finished span in the OpenTracing system.

Spans are created by the Tracer interface.

func SpanFromContext

func SpanFromContext(ctx context.Context) Span

SpanFromContext returns the `Span` previously associated with `ctx`, or `nil` if no such `Span` could be found.

func StartChildSpan

func StartChildSpan(parent Span, operationName string) Span

StartChildSpan is a simple helper to start a child span given only its parent (per StartSpanOptions.Parent) and an operation name per Span.SetOperationName.

func StartSpan

func StartSpan(operationName string) Span

StartSpan defers to `Tracer.StartSpan`. See `GlobalTracer()`.

func StartSpanFromContext

func StartSpanFromContext(ctx context.Context, operationName string) (Span, context.Context)

StartSpanFromContext starts and returns a Span with `operationName`, using any Span found within `ctx` as a parent. If no such parent could be found, StartSpanFromContext creates a root (parentless) Span.

The second return value is a context.Context object built around the returned Span.

Example usage:

SomeFunction(ctx context.Context, ...) {
    sp, ctx := opentracing.StartSpanFromContext(ctx, "SomeFunction")
    defer sp.Finish()
    ...
}

type StartSpanOptions

type StartSpanOptions struct {
	// OperationName may be empty (and set later via Span.SetOperationName)
	OperationName string

	// Parent may specify Span instance that caused the new (child) Span to be
	// created.
	//
	// If nil, start a "root" span (i.e., start a new trace).
	Parent Span

	// StartTime overrides the Span's start time, or implicitly becomes
	// time.Now() if StartTime.IsZero().
	StartTime time.Time

	// Tags may have zero or more entries; the restrictions on map values are
	// identical to those for Span.SetTag(). May be nil.
	//
	// If specified, the caller hands off ownership of Tags at
	// StartSpanWithOptions() invocation time.
	Tags map[string]interface{}
}

StartSpanOptions allows Tracer.StartSpanWithOptions callers to override the start timestamp, specify a parent Span, and make sure that Tags are available at Span initialization time.

type Tags

type Tags map[string]interface{}

Tags are a generic map from an arbitrary string key to an opaque value type. The underlying tracing system is responsible for interpreting and serializing the values.

func (Tags) Merge

func (t Tags) Merge(other Tags) Tags

Merge incorporates the keys and values from `other` into this `Tags` instance, then returns same.

type TextMapReader

type TextMapReader interface {
	// ForeachKey returns TextMap contents via repeated calls to the `handler`
	// function. If any call to `handler` returns a non-nil error, ForeachKey
	// terminates and returns that error.
	//
	// NOTE: A single `key` may appear in multiple calls to `handler` for a
	// single `ForeachKey` invocation.
	//
	// NOTE: The ForeachKey handler *may* be invoked for keys not set by any
	// TextMap writer (e.g., totally unrelated HTTP headers). As such, the
	// TextMap writer and reader should agree on a prefix or other convention
	// to distinguish their key:value pairs.
	//
	// The "foreach" callback pattern reduces unnecessary copying in some cases
	// and also allows implementations to hold locks while the map is read.
	ForeachKey(handler func(key, val string) error) error
}

TextMapReader is the Join() carrier for the TextMap builtin format. With it, the caller can decode a propagated Span as entries in a multimap of unicode strings.

type TextMapWriter

type TextMapWriter interface {
	// Set a key:value pair to the carrier. Multiple calls to Set() for the
	// same key leads to undefined behavior.
	//
	// NOTE: Since HTTP headers are a particularly important use case for the
	// TextMap carrier, `key` parameters identify their respective values in a
	// case-insensitive manner.
	//
	// NOTE: The backing store for the TextMapWriter may contain unrelated data
	// (e.g., arbitrary HTTP headers). As such, the TextMap writer and reader
	// should agree on a prefix or other convention to distinguish their
	// key:value pairs.
	Set(key, val string)
}

TextMapWriter is the Inject() carrier for the TextMap builtin format. With it, the caller can encode a Span for propagation as entries in a multimap of unicode strings.

type Tracer

type Tracer interface {
	// Create, start, and return a new Span with the given `operationName`, all
	// without specifying a parent Span that can be used to incorporate the
	// newly-returned Span into an existing trace. (I.e., the returned Span is
	// the "root" of its trace).
	//
	// Examples:
	//
	//     var tracer opentracing.Tracer = ...
	//
	//     sp := tracer.StartSpan("GetFeed")
	//
	//     sp := tracer.StartSpanWithOptions(opentracing.SpanOptions{
	//         OperationName: "LoggedHTTPRequest",
	//         Tags: opentracing.Tags{"user_agent", loggedReq.UserAgent},
	//         StartTime: loggedReq.Timestamp,
	//     })
	//
	StartSpan(operationName string) Span
	StartSpanWithOptions(opts StartSpanOptions) Span

	// Inject() takes the `sp` Span instance and represents it for propagation
	// within `carrier`. The actual type of `carrier` depends on the value of
	// `format`.
	//
	// OpenTracing defines a common set of `format` values (see BuiltinFormat),
	// and each has an expected carrier type.
	//
	// Other packages may declare their own `format` values, much like the keys
	// used by the `net.Context` package (see
	// https://godoc.org/golang.org/x/net/context#WithValue).
	//
	// Example usage (sans error handling):
	//
	//     carrier := opentracing.HTTPHeaderTextMapCarrier(httpReq.Header)
	//     tracer.Inject(
	//         span,
	//         opentracing.TextMap,
	//         carrier)
	//
	// NOTE: All opentracing.Tracer implementations MUST support all
	// BuiltinFormats.
	//
	// Implementations may return opentracing.ErrUnsupportedFormat if `format`
	// is or not supported by (or not known by) the implementation.
	//
	// Implementations may return opentracing.ErrInvalidCarrier or any other
	// implementation-specific error if the format is supported but injection
	// fails anyway.
	//
	// See Tracer.Join().
	Inject(sp Span, format interface{}, carrier interface{}) error

	// Join() returns a Span instance with operation name `operationName` given
	// `format` and `carrier`.
	//
	// Join() is responsible for extracting and joining to the trace of a Span
	// instance embedded in a format-specific "carrier" object. Typically the
	// joining will take place on the server side of an RPC boundary, but
	// message queues and other IPC mechanisms are also reasonable places to
	// use Join().
	//
	// OpenTracing defines a common set of `format` values (see BuiltinFormat),
	// and each has an expected carrier type.
	//
	// Other packages may declare their own `format` values, much like the keys
	// used by the `net.Context` package (see
	// https://godoc.org/golang.org/x/net/context#WithValue).
	//
	// Example usage (sans error handling):
	//
	//     carrier := opentracing.HTTPHeaderTextMapCarrier(httpReq.Header)
	//     span, err := tracer.Join(
	//         operationName,
	//         opentracing.TextMap,
	//         carrier)
	//
	// NOTE: All opentracing.Tracer implementations MUST support all
	// BuiltinFormats.
	//
	// Return values:
	//  - A successful join will return a started Span instance and a nil error
	//  - If there was simply no trace to join with in `carrier`, Join()
	//    returns (nil, opentracing.ErrTraceNotFound)
	//  - If `format` is unsupported or unrecognized, Join() returns (nil,
	//    opentracing.ErrUnsupportedFormat)
	//  - If there are more fundamental problems with the `carrier` object,
	//    Join() may return opentracing.ErrInvalidCarrier,
	//    opentracing.ErrTraceCorrupted, or implementation-specific errors.
	//
	// See Tracer.Inject().
	Join(operationName string, format interface{}, carrier interface{}) (Span, error)
}

Tracer is a simple, thin interface for Span creation.

A straightforward implementation is available via the `opentracing/basictracer-go` package's `standardtracer.New()'.

func GlobalTracer

func GlobalTracer() Tracer

GlobalTracer returns the global singleton `Tracer` implementation. Before `InitGlobalTracer()` is called, the `GlobalTracer()` is a noop implementation that drops all data handed to it.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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