1package opentracing
2
3import "time"
4
5// Tracer is a simple, thin interface for Span creation and SpanContext
6// propagation.
7type Tracer interface {
8
9	// Create, start, and return a new Span with the given `operationName` and
10	// incorporate the given StartSpanOption `opts`. (Note that `opts` borrows
11	// from the "functional options" pattern, per
12	// http://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis)
13	//
14	// A Span with no SpanReference options (e.g., opentracing.ChildOf() or
15	// opentracing.FollowsFrom()) becomes the root of its own trace.
16	//
17	// Examples:
18	//
19	//     var tracer opentracing.Tracer = ...
20	//
21	//     // The root-span case:
22	//     sp := tracer.StartSpan("GetFeed")
23	//
24	//     // The vanilla child span case:
25	//     sp := tracer.StartSpan(
26	//         "GetFeed",
27	//         opentracing.ChildOf(parentSpan.Context()))
28	//
29	//     // All the bells and whistles:
30	//     sp := tracer.StartSpan(
31	//         "GetFeed",
32	//         opentracing.ChildOf(parentSpan.Context()),
33	//         opentracing.Tag("user_agent", loggedReq.UserAgent),
34	//         opentracing.StartTime(loggedReq.Timestamp),
35	//     )
36	//
37	StartSpan(operationName string, opts ...StartSpanOption) Span
38
39	// Inject() takes the `sm` SpanContext instance and injects it for
40	// propagation within `carrier`. The actual type of `carrier` depends on
41	// the value of `format`.
42	//
43	// OpenTracing defines a common set of `format` values (see BuiltinFormat),
44	// and each has an expected carrier type.
45	//
46	// Other packages may declare their own `format` values, much like the keys
47	// used by `context.Context` (see
48	// https://godoc.org/golang.org/x/net/context#WithValue).
49	//
50	// Example usage (sans error handling):
51	//
52	//     carrier := opentracing.HTTPHeadersCarrier(httpReq.Header)
53	//     err := tracer.Inject(
54	//         span.Context(),
55	//         opentracing.HTTPHeaders,
56	//         carrier)
57	//
58	// NOTE: All opentracing.Tracer implementations MUST support all
59	// BuiltinFormats.
60	//
61	// Implementations may return opentracing.ErrUnsupportedFormat if `format`
62	// is not supported by (or not known by) the implementation.
63	//
64	// Implementations may return opentracing.ErrInvalidCarrier or any other
65	// implementation-specific error if the format is supported but injection
66	// fails anyway.
67	//
68	// See Tracer.Extract().
69	Inject(sm SpanContext, format interface{}, carrier interface{}) error
70
71	// Extract() returns a SpanContext instance given `format` and `carrier`.
72	//
73	// OpenTracing defines a common set of `format` values (see BuiltinFormat),
74	// and each has an expected carrier type.
75	//
76	// Other packages may declare their own `format` values, much like the keys
77	// used by `context.Context` (see
78	// https://godoc.org/golang.org/x/net/context#WithValue).
79	//
80	// Example usage (with StartSpan):
81	//
82	//
83	//     carrier := opentracing.HTTPHeadersCarrier(httpReq.Header)
84	//     clientContext, err := tracer.Extract(opentracing.HTTPHeaders, carrier)
85	//
86	//     // ... assuming the ultimate goal here is to resume the trace with a
87	//     // server-side Span:
88	//     var serverSpan opentracing.Span
89	//     if err == nil {
90	//         span = tracer.StartSpan(
91	//             rpcMethodName, ext.RPCServerOption(clientContext))
92	//     } else {
93	//         span = tracer.StartSpan(rpcMethodName)
94	//     }
95	//
96	//
97	// NOTE: All opentracing.Tracer implementations MUST support all
98	// BuiltinFormats.
99	//
100	// Return values:
101	//  - A successful Extract returns a SpanContext instance and a nil error
102	//  - If there was simply no SpanContext to extract in `carrier`, Extract()
103	//    returns (nil, opentracing.ErrSpanContextNotFound)
104	//  - If `format` is unsupported or unrecognized, Extract() returns (nil,
105	//    opentracing.ErrUnsupportedFormat)
106	//  - If there are more fundamental problems with the `carrier` object,
107	//    Extract() may return opentracing.ErrInvalidCarrier,
108	//    opentracing.ErrSpanContextCorrupted, or implementation-specific
109	//    errors.
110	//
111	// See Tracer.Inject().
112	Extract(format interface{}, carrier interface{}) (SpanContext, error)
113}
114
115// StartSpanOptions allows Tracer.StartSpan() callers and implementors a
116// mechanism to override the start timestamp, specify Span References, and make
117// a single Tag or multiple Tags available at Span start time.
118//
119// StartSpan() callers should look at the StartSpanOption interface and
120// implementations available in this package.
121//
122// Tracer implementations can convert a slice of `StartSpanOption` instances
123// into a `StartSpanOptions` struct like so:
124//
125//     func StartSpan(opName string, opts ...opentracing.StartSpanOption) {
126//         sso := opentracing.StartSpanOptions{}
127//         for _, o := range opts {
128//             o.Apply(&sso)
129//         }
130//         ...
131//     }
132//
133type StartSpanOptions struct {
134	// Zero or more causal references to other Spans (via their SpanContext).
135	// If empty, start a "root" Span (i.e., start a new trace).
136	References []SpanReference
137
138	// StartTime overrides the Span's start time, or implicitly becomes
139	// time.Now() if StartTime.IsZero().
140	StartTime time.Time
141
142	// Tags may have zero or more entries; the restrictions on map values are
143	// identical to those for Span.SetTag(). May be nil.
144	//
145	// If specified, the caller hands off ownership of Tags at
146	// StartSpan() invocation time.
147	Tags map[string]interface{}
148}
149
150// StartSpanOption instances (zero or more) may be passed to Tracer.StartSpan.
151//
152// StartSpanOption borrows from the "functional options" pattern, per
153// http://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis
154type StartSpanOption interface {
155	Apply(*StartSpanOptions)
156}
157
158// SpanReferenceType is an enum type describing different categories of
159// relationships between two Spans. If Span-2 refers to Span-1, the
160// SpanReferenceType describes Span-1 from Span-2's perspective. For example,
161// ChildOfRef means that Span-1 created Span-2.
162//
163// NOTE: Span-1 and Span-2 do *not* necessarily depend on each other for
164// completion; e.g., Span-2 may be part of a background job enqueued by Span-1,
165// or Span-2 may be sitting in a distributed queue behind Span-1.
166type SpanReferenceType int
167
168const (
169	// ChildOfRef refers to a parent Span that caused *and* somehow depends
170	// upon the new child Span. Often (but not always), the parent Span cannot
171	// finish until the child Span does.
172	//
173	// An timing diagram for a ChildOfRef that's blocked on the new Span:
174	//
175	//     [-Parent Span---------]
176	//          [-Child Span----]
177	//
178	// See http://opentracing.io/spec/
179	//
180	// See opentracing.ChildOf()
181	ChildOfRef SpanReferenceType = iota
182
183	// FollowsFromRef refers to a parent Span that does not depend in any way
184	// on the result of the new child Span. For instance, one might use
185	// FollowsFromRefs to describe pipeline stages separated by queues,
186	// or a fire-and-forget cache insert at the tail end of a web request.
187	//
188	// A FollowsFromRef Span is part of the same logical trace as the new Span:
189	// i.e., the new Span is somehow caused by the work of its FollowsFromRef.
190	//
191	// All of the following could be valid timing diagrams for children that
192	// "FollowFrom" a parent.
193	//
194	//     [-Parent Span-]  [-Child Span-]
195	//
196	//
197	//     [-Parent Span--]
198	//      [-Child Span-]
199	//
200	//
201	//     [-Parent Span-]
202	//                 [-Child Span-]
203	//
204	// See http://opentracing.io/spec/
205	//
206	// See opentracing.FollowsFrom()
207	FollowsFromRef
208)
209
210// SpanReference is a StartSpanOption that pairs a SpanReferenceType and a
211// referenced SpanContext. See the SpanReferenceType documentation for
212// supported relationships.  If SpanReference is created with
213// ReferencedContext==nil, it has no effect. Thus it allows for a more concise
214// syntax for starting spans:
215//
216//     sc, _ := tracer.Extract(someFormat, someCarrier)
217//     span := tracer.StartSpan("operation", opentracing.ChildOf(sc))
218//
219// The `ChildOf(sc)` option above will not panic if sc == nil, it will just
220// not add the parent span reference to the options.
221type SpanReference struct {
222	Type              SpanReferenceType
223	ReferencedContext SpanContext
224}
225
226// Apply satisfies the StartSpanOption interface.
227func (r SpanReference) Apply(o *StartSpanOptions) {
228	if r.ReferencedContext != nil {
229		o.References = append(o.References, r)
230	}
231}
232
233// ChildOf returns a StartSpanOption pointing to a dependent parent span.
234// If sc == nil, the option has no effect.
235//
236// See ChildOfRef, SpanReference
237func ChildOf(sc SpanContext) SpanReference {
238	return SpanReference{
239		Type:              ChildOfRef,
240		ReferencedContext: sc,
241	}
242}
243
244// FollowsFrom returns a StartSpanOption pointing to a parent Span that caused
245// the child Span but does not directly depend on its result in any way.
246// If sc == nil, the option has no effect.
247//
248// See FollowsFromRef, SpanReference
249func FollowsFrom(sc SpanContext) SpanReference {
250	return SpanReference{
251		Type:              FollowsFromRef,
252		ReferencedContext: sc,
253	}
254}
255
256// StartTime is a StartSpanOption that sets an explicit start timestamp for the
257// new Span.
258type StartTime time.Time
259
260// Apply satisfies the StartSpanOption interface.
261func (t StartTime) Apply(o *StartSpanOptions) {
262	o.StartTime = time.Time(t)
263}
264
265// Tags are a generic map from an arbitrary string key to an opaque value type.
266// The underlying tracing system is responsible for interpreting and
267// serializing the values.
268type Tags map[string]interface{}
269
270// Apply satisfies the StartSpanOption interface.
271func (t Tags) Apply(o *StartSpanOptions) {
272	if o.Tags == nil {
273		o.Tags = make(map[string]interface{})
274	}
275	for k, v := range t {
276		o.Tags[k] = v
277	}
278}
279
280// Tag may be passed as a StartSpanOption to add a tag to new spans,
281// or its Set method may be used to apply the tag to an existing Span,
282// for example:
283//
284// tracer.StartSpan("opName", Tag{"Key", value})
285//
286//   or
287//
288// Tag{"key", value}.Set(span)
289type Tag struct {
290	Key   string
291	Value interface{}
292}
293
294// Apply satisfies the StartSpanOption interface.
295func (t Tag) Apply(o *StartSpanOptions) {
296	if o.Tags == nil {
297		o.Tags = make(map[string]interface{})
298	}
299	o.Tags[t.Key] = t.Value
300}
301
302// Set applies the tag to an existing Span.
303func (t Tag) Set(s Span) {
304	s.SetTag(t.Key, t.Value)
305}
306