tracing

package module
v0.0.0-...-2dabd12 Latest Latest
Warning

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

Go to latest
Published: Oct 20, 2016 License: MIT Imports: 3 Imported by: 0

README

NOTE: this project has been deprecated and superseded by https://github.com/opentracing/opentracing-go.

Synopsis

Defines an interface for Uber libraries to use when reporting Dapper/Zipkin-style tracing information to distributed tracing systems. By programming to this API the libraries are abstracted away from the internal trace representation used in the tracing system, as well as other concepts like sampling.

Sample Usage

Assume you implement an http server that calls some other service while executing the request.

// Initialize global Tracer variable
var tracer = tracing.NewNoopTracer()

// Initialize Endpoint descriptor of your service (use real IP address)
var endpoint = &tracing.Endpoint{ServiceName:"my-service", IPv4: 127<<24|1, Port: 1000}

// In the http handler function
func (h *myHandler) handler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
    // instrumentation code
    spanName := urlToSpanName(r)
    client := makeEndpoint(r.RemoteAddr, r.Header.Get("Requestor"))
    header := r.Header.Get("X-Tracing")
    options := &tracing.BeginOptions{Peer: client}
    // call util method to create new trace or join the existing trace
    span, err := tracing.GetSpanFromHeader(header, tracer, spanName, endpoint, options)
    if err != nil {
        // header could not be parsed, but we may still decide to create a new trace
        span = tracer.BeginTrace(spanName, endpoint, options)
    }

    // You may annotate your span with events (timestamped) or attributes.  UI can find this trace 
    // via one of these case-insensitive queries: "api-version=1.2", "api-version", "i-got-hit".
    span.AddEvent("I-got-hit", nil)
    span.AddAttribute("api-version", "1.2")
    
    // propagation - store span in the context
    newCtx = tracing.ContextWithSpan(span)

    // continue with the regular handler
    processRequest(newCtx, w, r)

    // once finished, close the span.
    span.End(nil)
}

Suppose somewhere in processRequest() you need to make a call to another service

func processRequest(ctx context.Context, ...) {
    // retrieve the span from the context
    span, err := tracing.GetSpanFromContext(ctx)
    
    // start a new RPC span
    options := &tracing.BeginOptions{Peer: ...}
    childSpan := span.BeginChildSpan("another-service", options)
    
    // make the call to the remote service, passing trace ID in the header
    clientReq := ...
    clientReq.Header.Put("X-Tracing", tracer.GetStringPickler().ToString(childSpan.SpanID()))
    httpClient.call(clientReq, ...)
    
    // upon completion, close the span
    childSpan.End(nil)
}

Zipkin Trace ID

When RPC calls happen over a protocol that supports arbitrary string headers, the propagation of trace ID between services can be done using StringPickler as shown in the previous section. However, some protocols like TChannel encode tracing information in a specific Zipkin-compatible format, that consists of four fields, three 64-bit integers representing trace ID, span ID, and parent span ID, and an 8-bit flags field. The specific tracing system may not be compatible with propagating tracing information via this format. If it is compatible, it can implement two additional interfaces, ZipkinCompatibleTracer and ZipkinSpanID. Then to create a span ID the instrumentation code can do:

var span Span
zipkinTracer, zipkinOK := tracer.(ZipkinCompatibleTracer)
if frame.tracing != nil && zipkinOK {
    spanID := zipkinTracer.CreateSpanID(frame.tracing.traceID, frame.tracing.ID,
                                        frame.tracing.parentID, frame.tracing.flags)
    span := tracer.JoinTrace(... spanID ...)
} else {
    span = tracer.BeginTrace(...)
}

And when making an outgoing RPC call, it can serialize span ID:

if spanID, ok := childSpan.SpanID().(ZipkinSpanID); ok {
    outFrame.traceID = spanID.TraceID()
    outFrame.ID = spanID.ID()
    outFrame.parentID = spanID.ParentID()
}
...

License

opentracing-go is available under the MIT license. See the LICENSE file for more info.

Tests

gocov test -v | gocov report

Documentation

Index

Constants

View Source
const (
	CurrentSpanContextKey = "tracing.current_span"
)

Variables

View Source
var (
	NoCurrentSpanError  = errors.New("No tracing span found in the context")
	BadCurrentSpanError = errors.New("Tracing span found in the context is of the wrong type")
)

Functions

func ContextWithSpan

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

ContextWithSpan creates a child context that stores the current span

Types

type BeginOptions

type BeginOptions struct {
	TimeOption

	// LocalComponent, marks the span as a local, in-process unit of work, such as a function call to a library.
	// When this field is empty string, the span is considered to be an RPC span.
	LocalComponent string

	// Async marks the span as async, non-blocking, indicating that the parent continues doing other work.
	// This can be used in calculation of a critical path through the trace.
	// By default spans are considered sync/blocking.
	Async bool

	// Peer identifies the peer endpoint of an RPC request. When a server creates a span to handle incoming
	// request, the Peer is the client that made the request, e.g. from http.Request.RemoteAddr. When a process
	// creates a child span in order to make an RPC request to another server, i.e. it acts as a client,
	// the Peer is the server it is about to call.
	Peer *Endpoint
}

BeginOptions contains optional flags that can be passed to BeginChildSpan().

type EndOptions

type EndOptions struct {
	// Duration of the span calculated externally. If not specified, the tracer will calculate it as endTs - startTs.
	// Microseconds precision.
	Duration *time.Duration

	// Error indicates that span execution finished with an error. This can be used by the tracers to treat the span
	// as an anomaly, rather than ignoring it, e.g. if it finished quickly.
	Error error
}

EndOptions contains optional flags that can be passed to span.End() method.

type Endpoint

type Endpoint struct {
	// ServiceName is mandatory name of the service represented by this end point
	ServiceName string

	// IPv4 is 4-byte IP v.4 address of the server represented by this endpoint
	IPv4 int32

	// Port number the server represented by this endpoint is listening to
	Port uint16
}

Endpoint describes the service that participates in the trace.

type EventOptions

type EventOptions struct {
	TimeOption
}

EventOptions contains optional flags that can be passed to AppendEvent().

type Span

type Span interface {
	// SpanID returns the identifier of the span.
	SpanID() SpanID

	// BeginChildSpan denotes the beginning of a subordinate unit of work with a given name.
	BeginChildSpan(name string, options *BeginOptions) Span

	// End indicates that the work represented by this span has been completed or terminated.
	// If any attributes/events need to be added to the span, it should be done before calling End(),
	// otherwise they may be ignored.
	End(options *EndOptions)

	// AddAttribute attaches a key/value pair so the span. The same key may be repeated multiple times.
	// The storage allows spans and traces to be located both by key and by key=value combinations.
	// The set of supported value types is implementation specific. At minimum the following types
	// should be supported by the tracing system implementation:
	// * string
	// * int32
	// * int64
	// * float64
	// * bool
	// * []byte
	// * Endpoint
	// Other types may be optionally supported, e.g. JSON.
	AddAttribute(name string, value interface{})

	// AddEvent attaches a named marker with a timestamp to the span. The tracer will capture the timestamp.
	AddEvent(name string, options *EventOptions)
}

Span represents a unit of work executed on behalf of a trace. Examples of spans include a remote procedure call, or a in-process method call to a sub-component. A trace is required to have a single, top level "root" span, and zero or more children spans, which in turns can have their own children spans, thus forming a tree structure.

func GetSpanFromContext

func GetSpanFromContext(ctx context.Context) (Span, error)

GetSpanFromContext retrieves the current span from the context

func GetSpanFromHeader

func GetSpanFromHeader(header string, tracer Tracer, spanName string, endpoint *Endpoint, options *BeginOptions) (Span, error)

GetSpanFromHeader creates a top-level RPC server-side span. If the provided header value can be parsed as span ID, meaning the client is also instrumented for a compatible tracing system and it booked an RPC span, the server joins that span. Otherwise it creates a new root span. If the header contains a value that cannot be parsed as span ID, this method returns an error.

type SpanID

type SpanID interface {
	String() string
}

SpanID identifies the span. It contains information that must be passed between services as part of the instrumentation, e.g. in the form of HTTP headers or other protocol-specific data.

type StringPickler

type StringPickler interface {
	// ToString() serializes a span ID to a string
	ToString(spanID SpanID) string

	// FromString deserialized a span ID from a string, or returns an error if the string value is malformed
	FromString(value string) (SpanID, error)
}

StringPickler can marshall a SpanID to and from a string, e.g. for storing in HTTP header.

type TimeOption

type TimeOption struct {
	// Timestamp of the event being recorded, such as start time of the span recorded externally.
	// If nil, the tracer will capture the current time.  Microseconds precision.
	Timestamp *time.Time
}

TimeOption can be used to provide externally captured time and duration to span methods, e.g. when recording spans produced by a component that could not emit them directly to the tracer, such as a mobile application.

type Tracer

type Tracer interface {
	// BeginTrace starts a new trace and creates a new root span.
	// Used by any service that is instrumented for tracing, but did not receive trace ID from upstream.
	// The spanName should reflect the server's name of the end-point that received the request.
	// The domain of names must be limited, do not use UUIDs or entity IDs or timestamps as part of the name.
	// The service endpoint is mandatory.
	BeginTrace(spanName string, service *Endpoint, options *BeginOptions) Span

	// JoinTrace joins a trace started elsewhere and creates a span with the specified ID.
	// Used by services that receive trace ID from upstream.
	// The name should reflect the server's name of the end-point that received the request.
	// The domain of names must be limited, do not use UUIDs or entity IDs or timestamps as part of the name.
	JoinTrace(spanName string, service *Endpoint, spanID SpanID, options *BeginOptions) Span

	// GetStringPickler returns a pickler that can marshal SpanID to/from a string.
	// It can be used when transmitting SpanID across processes in a string protocol, e.g. in HTTP header.
	GetStringPickler() StringPickler

	// Close does a clean shutdown of the tracer, flushing any traces that may be buffered in memory.
	Close()
}

Tracer is the entry point API between instrumentation code and the tracing implementation.

func NewNoopTracer

func NewNoopTracer() Tracer

NewNoopTracer creates a tracer that does not perform any tracing

type ZipkinCompatibleTracer

type ZipkinCompatibleTracer interface {
	// CreateSpanID instantiates ZipkinSpanID from 4 values. It is not meant for creating brand new IDs
	// externally, but for constructing an ID based on the 4 values read from the incoming request.
	// For example, TChannel protocol explicitly records these 4 values in its frame, so one cannot use
	// a more abstract factory like StringPickler.
	CreateSpanID(traceID, spanID, parentID int64, flags byte) ZipkinSpanID
}

ZipkinCompatibleTracer is a tracer that represents trace ID as a 4-tuple similar to Zipkin.

type ZipkinSpanID

type ZipkinSpanID interface {
	SpanID

	// TraceID represents globally unique ID of the trace. Usually generated as a random number.
	TraceID() int64

	// ID represents span ID. It must be unique within a given trace, but does not have to be globally unique.
	ID() int64

	// ParentID refers to the ID of the parent span. Should be 0 if the current span is a root span.
	ParentID() int64

	// IsSampled returns whether this trace was chosen for permanent storage by the sampling mechanism of the tracer.
	IsSampled() bool
}

ZipkinSpanID is a subtype of SpanID that can be exposed by Zipkin-compatible tracers.

Jump to

Keyboard shortcuts

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