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