|
@@ -0,0 +1,305 @@
|
|
|
+package opentracing
|
|
|
+
|
|
|
+import "time"
|
|
|
+
|
|
|
+// Tracer is a simple, thin interface for Span creation and SpanContext
|
|
|
+// propagation.
|
|
|
+type Tracer interface {
|
|
|
+
|
|
|
+ // Create, start, and return a new Span with the given `operationName` and
|
|
|
+ // incorporate the given StartSpanOption `opts`. (Note that `opts` borrows
|
|
|
+ // from the "functional options" pattern, per
|
|
|
+ // http://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis)
|
|
|
+ //
|
|
|
+ // A Span with no SpanReference options (e.g., opentracing.ChildOf() or
|
|
|
+ // opentracing.FollowsFrom()) becomes the root of its own trace.
|
|
|
+ //
|
|
|
+ // Examples:
|
|
|
+ //
|
|
|
+ // var tracer opentracing.Tracer = ...
|
|
|
+ //
|
|
|
+ // // The root-span case:
|
|
|
+ // sp := tracer.StartSpan("GetFeed")
|
|
|
+ //
|
|
|
+ // // The vanilla child span case:
|
|
|
+ // sp := tracer.StartSpan(
|
|
|
+ // "GetFeed",
|
|
|
+ // opentracing.ChildOf(parentSpan.Context()))
|
|
|
+ //
|
|
|
+ // // All the bells and whistles:
|
|
|
+ // sp := tracer.StartSpan(
|
|
|
+ // "GetFeed",
|
|
|
+ // opentracing.ChildOf(parentSpan.Context()),
|
|
|
+ // opentracing.Tag{"user_agent", loggedReq.UserAgent},
|
|
|
+ // opentracing.StartTime(loggedReq.Timestamp),
|
|
|
+ // )
|
|
|
+ //
|
|
|
+ StartSpan(operationName string, opts ...StartSpanOption) Span
|
|
|
+
|
|
|
+ // Inject() takes the `sm` SpanContext instance and injects 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 `context.Context` (see
|
|
|
+ // https://godoc.org/golang.org/x/net/context#WithValue).
|
|
|
+ //
|
|
|
+ // Example usage (sans error handling):
|
|
|
+ //
|
|
|
+ // carrier := opentracing.HTTPHeadersCarrier(httpReq.Header)
|
|
|
+ // err := tracer.Inject(
|
|
|
+ // span.Context(),
|
|
|
+ // opentracing.HTTPHeaders,
|
|
|
+ // carrier)
|
|
|
+ //
|
|
|
+ // NOTE: All opentracing.Tracer implementations MUST support all
|
|
|
+ // BuiltinFormats.
|
|
|
+ //
|
|
|
+ // Implementations may return opentracing.ErrUnsupportedFormat if `format`
|
|
|
+ // is 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.Extract().
|
|
|
+ Inject(sm SpanContext, format interface{}, carrier interface{}) error
|
|
|
+
|
|
|
+ // Extract() returns a SpanContext instance given `format` and `carrier`.
|
|
|
+ //
|
|
|
+ // 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 `context.Context` (see
|
|
|
+ // https://godoc.org/golang.org/x/net/context#WithValue).
|
|
|
+ //
|
|
|
+ // Example usage (with StartSpan):
|
|
|
+ //
|
|
|
+ //
|
|
|
+ // carrier := opentracing.HTTPHeadersCarrier(httpReq.Header)
|
|
|
+ // clientContext, err := tracer.Extract(opentracing.HTTPHeaders, carrier)
|
|
|
+ //
|
|
|
+ // // ... assuming the ultimate goal here is to resume the trace with a
|
|
|
+ // // server-side Span:
|
|
|
+ // var serverSpan opentracing.Span
|
|
|
+ // if err == nil {
|
|
|
+ // span = tracer.StartSpan(
|
|
|
+ // rpcMethodName, ext.RPCServerOption(clientContext))
|
|
|
+ // } else {
|
|
|
+ // span = tracer.StartSpan(rpcMethodName)
|
|
|
+ // }
|
|
|
+ //
|
|
|
+ //
|
|
|
+ // NOTE: All opentracing.Tracer implementations MUST support all
|
|
|
+ // BuiltinFormats.
|
|
|
+ //
|
|
|
+ // Return values:
|
|
|
+ // - A successful Extract returns a SpanContext instance and a nil error
|
|
|
+ // - If there was simply no SpanContext to extract in `carrier`, Extract()
|
|
|
+ // returns (nil, opentracing.ErrSpanContextNotFound)
|
|
|
+ // - If `format` is unsupported or unrecognized, Extract() returns (nil,
|
|
|
+ // opentracing.ErrUnsupportedFormat)
|
|
|
+ // - If there are more fundamental problems with the `carrier` object,
|
|
|
+ // Extract() may return opentracing.ErrInvalidCarrier,
|
|
|
+ // opentracing.ErrSpanContextCorrupted, or implementation-specific
|
|
|
+ // errors.
|
|
|
+ //
|
|
|
+ // See Tracer.Inject().
|
|
|
+ Extract(format interface{}, carrier interface{}) (SpanContext, error)
|
|
|
+}
|
|
|
+
|
|
|
+// StartSpanOptions allows Tracer.StartSpan() callers and implementors a
|
|
|
+// mechanism to override the start timestamp, specify Span References, and make
|
|
|
+// a single Tag or multiple Tags available at Span start time.
|
|
|
+//
|
|
|
+// StartSpan() callers should look at the StartSpanOption interface and
|
|
|
+// implementations available in this package.
|
|
|
+//
|
|
|
+// Tracer implementations can convert a slice of `StartSpanOption` instances
|
|
|
+// into a `StartSpanOptions` struct like so:
|
|
|
+//
|
|
|
+// func StartSpan(opName string, opts ...opentracing.StartSpanOption) {
|
|
|
+// sso := opentracing.StartSpanOptions{}
|
|
|
+// for _, o := range opts {
|
|
|
+// o.Apply(&sso)
|
|
|
+// }
|
|
|
+// ...
|
|
|
+// }
|
|
|
+//
|
|
|
+type StartSpanOptions struct {
|
|
|
+ // Zero or more causal references to other Spans (via their SpanContext).
|
|
|
+ // If empty, start a "root" Span (i.e., start a new trace).
|
|
|
+ References []SpanReference
|
|
|
+
|
|
|
+ // 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
|
|
|
+ // StartSpan() invocation time.
|
|
|
+ Tags map[string]interface{}
|
|
|
+}
|
|
|
+
|
|
|
+// StartSpanOption instances (zero or more) may be passed to Tracer.StartSpan.
|
|
|
+//
|
|
|
+// StartSpanOption borrows from the "functional options" pattern, per
|
|
|
+// http://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis
|
|
|
+type StartSpanOption interface {
|
|
|
+ Apply(*StartSpanOptions)
|
|
|
+}
|
|
|
+
|
|
|
+// SpanReferenceType is an enum type describing different categories of
|
|
|
+// relationships between two Spans. If Span-2 refers to Span-1, the
|
|
|
+// SpanReferenceType describes Span-1 from Span-2's perspective. For example,
|
|
|
+// ChildOfRef means that Span-1 created Span-2.
|
|
|
+//
|
|
|
+// NOTE: Span-1 and Span-2 do *not* necessarily depend on each other for
|
|
|
+// completion; e.g., Span-2 may be part of a background job enqueued by Span-1,
|
|
|
+// or Span-2 may be sitting in a distributed queue behind Span-1.
|
|
|
+type SpanReferenceType int
|
|
|
+
|
|
|
+const (
|
|
|
+ // ChildOfRef refers to a parent Span that caused *and* somehow depends
|
|
|
+ // upon the new child Span. Often (but not always), the parent Span cannot
|
|
|
+ // finish until the child Span does.
|
|
|
+ //
|
|
|
+ // An timing diagram for a ChildOfRef that's blocked on the new Span:
|
|
|
+ //
|
|
|
+ // [-Parent Span---------]
|
|
|
+ // [-Child Span----]
|
|
|
+ //
|
|
|
+ // See http://opentracing.io/spec/
|
|
|
+ //
|
|
|
+ // See opentracing.ChildOf()
|
|
|
+ ChildOfRef SpanReferenceType = iota
|
|
|
+
|
|
|
+ // FollowsFromRef refers to a parent Span that does not depend in any way
|
|
|
+ // on the result of the new child Span. For instance, one might use
|
|
|
+ // FollowsFromRefs to describe pipeline stages separated by queues,
|
|
|
+ // or a fire-and-forget cache insert at the tail end of a web request.
|
|
|
+ //
|
|
|
+ // A FollowsFromRef Span is part of the same logical trace as the new Span:
|
|
|
+ // i.e., the new Span is somehow caused by the work of its FollowsFromRef.
|
|
|
+ //
|
|
|
+ // All of the following could be valid timing diagrams for children that
|
|
|
+ // "FollowFrom" a parent.
|
|
|
+ //
|
|
|
+ // [-Parent Span-] [-Child Span-]
|
|
|
+ //
|
|
|
+ //
|
|
|
+ // [-Parent Span--]
|
|
|
+ // [-Child Span-]
|
|
|
+ //
|
|
|
+ //
|
|
|
+ // [-Parent Span-]
|
|
|
+ // [-Child Span-]
|
|
|
+ //
|
|
|
+ // See http://opentracing.io/spec/
|
|
|
+ //
|
|
|
+ // See opentracing.FollowsFrom()
|
|
|
+ FollowsFromRef
|
|
|
+)
|
|
|
+
|
|
|
+// SpanReference is a StartSpanOption that pairs a SpanReferenceType and a
|
|
|
+// referenced SpanContext. See the SpanReferenceType documentation for
|
|
|
+// supported relationships. If SpanReference is created with
|
|
|
+// ReferencedContext==nil, it has no effect. Thus it allows for a more concise
|
|
|
+// syntax for starting spans:
|
|
|
+//
|
|
|
+// sc, _ := tracer.Extract(someFormat, someCarrier)
|
|
|
+// span := tracer.StartSpan("operation", opentracing.ChildOf(sc))
|
|
|
+//
|
|
|
+// The `ChildOf(sc)` option above will not panic if sc == nil, it will just
|
|
|
+// not add the parent span reference to the options.
|
|
|
+type SpanReference struct {
|
|
|
+ Type SpanReferenceType
|
|
|
+ ReferencedContext SpanContext
|
|
|
+}
|
|
|
+
|
|
|
+// Apply satisfies the StartSpanOption interface.
|
|
|
+func (r SpanReference) Apply(o *StartSpanOptions) {
|
|
|
+ if r.ReferencedContext != nil {
|
|
|
+ o.References = append(o.References, r)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// ChildOf returns a StartSpanOption pointing to a dependent parent span.
|
|
|
+// If sc == nil, the option has no effect.
|
|
|
+//
|
|
|
+// See ChildOfRef, SpanReference
|
|
|
+func ChildOf(sc SpanContext) SpanReference {
|
|
|
+ return SpanReference{
|
|
|
+ Type: ChildOfRef,
|
|
|
+ ReferencedContext: sc,
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// FollowsFrom returns a StartSpanOption pointing to a parent Span that caused
|
|
|
+// the child Span but does not directly depend on its result in any way.
|
|
|
+// If sc == nil, the option has no effect.
|
|
|
+//
|
|
|
+// See FollowsFromRef, SpanReference
|
|
|
+func FollowsFrom(sc SpanContext) SpanReference {
|
|
|
+ return SpanReference{
|
|
|
+ Type: FollowsFromRef,
|
|
|
+ ReferencedContext: sc,
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// StartTime is a StartSpanOption that sets an explicit start timestamp for the
|
|
|
+// new Span.
|
|
|
+type StartTime time.Time
|
|
|
+
|
|
|
+// Apply satisfies the StartSpanOption interface.
|
|
|
+func (t StartTime) Apply(o *StartSpanOptions) {
|
|
|
+ o.StartTime = time.Time(t)
|
|
|
+}
|
|
|
+
|
|
|
+// 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.
|
|
|
+type Tags map[string]interface{}
|
|
|
+
|
|
|
+// Apply satisfies the StartSpanOption interface.
|
|
|
+func (t Tags) Apply(o *StartSpanOptions) {
|
|
|
+ if o.Tags == nil {
|
|
|
+ o.Tags = make(map[string]interface{})
|
|
|
+ }
|
|
|
+ for k, v := range t {
|
|
|
+ o.Tags[k] = v
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Tag may be passed as a StartSpanOption to add a tag to new spans,
|
|
|
+// or its Set method may be used to apply the tag to an existing Span,
|
|
|
+// for example:
|
|
|
+//
|
|
|
+// tracer.StartSpan("opName", Tag{"Key", value})
|
|
|
+//
|
|
|
+// or
|
|
|
+//
|
|
|
+// Tag{"key", value}.Set(span)
|
|
|
+type Tag struct {
|
|
|
+ Key string
|
|
|
+ Value interface{}
|
|
|
+}
|
|
|
+
|
|
|
+// Apply satisfies the StartSpanOption interface.
|
|
|
+func (t Tag) Apply(o *StartSpanOptions) {
|
|
|
+ if o.Tags == nil {
|
|
|
+ o.Tags = make(map[string]interface{})
|
|
|
+ }
|
|
|
+ o.Tags[t.Key] = t.Value
|
|
|
+}
|
|
|
+
|
|
|
+// Set applies the tag to an existing Span.
|
|
|
+func (t Tag) Set(s Span) {
|
|
|
+ s.SetTag(t.Key, t.Value)
|
|
|
+}
|